Convert gr-rule-editor to lit
Change-Id: If48d85c6ad627f8e9e452a889ffd9bd24bb26b49
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
index 2754963..c953be4 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
@@ -55,6 +55,7 @@
import {PolymerDomRepeatEvent} from '../../../types/types';
import {getAppContext} from '../../../services/app-context';
import {fireEvent} from '../../../utils/event-util';
+import {PolymerDomRepeatCustomEvent} from '../../../types/types';
const MAX_AUTOCOMPLETE_RESULTS = 20;
@@ -412,6 +413,19 @@
_onTapExclusiveToggle(e: Event) {
e.preventDefault();
}
+
+ _handleRuleChanged(e: PolymerDomRepeatCustomEvent) {
+ if (
+ this._rules === undefined ||
+ (e as CustomEvent).detail.value === undefined
+ )
+ return;
+ const index = Number(e.model.index);
+ if (isNaN(index)) {
+ return;
+ }
+ this.splice('_rules', index, (e as CustomEvent).detail.value);
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
index a8405df..eacd5ef 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
@@ -115,9 +115,10 @@
group-id="[[rule.id]]"
group-name="[[_computeGroupName(groups, rule.id)]]"
permission="[[permission.id]]"
- rule="{{rule}}"
+ rule="[[rule]]"
section="[[section]]"
on-added-rule-removed="_handleAddedRuleRemoved"
+ on-rule-changed="_handleRuleChanged"
></gr-rule-editor>
</template>
<div id="addRule">
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
index f811ee2..3b180df 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
@@ -15,16 +15,16 @@
* limitations under the License.
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
-import '../../../styles/gr-form-styles';
-import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-select/gr-select';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-rule-editor_html';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
import {AccessPermissionId} from '../../../utils/access-util';
-import {property, customElement, observe} from '@polymer/decorators';
import {fireEvent} from '../../../utils/event-util';
+import {formStyles} from '../../../styles/gr-form-styles';
+import {sharedStyles} from '../../../styles/shared-styles';
+import {LitElement, PropertyValues, html, css} from 'lit';
+import {customElement, property, state} from 'lit/decorators';
+import {BindValueChangeEvent} from '../../../types/events';
/**
* Fired when the rule has been modified or removed.
@@ -100,18 +100,14 @@
}
@customElement('gr-rule-editor')
-export class GrRuleEditor extends PolymerElement {
- static get template() {
- return htmlTemplate;
- }
-
+export class GrRuleEditor extends LitElement {
@property({type: Boolean})
hasRange?: boolean;
@property({type: Object})
label?: RuleLabel;
- @property({type: Boolean, observer: '_handleEditingChanged'})
+ @property({type: Boolean})
editing = false;
@property({type: String})
@@ -124,97 +120,280 @@
@property({type: String})
permission!: AccessPermissionId;
- @property({type: Object, notify: true})
+ @property({type: Object})
rule?: Rule;
@property({type: String})
section?: string;
- @property({type: Boolean})
- _deleted = false;
+ // private but used in test
+ @state() deleted = false;
- @property({type: Object})
- _originalRuleValues?: RuleValue;
+ // private but used in test
+ @state() originalRuleValues?: RuleValue;
constructor() {
super();
- this.addEventListener('access-saved', () => this._handleAccessSaved());
- }
-
- override ready() {
- super.ready();
- // Called on ready rather than the observer because when new rules are
- // added, the observer is triggered prior to being ready.
- if (!this.rule) {
- return;
- } // Check needed for test purposes.
- this._setupValues(this.rule);
+ this.addEventListener('access-saved', () => this.handleAccessSaved());
}
override connectedCallback() {
super.connectedCallback();
+ if (this.rule) {
+ this.setupValues();
+ }
// Check needed for test purposes.
- if (!this._originalRuleValues && this.rule) {
- // Observer _handleValueChange is called after the ready()
- // method finishes. Original values must be set later to
- // avoid set .modified flag to true
- this._setOriginalRuleValues(this.rule?.value);
+ if (!this.originalRuleValues && this.rule) {
+ this.setOriginalRuleValues();
}
}
- _setupValues(rule?: Rule) {
- if (!rule?.value) {
- this._setDefaultRuleValues();
+ static override get styles() {
+ return [
+ formStyles,
+ sharedStyles,
+ css`
+ :host {
+ border-bottom: 1px solid var(--border-color);
+ padding: var(--spacing-m);
+ display: block;
+ }
+ #removeBtn {
+ display: none;
+ }
+ .editing #removeBtn {
+ display: flex;
+ }
+ #options {
+ align-items: baseline;
+ display: flex;
+ }
+ #options > * {
+ margin-right: var(--spacing-m);
+ }
+ #mainContainer {
+ align-items: baseline;
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ }
+ #deletedContainer.deleted {
+ align-items: baseline;
+ display: flex;
+ justify-content: space-between;
+ }
+ #undoBtn,
+ #force,
+ #deletedContainer,
+ #mainContainer.deleted {
+ display: none;
+ }
+ #undoBtn.modified,
+ #force.force {
+ display: block;
+ }
+ .groupPath {
+ color: var(--deemphasized-text-color);
+ }
+ iron-autogrow-textarea {
+ width: 14em;
+ }
+ `,
+ ];
+ }
+
+ override render() {
+ return html`
+ <div
+ id="mainContainer"
+ class="gr-form-styles ${this.computeSectionClass()}"
+ >
+ <div id="options">
+ <gr-select
+ id="action"
+ .bindValue=${this.rule?.value?.action}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.handleActionBindValueChanged(e);
+ }}
+ >
+ <select ?disabled=${!this.editing}>
+ ${this.computeOptions().map(
+ item => html` <option value=${item}>${item}</option> `
+ )}
+ </select>
+ </gr-select>
+ ${this.renderMinAndMaxLabel()} ${this.renderMinAndMaxInput()}
+ <a class="groupPath" href="${this.computeGroupPath(this.groupId)}">
+ ${this.groupName}
+ </a>
+ <gr-select
+ id="force"
+ class="${this.computeForce(this.rule?.value?.action)
+ ? 'force'
+ : ''}"
+ .bindValue=${this.rule?.value?.force}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.handleForceBindValueChanged(e);
+ }}
+ >
+ <select ?disabled=${!this.editing}>
+ ${this.computeForceOptions(this.rule?.value?.action).map(
+ item => html`
+ <option value=${item.value}>${item.value}</option>
+ `
+ )}
+ </select>
+ </gr-select>
+ </div>
+ <gr-button
+ link
+ id="removeBtn"
+ @click=${() => {
+ this.handleRemoveRule();
+ }}
+ >Remove</gr-button
+ >
+ </div>
+ <div
+ id="deletedContainer"
+ class="gr-form-styles ${this.computeSectionClass()}"
+ >
+ ${this.groupName} was deleted
+ <gr-button
+ link
+ id="undoRemoveBtn"
+ @click=${() => {
+ this.handleUndoRemove();
+ }}
+ >Undo</gr-button
+ >
+ </div>
+ `;
+ }
+
+ private renderMinAndMaxLabel() {
+ if (!this.label) return;
+
+ return html`
+ <gr-select
+ id="labelMin"
+ .bindValue=${this.rule?.value?.min}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.handleMinBindValueChanged(e);
+ }}
+ >
+ <select ?disabled=${!this.editing}>
+ ${this.label.values.map(
+ item => html` <option value=${item.value}>${item.value}</option> `
+ )}
+ </select>
+ </gr-select>
+ <gr-select
+ id="labelMax"
+ .bindValue=${this.rule?.value?.max}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.handleMaxBindValueChanged(e);
+ }}
+ >
+ <select ?disabled=${!this.editing}>
+ ${this.label.values.map(
+ item => html` <option value=${item.value}>${item.value}</option> `
+ )}
+ </select>
+ </gr-select>
+ `;
+ }
+
+ private renderMinAndMaxInput() {
+ if (!this.hasRange) return;
+
+ return html`
+ <iron-autogrow-textarea
+ id="minInput"
+ class="min"
+ autocomplete="on"
+ placeholder="Min value"
+ .bindValue=${this.rule?.value?.min}
+ ?disabled=${!this.editing}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.handleMinBindValueChanged(e);
+ }}
+ ></iron-autogrow-textarea>
+ <iron-autogrow-textarea
+ id="maxInput"
+ class="max"
+ autocomplete="on"
+ placeholder="Max value"
+ .bindValue=${this.rule?.value?.max}
+ ?disabled=${!this.editing}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.handleMaxBindValueChanged(e);
+ }}
+ ></iron-autogrow-textarea>
+ `;
+ }
+
+ override willUpdate(changedProperties: PropertyValues) {
+ if (changedProperties.has('editing')) {
+ this.handleEditingChanged(changedProperties.get('editing') as boolean);
}
}
- _computeForce(permission: AccessPermissionId, action?: string) {
- if (AccessPermissionId.PUSH === permission && action !== Action.DENY) {
+ // private but used in test
+ setupValues() {
+ if (!this.rule?.value) {
+ this.setDefaultRuleValues();
+ }
+ }
+
+ // private but used in test
+ computeForce(action?: string) {
+ if (AccessPermissionId.PUSH === this.permission && action !== Action.DENY) {
return true;
}
- return AccessPermissionId.EDIT_TOPIC_NAME === permission;
+ return AccessPermissionId.EDIT_TOPIC_NAME === this.permission;
}
- _computeForceClass(permission: AccessPermissionId, action?: string) {
- return this._computeForce(permission, action) ? 'force' : '';
+ // private but used in test
+ computeGroupPath(groupId?: string) {
+ if (!groupId) return;
+ return `${getBaseUrl()}/admin/groups/${encodeURL(groupId, true)}`;
}
- _computeGroupPath(group: string) {
- return `${getBaseUrl()}/admin/groups/${encodeURL(group, true)}`;
- }
-
- _handleAccessSaved() {
- if (!this.rule) return;
+ // private but used in test
+ handleAccessSaved() {
// Set a new 'original' value to keep track of after the value has been
// saved.
- this._setOriginalRuleValues(this.rule.value);
+ this.setOriginalRuleValues();
}
- _handleEditingChanged(editing: boolean, editingOld: boolean) {
+ private handleEditingChanged(editingOld: boolean) {
// Ignore when editing gets set initially.
if (!editingOld) {
return;
}
// Restore original values if no longer editing.
- if (!editing) {
- this._handleUndoChange();
+ if (!this.editing) {
+ this.handleUndoChange();
}
}
- _computeSectionClass(editing: boolean, deleted: boolean) {
+ // private but used in test
+ computeSectionClass() {
const classList = [];
- if (editing) {
+ if (this.editing) {
classList.push('editing');
}
- if (deleted) {
+ if (this.deleted) {
classList.push('deleted');
}
return classList.join(' ');
}
- _computeForceOptions(permission: string, action?: string) {
- if (permission === AccessPermissionId.PUSH) {
+ // private but used in test
+ computeForceOptions(action?: string) {
+ if (this.permission === AccessPermissionId.PUSH) {
if (action === Action.ALLOW) {
return ForcePushOptions.ALLOW;
} else if (action === Action.BLOCK) {
@@ -222,83 +401,158 @@
} else {
return [];
}
- } else if (permission === AccessPermissionId.EDIT_TOPIC_NAME) {
+ } else if (this.permission === AccessPermissionId.EDIT_TOPIC_NAME) {
return FORCE_EDIT_OPTIONS;
}
return [];
}
- _getDefaultRuleValues(permission: AccessPermissionId, label?: RuleLabel) {
+ // private but used in test
+ getDefaultRuleValues() {
const ruleAction = Action.ALLOW;
const value: RuleValue = {};
- if (permission === AccessPermissionId.PRIORITY) {
+ if (this.permission === AccessPermissionId.PRIORITY) {
value.action = PRIORITY_OPTIONS[0];
return value;
- } else if (label) {
- value.min = label.values[0].value;
- value.max = label.values[label.values.length - 1].value;
- } else if (this._computeForce(permission, ruleAction)) {
- value.force = this._computeForceOptions(permission, ruleAction)[0].value;
+ } else if (this.label) {
+ value.min = this.label.values[0].value;
+ value.max = this.label.values[this.label.values.length - 1].value;
+ } else if (this.computeForce(ruleAction)) {
+ value.force = this.computeForceOptions(ruleAction)[0].value;
}
value.action = DROPDOWN_OPTIONS[0];
return value;
}
- _setDefaultRuleValues() {
- this.set(
- 'rule.value',
- this._getDefaultRuleValues(this.permission, this.label)
- );
+ // private but used in test
+ setDefaultRuleValues() {
+ this.rule!.value = this.getDefaultRuleValues();
+
+ this.handleRuleChange();
}
- _computeOptions(permission: string) {
- if (permission === 'priority') {
+ // private but used in test
+ computeOptions() {
+ if (this.permission === 'priority') {
return PRIORITY_OPTIONS;
}
return DROPDOWN_OPTIONS;
}
- _handleRemoveRule() {
+ private handleRemoveRule() {
if (!this.rule?.value) return;
if (this.rule.value.added) {
fireEvent(this, 'added-rule-removed');
}
- this._deleted = true;
+ this.deleted = true;
this.rule.value.deleted = true;
+
+ this.handleRuleChange();
+
fireEvent(this, 'access-modified');
}
- _handleUndoRemove() {
+ private handleUndoRemove() {
if (!this.rule?.value) return;
- this._deleted = false;
+ this.deleted = false;
delete this.rule.value.deleted;
+
+ this.handleRuleChange();
}
- _handleUndoChange() {
+ private handleUndoChange() {
if (!this.rule?.value) return;
// gr-permission will take care of removing rules that were added but
// unsaved. We need to keep the added bit for the filter.
if (this.rule.value.added) {
return;
}
- this.set('rule.value', {...this._originalRuleValues});
- this._deleted = false;
+ this.rule.value = {...this.originalRuleValues};
+ this.deleted = false;
delete this.rule.value.deleted;
delete this.rule.value.modified;
+
+ this.handleRuleChange();
}
- @observe('rule.value.*')
- _handleValueChange() {
- if (!this._originalRuleValues || !this.rule?.value) {
+ // private but used in test
+ handleValueChange() {
+ if (!this.originalRuleValues || !this.rule?.value) {
return;
}
this.rule.value.modified = true;
+
+ this.handleRuleChange();
+
// Allows overall access page to know a change has been made.
fireEvent(this, 'access-modified');
}
- _setOriginalRuleValues(value?: RuleValue) {
- if (value === undefined) return;
- this._originalRuleValues = {...value};
+ // private but used in test
+ setOriginalRuleValues() {
+ if (!this.rule?.value) return;
+ this.originalRuleValues = {...this.rule!.value};
+ }
+
+ private handleActionBindValueChanged(e: BindValueChangeEvent) {
+ if (
+ !this.rule?.value ||
+ e.detail.value === undefined ||
+ this.rule.value.action === String(e.detail.value)
+ )
+ return;
+
+ this.rule.value.action = String(e.detail.value);
+
+ this.handleValueChange();
+ }
+
+ private handleMinBindValueChanged(e: BindValueChangeEvent) {
+ if (
+ !this.rule?.value ||
+ e.detail.value === undefined ||
+ this.rule.value.min === Number(e.detail.value)
+ )
+ return;
+ this.rule.value.min = Number(e.detail.value);
+
+ this.handleValueChange();
+ }
+
+ private handleMaxBindValueChanged(e: BindValueChangeEvent) {
+ if (
+ !this.rule?.value ||
+ e.detail.value === undefined ||
+ this.rule.value.max === Number(e.detail.value)
+ )
+ return;
+ this.rule.value.max = Number(e.detail.value);
+
+ this.handleValueChange();
+ }
+
+ private handleForceBindValueChanged(e: BindValueChangeEvent) {
+ const forceValue = String(e.detail.value) === 'true' ? true : false;
+ if (
+ !this.rule?.value ||
+ e.detail.value === undefined ||
+ this.rule.value.force === forceValue
+ )
+ return;
+ this.rule.value.force = forceValue;
+
+ this.handleValueChange();
+ }
+
+ private handleRuleChange() {
+ this.requestUpdate('rule');
+
+ this.dispatchEvent(
+ new CustomEvent('rule-changed', {
+ detail: {value: this.rule},
+ composed: true,
+ bubbles: true,
+ })
+ );
}
}
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_html.ts b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_html.ts
deleted file mode 100644
index c4d7688..0000000
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_html.ts
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
- <style include="shared-styles">
- :host {
- border-bottom: 1px solid var(--border-color);
- padding: var(--spacing-m);
- display: block;
- }
- #removeBtn {
- display: none;
- }
- .editing #removeBtn {
- display: flex;
- }
- #options {
- align-items: baseline;
- display: flex;
- }
- #options > * {
- margin-right: var(--spacing-m);
- }
- #mainContainer {
- align-items: baseline;
- display: flex;
- flex-wrap: nowrap;
- justify-content: space-between;
- }
- #deletedContainer.deleted {
- align-items: baseline;
- display: flex;
- justify-content: space-between;
- }
- #undoBtn,
- #force,
- #deletedContainer,
- #mainContainer.deleted {
- display: none;
- }
- #undoBtn.modified,
- #force.force {
- display: block;
- }
- .groupPath {
- color: var(--deemphasized-text-color);
- }
- </style>
- <style include="gr-form-styles">
- iron-autogrow-textarea {
- width: 14em;
- }
- </style>
- <div
- id="mainContainer"
- class$="gr-form-styles [[_computeSectionClass(editing, _deleted)]]"
- >
- <div id="options">
- <gr-select
- id="action"
- bind-value="{{rule.value.action}}"
- on-change="_handleValueChange"
- >
- <select disabled$="[[!editing]]">
- <template is="dom-repeat" items="[[_computeOptions(permission)]]">
- <option value="[[item]]">[[item]]</option>
- </template>
- </select>
- </gr-select>
- <template is="dom-if" if="[[label]]">
- <gr-select
- id="labelMin"
- bind-value="{{rule.value.min}}"
- on-change="_handleValueChange"
- >
- <select disabled$="[[!editing]]">
- <template is="dom-repeat" items="[[label.values]]">
- <option value="[[item.value]]">[[item.value]]</option>
- </template>
- </select>
- </gr-select>
- <gr-select
- id="labelMax"
- bind-value="{{rule.value.max}}"
- on-change="_handleValueChange"
- >
- <select disabled$="[[!editing]]">
- <template is="dom-repeat" items="[[label.values]]">
- <option value="[[item.value]]">[[item.value]]</option>
- </template>
- </select>
- </gr-select>
- </template>
- <template is="dom-if" if="[[hasRange]]">
- <iron-autogrow-textarea
- id="minInput"
- class="min"
- autocomplete="on"
- placeholder="Min value"
- bind-value="{{rule.value.min}}"
- disabled$="[[!editing]]"
- ></iron-autogrow-textarea>
- <iron-autogrow-textarea
- id="maxInput"
- class="max"
- autocomplete="on"
- placeholder="Max value"
- bind-value="{{rule.value.max}}"
- disabled$="[[!editing]]"
- ></iron-autogrow-textarea>
- </template>
- <a class="groupPath" href$="[[_computeGroupPath(groupId)]]">
- [[groupName]]
- </a>
- <gr-select
- id="force"
- class$="[[_computeForceClass(permission, rule.value.action)]]"
- bind-value="{{rule.value.force}}"
- on-change="_handleValueChange"
- >
- <select disabled$="[[!editing]]">
- <template
- is="dom-repeat"
- items="[[_computeForceOptions(permission, rule.value.action)]]"
- >
- <option value="[[item.value]]">[[item.name]]</option>
- </template>
- </select>
- </gr-select>
- </div>
- <gr-button link="" id="removeBtn" on-click="_handleRemoveRule"
- >Remove</gr-button
- >
- </div>
- <div
- id="deletedContainer"
- class$="gr-form-styles [[_computeSectionClass(editing, _deleted)]]"
- >
- [[groupName]] was deleted
- <gr-button link="" id="undoRemoveBtn" on-click="_handleUndoRemove"
- >Undo</gr-button
- >
- </div>
-`;
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.ts b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.ts
index 1afd123..47c3bea 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.ts
@@ -29,12 +29,13 @@
suite('gr-rule-editor tests', () => {
let element: GrRuleEditor;
- setup(() => {
- element = basicFixture.instantiate();
+ setup(async () => {
+ element = basicFixture.instantiate() as GrRuleEditor;
+ await element.updateComplete;
});
suite('unit tests', () => {
- test('_computeForce, _computeForceClass, and _computeForceOptions', () => {
+ test('computeForce and computeForceOptions', () => {
const ForcePushOptions = {
ALLOW: [
{name: 'Allow pushing (but not force pushing)', value: false},
@@ -56,67 +57,55 @@
value: true,
},
];
- let permission = 'push' as AccessPermissionId;
+ element.permission = 'push' as AccessPermissionId;
let action = 'ALLOW';
- assert.isTrue(element._computeForce(permission, action));
- assert.equal(element._computeForceClass(permission, action), 'force');
+ assert.isTrue(element.computeForce(action));
assert.deepEqual(
- element._computeForceOptions(permission, action),
+ element.computeForceOptions(action),
ForcePushOptions.ALLOW
);
action = 'BLOCK';
- assert.isTrue(element._computeForce(permission, action));
- assert.equal(element._computeForceClass(permission, action), 'force');
+ assert.isTrue(element.computeForce(action));
assert.deepEqual(
- element._computeForceOptions(permission, action),
+ element.computeForceOptions(action),
ForcePushOptions.BLOCK
);
action = 'DENY';
- assert.isFalse(element._computeForce(permission, action));
- assert.equal(element._computeForceClass(permission, action), '');
- assert.equal(element._computeForceOptions(permission, action).length, 0);
+ assert.isFalse(element.computeForce(action));
+ assert.equal(element.computeForceOptions(action).length, 0);
- permission = 'editTopicName' as AccessPermissionId;
- assert.isTrue(element._computeForce(permission));
- assert.equal(element._computeForceClass(permission), 'force');
- assert.deepEqual(
- element._computeForceOptions(permission),
- FORCE_EDIT_OPTIONS
- );
- permission = 'submit' as AccessPermissionId;
- assert.isFalse(element._computeForce(permission));
- assert.equal(element._computeForceClass(permission), '');
- assert.deepEqual(element._computeForceOptions(permission), []);
+ element.permission = 'editTopicName' as AccessPermissionId;
+ assert.isTrue(element.computeForce());
+ assert.deepEqual(element.computeForceOptions(), FORCE_EDIT_OPTIONS);
+ element.permission = 'submit' as AccessPermissionId;
+ assert.isFalse(element.computeForce());
+ assert.deepEqual(element.computeForceOptions(), []);
});
- test('_computeSectionClass', () => {
- let deleted = true;
- let editing = false;
- assert.equal(element._computeSectionClass(editing, deleted), 'deleted');
+ test('computeSectionClass', () => {
+ element.deleted = true;
+ element.editing = false;
+ assert.equal(element.computeSectionClass(), 'deleted');
- deleted = false;
- assert.equal(element._computeSectionClass(editing, deleted), '');
+ element.deleted = false;
+ assert.equal(element.computeSectionClass(), '');
- editing = true;
- assert.equal(element._computeSectionClass(editing, deleted), 'editing');
+ element.editing = true;
+ assert.equal(element.computeSectionClass(), 'editing');
- deleted = true;
- assert.equal(
- element._computeSectionClass(editing, deleted),
- 'editing deleted'
- );
+ element.deleted = true;
+ assert.equal(element.computeSectionClass(), 'editing deleted');
});
- test('_getDefaultRuleValues', () => {
- let permission = 'priority' as AccessPermissionId;
- let label;
- assert.deepEqual(element._getDefaultRuleValues(permission, label), {
+ test('getDefaultRuleValues', () => {
+ element.permission = 'priority' as AccessPermissionId;
+ assert.deepEqual(element.getDefaultRuleValues(), {
action: 'BATCH',
});
- permission = 'label-Code-Review' as AccessPermissionId;
- label = {
+ element.permission = 'label-Code-Review' as AccessPermissionId;
+ element.label = {
values: [
{value: -2, text: 'This shall not be merged'},
{value: -1, text: 'I would prefer this is not merged as is'},
@@ -125,71 +114,73 @@
{value: 2, text: 'Looks good to me, approved'},
],
};
- assert.deepEqual(element._getDefaultRuleValues(permission, label), {
+ assert.deepEqual(element.getDefaultRuleValues(), {
action: 'ALLOW',
max: 2,
min: -2,
});
- permission = 'push' as AccessPermissionId;
- label = undefined;
- assert.deepEqual(element._getDefaultRuleValues(permission, label), {
+ element.permission = 'push' as AccessPermissionId;
+ element.label = undefined;
+ assert.deepEqual(element.getDefaultRuleValues(), {
action: 'ALLOW',
force: false,
});
- permission = 'submit' as AccessPermissionId;
- assert.deepEqual(element._getDefaultRuleValues(permission, label), {
+ element.permission = 'submit' as AccessPermissionId;
+ assert.deepEqual(element.getDefaultRuleValues(), {
action: 'ALLOW',
});
});
- test('_setDefaultRuleValues', async () => {
+ test('setDefaultRuleValues', async () => {
element.rule = {value: {}};
const defaultValue = {action: 'ALLOW'};
const getDefaultRuleValuesStub = sinon
- .stub(element, '_getDefaultRuleValues')
+ .stub(element, 'getDefaultRuleValues')
.returns(defaultValue);
- element._setDefaultRuleValues();
+ element.setDefaultRuleValues();
assert.isTrue(getDefaultRuleValuesStub.called);
assert.equal(element.rule!.value, defaultValue);
});
- test('_computeOptions', () => {
+ test('computeOptions', () => {
const PRIORITY_OPTIONS = ['BATCH', 'INTERACTIVE'];
const DROPDOWN_OPTIONS = ['ALLOW', 'DENY', 'BLOCK'];
- let permission = 'priority';
- assert.deepEqual(element._computeOptions(permission), PRIORITY_OPTIONS);
- permission = 'submit';
- assert.deepEqual(element._computeOptions(permission), DROPDOWN_OPTIONS);
+ element.permission = 'priority' as AccessPermissionId;
+ assert.deepEqual(element.computeOptions(), PRIORITY_OPTIONS);
+ element.permission = 'submit' as AccessPermissionId;
+ assert.deepEqual(element.computeOptions(), DROPDOWN_OPTIONS);
});
- test('_handleValueChange', () => {
+ test('handleValueChange', () => {
const modifiedHandler = sinon.stub();
element.rule = {value: {}};
element.addEventListener('access-modified', modifiedHandler);
- element._handleValueChange();
+ element.handleValueChange();
assert.isNotOk(element.rule!.value!.modified);
- element._originalRuleValues = {};
- element._handleValueChange();
+ element.originalRuleValues = {};
+ element.handleValueChange();
assert.isTrue(element.rule!.value!.modified);
assert.isTrue(modifiedHandler.called);
});
- test('_handleAccessSaved', () => {
+ test('handleAccessSaved', () => {
const originalValue = {action: 'DENY'};
const newValue = {action: 'ALLOW'};
- element._originalRuleValues = originalValue;
+ element.originalRuleValues = originalValue;
element.rule = {value: newValue};
- element._handleAccessSaved();
- assert.deepEqual(element._originalRuleValues, newValue);
+ element.handleAccessSaved();
+ assert.deepEqual(element.originalRuleValues, newValue);
});
- test('_setOriginalRuleValues', () => {
- const value = {
- action: 'ALLOW',
- force: false,
+ test('setOriginalRuleValues', () => {
+ element.rule = {
+ value: {
+ action: 'ALLOW',
+ force: false,
+ },
};
- element._setOriginalRuleValues(value);
- assert.deepEqual(element._originalRuleValues, value);
+ element.setOriginalRuleValues();
+ assert.deepEqual(element.originalRuleValues, element.rule.value);
});
});
@@ -204,16 +195,13 @@
},
};
element.section = 'refs/*';
-
- // Typically called on ready since elements will have properties defined
- // by the parent element.
- element._setupValues(element.rule);
- await flush();
- element.connectedCallback();
+ element.setupValues();
+ element.setOriginalRuleValues();
+ await element.updateComplete;
});
- test('_ruleValues and _originalRuleValues are set correctly', () => {
- assert.deepEqual(element._originalRuleValues, element.rule!.value);
+ test('_ruleValues and originalRuleValues are set correctly', () => {
+ assert.deepEqual(element.originalRuleValues, element.rule!.value);
});
test('values are set correctly', () => {
@@ -228,8 +216,10 @@
);
});
- test('modify and cancel restores original values', () => {
+ test('modify and cancel restores original values', async () => {
+ element.rule = {value: {}};
element.editing = true;
+ await element.updateComplete;
assert.notEqual(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
@@ -240,12 +230,13 @@
actionBindValue.bindValue = 'DENY';
assert.isTrue(element.rule!.value!.modified);
element.editing = false;
+ await element.updateComplete;
assert.equal(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
'none'
);
- assert.deepEqual(element._originalRuleValues, element.rule!.value);
+ assert.deepEqual(element.originalRuleValues, element.rule!.value);
assert.equal(
queryAndAssert<GrSelect>(element, '#action').bindValue,
'ALLOW'
@@ -253,31 +244,33 @@
assert.isNotOk(element.rule!.value!.modified);
});
- test('modify value', () => {
+ test('modify value', async () => {
assert.isNotOk(element.rule!.value!.modified);
const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
actionBindValue.bindValue = 'DENY';
- flush();
+ await element.updateComplete;
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
- assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
+ assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
});
- test('all selects are disabled when not in edit mode', () => {
+ test('all selects are disabled when not in edit mode', async () => {
const selects = queryAll<HTMLSelectElement>(element, 'select');
for (const select of selects) {
assert.isTrue(select.disabled);
}
element.editing = true;
+ await element.updateComplete;
for (const select of selects) {
assert.isFalse(select.disabled);
}
});
- test('remove rule and undo remove', () => {
+ test('remove rule and undo remove', async () => {
element.editing = true;
element.rule = {value: {action: 'ALLOW'}};
+ await element.updateComplete;
assert.isFalse(
queryAndAssert<HTMLDivElement>(
element,
@@ -285,22 +278,25 @@
).classList.contains('deleted')
);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
+ await element.updateComplete;
assert.isTrue(
queryAndAssert<HTMLDivElement>(
element,
'#deletedContainer'
).classList.contains('deleted')
);
- assert.isTrue(element._deleted);
+ assert.isTrue(element.deleted);
assert.isTrue(element.rule!.value!.deleted);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#undoRemoveBtn'));
- assert.isFalse(element._deleted);
+ await element.updateComplete;
+ assert.isFalse(element.deleted);
assert.isNotOk(element.rule!.value!.deleted);
});
- test('remove rule and cancel', () => {
+ test('remove rule and cancel', async () => {
element.editing = true;
+ await element.updateComplete;
assert.notEqual(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
@@ -314,7 +310,9 @@
);
element.rule = {value: {action: 'ALLOW'}};
+ await element.updateComplete;
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
+ await element.updateComplete;
assert.notEqual(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
@@ -326,15 +324,16 @@
).display,
'none'
);
- assert.isTrue(element._deleted);
+ assert.isTrue(element.deleted);
assert.isTrue(element.rule!.value!.deleted);
element.editing = false;
- assert.isFalse(element._deleted);
+ await element.updateComplete;
+ assert.isFalse(element.deleted);
assert.isNotOk(element.rule!.value!.deleted);
assert.isNotOk(element.rule!.value!.modified);
- assert.deepEqual(element._originalRuleValues, element.rule!.value);
+ assert.deepEqual(element.originalRuleValues, element.rule!.value);
assert.equal(
getComputedStyle(queryAndAssert<GrButton>(element, '#removeBtn'))
.display,
@@ -348,9 +347,9 @@
);
});
- test('_computeGroupPath', () => {
+ test('computeGroupPath', () => {
const group = '123';
- assert.equal(element._computeGroupPath(group), '/admin/groups/123');
+ assert.equal(element.computeGroupPath(group), '/admin/groups/123');
});
});
@@ -360,14 +359,14 @@
element.permission = 'editTopicName' as AccessPermissionId;
element.rule = {};
element.section = 'refs/*';
- element._setupValues(element.rule!);
- await flush();
+ element.setupValues();
+ await element.updateComplete;
element.rule!.value!.added = true;
- await flush();
+ await element.updateComplete;
element.connectedCallback();
});
- test('_ruleValues and _originalRuleValues are set correctly', () => {
+ test('_ruleValues and originalRuleValues are set correctly', () => {
// Since the element does not already have default values, they should
// be set. The original values should be set to those too.
assert.isNotOk(element.rule!.value!.modified);
@@ -389,23 +388,23 @@
});
});
- test('modify value', () => {
+ test('modify value', async () => {
assert.isNotOk(element.rule!.value!.modified);
const forceBindValue = queryAndAssert<GrSelect>(element, '#force');
- forceBindValue.bindValue = true;
- flush();
+ forceBindValue.bindValue = 'true';
+ await element.updateComplete;
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
- assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
+ assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
});
- test('remove value', () => {
+ test('remove value', async () => {
element.editing = true;
const removeStub = sinon.stub();
element.addEventListener('added-rule-removed', removeStub);
MockInteractions.tap(queryAndAssert<GrButton>(element, '#removeBtn'));
- flush();
+ await element.updateComplete;
assert.isTrue(removeStub.called);
});
});
@@ -432,13 +431,13 @@
},
};
element.section = 'refs/*';
- element._setupValues(element.rule);
- await flush();
+ element.setupValues();
+ await element.updateComplete;
element.connectedCallback();
});
- test('_ruleValues and _originalRuleValues are set correctly', () => {
- assert.deepEqual(element._originalRuleValues, element.rule!.value);
+ test('_ruleValues and originalRuleValues are set correctly', () => {
+ assert.deepEqual(element.originalRuleValues, element.rule!.value);
});
test('values are set correctly', () => {
@@ -459,18 +458,18 @@
);
});
- test('modify value', () => {
+ test('modify value', async () => {
const removeStub = sinon.stub();
element.addEventListener('added-rule-removed', removeStub);
assert.isNotOk(element.rule!.value!.modified);
const labelMinBindValue = queryAndAssert<GrSelect>(element, '#labelMin');
labelMinBindValue.bindValue = 1;
- flush();
+ await element.updateComplete;
assert.isTrue(element.rule!.value!.modified);
assert.isFalse(removeStub.called);
// The original value should now differ from the rule values.
- assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
+ assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
});
});
@@ -478,7 +477,7 @@
let setDefaultRuleValuesSpy: sinon.SinonSpy;
setup(async () => {
- setDefaultRuleValuesSpy = sinon.spy(element, '_setDefaultRuleValues');
+ setDefaultRuleValuesSpy = sinon.spy(element, 'setDefaultRuleValues');
element.label = {
values: [
{value: -2, text: 'This shall not be merged'},
@@ -492,14 +491,14 @@
element.permission = 'label-Code-Review' as AccessPermissionId;
element.rule = {};
element.section = 'refs/*';
- element._setupValues(element.rule!);
- await flush();
+ element.setupValues();
+ await element.updateComplete;
element.rule!.value!.added = true;
- await flush();
+ await element.updateComplete;
element.connectedCallback();
});
- test('_ruleValues and _originalRuleValues are set correctly', () => {
+ test('_ruleValues and originalRuleValues are set correctly', () => {
// Since the element does not already have default values, they should
// be set. The original values should be set to those too.
assert.isNotOk(element.rule!.value!.modified);
@@ -528,15 +527,15 @@
});
});
- test('modify value', () => {
+ test('modify value', async () => {
assert.isNotOk(element.rule!.value!.modified);
const labelMinBindValue = queryAndAssert<GrSelect>(element, '#labelMin');
labelMinBindValue.bindValue = 1;
- flush();
+ await element.updateComplete;
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
- assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
+ assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
});
});
@@ -551,108 +550,13 @@
},
};
element.section = 'refs/*';
- element._setupValues(element.rule!);
- await flush();
+ element.setupValues();
+ await element.updateComplete;
element.connectedCallback();
});
- test('_ruleValues and _originalRuleValues are set correctly', () => {
- assert.deepEqual(element._originalRuleValues, element.rule!.value);
- });
-
- test('values are set correctly', () => {
- assert.isTrue(
- queryAndAssert<GrSelect>(element, '#force').classList.contains('force')
- );
- assert.equal(
- queryAndAssert<GrSelect>(element, '#action').bindValue,
- element.rule!.value!.action
- );
- assert.equal(
- queryAndAssert<GrSelect>(element, '#force').bindValue,
- element.rule!.value!.force
- );
- assert.isNotOk(query<GrSelect>(element, '#labelMin'));
- assert.isNotOk(query<GrSelect>(element, '#labelMax'));
- });
-
- test('modify value', () => {
- assert.isNotOk(element.rule!.value!.modified);
- const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
- actionBindValue.bindValue = false;
- flush();
- assert.isTrue(element.rule!.value!.modified);
-
- // The original value should now differ from the rule values.
- assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
- });
- });
-
- suite('new push rule', () => {
- setup(async () => {
- element.groupName = 'Group Name';
- element.permission = 'push' as AccessPermissionId;
- element.rule = {};
- element.section = 'refs/*';
- element._setupValues(element.rule!);
- await flush();
- element.rule!.value!.added = true;
- await flush();
- element.connectedCallback();
- });
-
- test('_ruleValues and _originalRuleValues are set correctly', () => {
- // Since the element does not already have default values, they should
- // be set. The original values should be set to those too.
- assert.isNotOk(element.rule!.value!.modified);
- const expectedRuleValue = {
- action: 'ALLOW',
- force: false,
- added: true,
- };
- assert.deepEqual(element.rule!.value, expectedRuleValue);
- test('values are set correctly', () => {
- assert.equal(
- queryAndAssert<GrSelect>(element, '#action').bindValue,
- expectedRuleValue.action
- );
- assert.equal(
- queryAndAssert<GrSelect>(element, '#force').bindValue,
- expectedRuleValue.action
- );
- });
- });
-
- test('modify value', () => {
- assert.isNotOk(element.rule!.value!.modified);
- const forceBindValue = queryAndAssert<GrSelect>(element, '#force');
- forceBindValue.bindValue = true;
- flush();
- assert.isTrue(element.rule!.value!.modified);
-
- // The original value should now differ from the rule values.
- assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
- });
- });
-
- suite('already existing edit rule', () => {
- setup(async () => {
- element.groupName = 'Group Name';
- element.permission = 'editTopicName' as AccessPermissionId;
- element.rule = {
- value: {
- action: 'ALLOW',
- force: true,
- },
- };
- element.section = 'refs/*';
- element._setupValues(element.rule);
- await flush();
- element.connectedCallback();
- });
-
- test('_ruleValues and _originalRuleValues are set correctly', () => {
- assert.deepEqual(element._originalRuleValues, element.rule!.value);
+ test('_ruleValues and originalRuleValues are set correctly', () => {
+ assert.deepEqual(element.originalRuleValues, element.rule!.value);
});
test('values are set correctly', () => {
@@ -675,11 +579,106 @@
assert.isNotOk(element.rule!.value!.modified);
const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
actionBindValue.bindValue = false;
- await flush();
+ await element.updateComplete;
assert.isTrue(element.rule!.value!.modified);
// The original value should now differ from the rule values.
- assert.notDeepEqual(element._originalRuleValues, element.rule!.value);
+ assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
+ });
+ });
+
+ suite('new push rule', async () => {
+ setup(async () => {
+ element.groupName = 'Group Name';
+ element.permission = 'push' as AccessPermissionId;
+ element.rule = {};
+ element.section = 'refs/*';
+ element.setupValues();
+ await element.updateComplete;
+ element.rule!.value!.added = true;
+ await element.updateComplete;
+ element.connectedCallback();
+ });
+
+ test('_ruleValues and originalRuleValues are set correctly', () => {
+ // Since the element does not already have default values, they should
+ // be set. The original values should be set to those too.
+ assert.isNotOk(element.rule!.value!.modified);
+ const expectedRuleValue = {
+ action: 'ALLOW',
+ force: false,
+ added: true,
+ };
+ assert.deepEqual(element.rule!.value, expectedRuleValue);
+ test('values are set correctly', () => {
+ assert.equal(
+ queryAndAssert<GrSelect>(element, '#action').bindValue,
+ expectedRuleValue.action
+ );
+ assert.equal(
+ queryAndAssert<GrSelect>(element, '#force').bindValue,
+ expectedRuleValue.action
+ );
+ });
+ });
+
+ test('modify value', async () => {
+ assert.isNotOk(element.rule!.value!.modified);
+ const forceBindValue = queryAndAssert<GrSelect>(element, '#force');
+ forceBindValue.bindValue = true;
+ await element.updateComplete;
+ assert.isTrue(element.rule!.value!.modified);
+
+ // The original value should now differ from the rule values.
+ assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
+ });
+ });
+
+ suite('already existing edit rule', () => {
+ setup(async () => {
+ element.groupName = 'Group Name';
+ element.permission = 'editTopicName' as AccessPermissionId;
+ element.rule = {
+ value: {
+ action: 'ALLOW',
+ force: true,
+ },
+ };
+ element.section = 'refs/*';
+ element.setupValues();
+ await element.updateComplete;
+ element.connectedCallback();
+ });
+
+ test('_ruleValues and originalRuleValues are set correctly', () => {
+ assert.deepEqual(element.originalRuleValues, element.rule!.value);
+ });
+
+ test('values are set correctly', () => {
+ assert.isTrue(
+ queryAndAssert<GrSelect>(element, '#force').classList.contains('force')
+ );
+ assert.equal(
+ queryAndAssert<GrSelect>(element, '#action').bindValue,
+ element.rule!.value!.action
+ );
+ assert.equal(
+ queryAndAssert<GrSelect>(element, '#force').bindValue,
+ element.rule!.value!.force
+ );
+ assert.isNotOk(query<GrSelect>(element, '#labelMin'));
+ assert.isNotOk(query<GrSelect>(element, '#labelMax'));
+ });
+
+ test('modify value', async () => {
+ assert.isNotOk(element.rule!.value!.modified);
+ const actionBindValue = queryAndAssert<GrSelect>(element, '#action');
+ actionBindValue.bindValue = false;
+ await element.updateComplete;
+ assert.isTrue(element.rule!.value!.modified);
+
+ // The original value should now differ from the rule values.
+ assert.notDeepEqual(element.originalRuleValues, element.rule!.value);
});
});
});