Merge changes from topic "gr-change-requirements-to-ts"

* changes:
  Convert gr-change-requirements to typescript
  Rename files to preserve history
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
deleted file mode 100644
index 8dfee81..0000000
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 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 '../../../styles/shared-styles.js';
-import '../../shared/gr-button/gr-button.js';
-import '../../shared/gr-icons/gr-icons.js';
-import '../../shared/gr-label/gr-label.js';
-import '../../shared/gr-label-info/gr-label-info.js';
-import '../../shared/gr-limited-text/gr-limited-text.js';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-import {htmlTemplate} from './gr-change-requirements_html.js';
-
-/**
- * @extends PolymerElement
- */
-class GrChangeRequirements extends GestureEventListeners(
-    LegacyElementMixin(PolymerElement)) {
-  static get template() { return htmlTemplate; }
-
-  static get is() { return 'gr-change-requirements'; }
-
-  static get properties() {
-    return {
-    /** @type {?} */
-      change: Object,
-      account: Object,
-      mutable: Boolean,
-      _requirements: {
-        type: Array,
-        computed: '_computeRequirements(change)',
-      },
-      _requiredLabels: {
-        type: Array,
-        value: () => [],
-      },
-      _optionalLabels: {
-        type: Array,
-        value: () => [],
-      },
-      _showWip: {
-        type: Boolean,
-        computed: '_computeShowWip(change)',
-      },
-      _showOptionalLabels: {
-        type: Boolean,
-        value: true,
-      },
-    };
-  }
-
-  static get observers() {
-    return [
-      '_computeLabels(change.labels.*)',
-    ];
-  }
-
-  _computeShowWip(change) {
-    return change.work_in_progress;
-  }
-
-  _computeRequirements(change) {
-    const _requirements = [];
-
-    if (change.requirements) {
-      for (const requirement of change.requirements) {
-        requirement.satisfied = requirement.status === 'OK';
-        requirement.style =
-            this._computeRequirementClass(requirement.satisfied);
-        _requirements.push(requirement);
-      }
-    }
-    if (change.work_in_progress) {
-      _requirements.push({
-        type: 'wip',
-        fallback_text: 'Work-in-progress',
-        tooltip: 'Change must not be in \'Work in Progress\' state.',
-      });
-    }
-
-    return _requirements;
-  }
-
-  _computeRequirementClass(requirementStatus) {
-    return requirementStatus ? 'approved' : '';
-  }
-
-  _computeRequirementIcon(requirementStatus) {
-    return requirementStatus ? 'gr-icons:check' : 'gr-icons:schedule';
-  }
-
-  _computeLabels(labelsRecord) {
-    const labels = labelsRecord.base;
-    this._optionalLabels = [];
-    this._requiredLabels = [];
-
-    for (const label in labels) {
-      if (!labels.hasOwnProperty(label)) { continue; }
-
-      const labelInfo = labels[label];
-      const icon = this._computeLabelIcon(labelInfo);
-      const style = this._computeLabelClass(labelInfo);
-      const path = labelInfo.optional ? '_optionalLabels' : '_requiredLabels';
-
-      this.push(path, {label, icon, style, labelInfo});
-    }
-  }
-
-  /**
-   * @param {Object} labelInfo
-   * @return {string} The icon name, or undefined if no icon should
-   *     be used.
-   */
-  _computeLabelIcon(labelInfo) {
-    if (labelInfo.approved) { return 'gr-icons:check'; }
-    if (labelInfo.rejected) { return 'gr-icons:close'; }
-    return 'gr-icons:schedule';
-  }
-
-  /**
-   * @param {Object} labelInfo
-   */
-  _computeLabelClass(labelInfo) {
-    if (labelInfo.approved) { return 'approved'; }
-    if (labelInfo.rejected) { return 'rejected'; }
-    return '';
-  }
-
-  _computeShowOptional(optionalFieldsRecord) {
-    return optionalFieldsRecord.base.length ? '' : 'hidden';
-  }
-
-  _computeLabelValue(value) {
-    return (value > 0 ? '+' : '') + value;
-  }
-
-  _computeShowHideIcon(showOptionalLabels) {
-    return showOptionalLabels ?
-      'gr-icons:expand-less' :
-      'gr-icons:expand-more';
-  }
-
-  _computeSectionClass(show) {
-    return show ? '' : 'hidden';
-  }
-
-  _handleShowHide(e) {
-    this._showOptionalLabels = !this._showOptionalLabels;
-  }
-
-  _computeSubmitRequirementEndpoint(item) {
-    return `submit-requirement-item-${item.type}`;
-  }
-}
-
-customElements.define(GrChangeRequirements.is, GrChangeRequirements);
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
new file mode 100644
index 0000000..7a99086
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
@@ -0,0 +1,202 @@
+/**
+ * @license
+ * Copyright (C) 2018 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 '../../../styles/shared-styles';
+import '../../shared/gr-button/gr-button';
+import '../../shared/gr-icons/gr-icons';
+import '../../shared/gr-label/gr-label';
+import '../../shared/gr-label-info/gr-label-info';
+import '../../shared/gr-limited-text/gr-limited-text';
+import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
+import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
+import {PolymerElement} from '@polymer/polymer/polymer-element';
+import {htmlTemplate} from './gr-change-requirements_html';
+import {customElement, property, observe} from '@polymer/decorators';
+import {
+  ChangeInfo,
+  AccountInfo,
+  QuickLabelInfo,
+  Requirement,
+  RequirementType,
+  LabelNameToInfoMap,
+  LabelInfo,
+} from '../../../types/common';
+import {hasOwnProperty} from '../../../utils/common-util';
+import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
+
+interface ChangeRequirement extends Requirement {
+  satisfied: boolean;
+  style: string;
+}
+
+interface ChangeWIP {
+  type: RequirementType;
+  fallback_text: string;
+  tooltip: string;
+}
+
+interface Label {
+  labelInfo: LabelInfo;
+  icon: string;
+  style: string;
+}
+
+@customElement('gr-change-requirements')
+class GrChangeRequirements extends GestureEventListeners(
+  LegacyElementMixin(PolymerElement)
+) {
+  static get template() {
+    return htmlTemplate;
+  }
+
+  @property({type: Object})
+  change?: ChangeInfo;
+
+  @property({type: Object})
+  account?: AccountInfo;
+
+  @property({type: Boolean})
+  mutable?: boolean;
+
+  @property({type: Array, computed: '_computeRequirements(change)'})
+  _requirements?: Array<ChangeRequirement | ChangeWIP>;
+
+  @property({type: Array})
+  _requiredLabels: Label[] = [];
+
+  @property({type: Array})
+  _optionalLabels: Label[] = [];
+
+  @property({type: Boolean, computed: '_computeShowWip(change)'})
+  _showWip?: boolean;
+
+  @property({type: Boolean})
+  _showOptionalLabels = true;
+
+  _computeShowWip(change: ChangeInfo) {
+    return change.work_in_progress;
+  }
+
+  _computeRequirements(change: ChangeInfo) {
+    const _requirements: Array<ChangeRequirement | ChangeWIP> = [];
+
+    if (change.requirements) {
+      for (const requirement of change.requirements) {
+        const satisfied = requirement.status === 'OK';
+        const style = this._computeRequirementClass(satisfied);
+        _requirements.push({...requirement, satisfied, style});
+      }
+    }
+    if (change.work_in_progress) {
+      _requirements.push({
+        type: 'wip' as RequirementType,
+        fallback_text: 'Work-in-progress',
+        tooltip: "Change must not be in 'Work in Progress' state.",
+      });
+    }
+
+    return _requirements;
+  }
+
+  _computeRequirementClass(requirementStatus: boolean) {
+    return requirementStatus ? 'approved' : '';
+  }
+
+  _computeRequirementIcon(requirementStatus: boolean) {
+    return requirementStatus ? 'gr-icons:check' : 'gr-icons:schedule';
+  }
+
+  @observe('change.labels.*')
+  _computeLabels(
+    labelsRecord: PolymerDeepPropertyChange<
+      LabelNameToInfoMap,
+      LabelNameToInfoMap
+    >
+  ) {
+    const labels = labelsRecord.base;
+    this._optionalLabels = [];
+    this._requiredLabels = [];
+
+    for (const label in labels) {
+      if (!hasOwnProperty(labels, label)) {
+        continue;
+      }
+
+      const labelInfo = labels[label];
+      const icon = this._computeLabelIcon(labelInfo);
+      const style = this._computeLabelClass(labelInfo);
+      const path = labelInfo.optional ? '_optionalLabels' : '_requiredLabels';
+
+      this.push(path, {label, icon, style, labelInfo});
+    }
+  }
+
+  /**
+   * @return The icon name, or undefined if no icon should
+   * be used.
+   */
+  _computeLabelIcon(labelInfo: QuickLabelInfo) {
+    if (labelInfo.approved) {
+      return 'gr-icons:check';
+    }
+    if (labelInfo.rejected) {
+      return 'gr-icons:close';
+    }
+    return 'gr-icons:schedule';
+  }
+
+  _computeLabelClass(labelInfo: QuickLabelInfo) {
+    if (labelInfo.approved) {
+      return 'approved';
+    }
+    if (labelInfo.rejected) {
+      return 'rejected';
+    }
+    return '';
+  }
+
+  _computeShowOptional(
+    optionalFieldsRecord: PolymerDeepPropertyChange<Label[], Label[]>
+  ) {
+    return optionalFieldsRecord.base.length ? '' : 'hidden';
+  }
+
+  _computeLabelValue(value: number) {
+    return `${value > 0 ? '+' : ''}${value}`;
+  }
+
+  _computeShowHideIcon(showOptionalLabels: boolean) {
+    return showOptionalLabels ? 'gr-icons:expand-less' : 'gr-icons:expand-more';
+  }
+
+  _computeSectionClass(show: boolean) {
+    return show ? '' : 'hidden';
+  }
+
+  _handleShowHide() {
+    this._showOptionalLabels = !this._showOptionalLabels;
+  }
+
+  _computeSubmitRequirementEndpoint(item: ChangeRequirement | ChangeWIP) {
+    return `submit-requirement-item-${item.type}`;
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'gr-change-requirements': GrChangeRequirements;
+  }
+}