Merge "Split gr-related-change to separate file"
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-change.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-change.ts
new file mode 100644
index 0000000..3ed545e
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-change.ts
@@ -0,0 +1,197 @@
+/**
+ * @license
+ * Copyright (C) 2021 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 'lit-html';
+import {GrLitElement} from '../../lit/gr-lit-element';
+import {customElement, property, css} from 'lit-element';
+import {sharedStyles} from '../../../styles/shared-styles';
+import {
+  ChangeInfo,
+  RelatedChangeAndCommitInfo,
+  CommitId,
+} from '../../../types/common';
+import {ChangeStatus} from '../../../constants/constants';
+import {isChangeInfo} from '../../../utils/change-util';
+
+@customElement('gr-related-change')
+export class GrRelatedChange extends GrLitElement {
+  @property()
+  change?: ChangeInfo | RelatedChangeAndCommitInfo;
+
+  @property()
+  href?: string;
+
+  @property()
+  isCurrentChange = false;
+
+  @property()
+  showSubmittableCheck = false;
+
+  @property()
+  showChangeStatus = false;
+
+  /*
+   * Needed for calculation if change is direct or indirect ancestor/descendant
+   * to current change.
+   */
+  @property()
+  connectedRevisions?: CommitId[];
+
+  static get styles() {
+    return [
+      sharedStyles,
+      css`
+        a {
+          display: block;
+        }
+        .changeContainer,
+        a {
+          max-width: 100%;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+        .changeContainer {
+          display: flex;
+        }
+        .strikethrough {
+          color: var(--deemphasized-text-color);
+          text-decoration: line-through;
+        }
+        .status {
+          color: var(--deemphasized-text-color);
+          font-weight: var(--font-weight-bold);
+          margin-left: var(--spacing-xs);
+        }
+        .notCurrent {
+          color: #e65100;
+        }
+        .indirectAncestor {
+          color: #33691e;
+        }
+        .submittableCheck {
+          padding-left: var(--spacing-s);
+          color: var(--positive-green-text-color);
+          display: none;
+        }
+        .submittableCheck.submittable {
+          display: inline;
+        }
+        .hidden,
+        .mobile {
+          display: none;
+        }
+        .submittableCheck {
+          padding-left: var(--spacing-s);
+          color: var(--positive-green-text-color);
+          display: none;
+        }
+        .submittableCheck.submittable {
+          display: inline;
+        }
+        .arrowToCurrentChange {
+          position: absolute;
+        }
+      `,
+    ];
+  }
+
+  render() {
+    const change = this.change;
+    if (!change) throw new Error('Missing change');
+    const linkClass = this._computeLinkClass(change);
+    return html`<span
+        role="img"
+        class="arrowToCurrentChange"
+        aria-label="Arrow marking current change"
+        ?hidden=${!this.isCurrentChange}
+        >➔</span
+      >
+      <div class="changeContainer">
+        <a href="${this.href}" class="${linkClass}"><slot></slot></a>
+        ${this.showSubmittableCheck
+          ? html`<span
+              tabindex="-1"
+              title="Submittable"
+              class="submittableCheck ${linkClass}"
+              role="img"
+              aria-label="Submittable"
+              >✓</span
+            >`
+          : ''}
+        ${this.showChangeStatus && !isChangeInfo(change)
+          ? html`<span class="${this._computeChangeStatusClass(change)}">
+              (${this._computeChangeStatus(change)})
+            </span>`
+          : ''}
+      </div> `;
+  }
+
+  _computeLinkClass(change: ChangeInfo | RelatedChangeAndCommitInfo) {
+    const statuses = [];
+    if (change.status === ChangeStatus.ABANDONED) {
+      statuses.push('strikethrough');
+    }
+    if (change.submittable) {
+      statuses.push('submittable');
+    }
+    return statuses.join(' ');
+  }
+
+  _computeChangeStatusClass(change: RelatedChangeAndCommitInfo) {
+    const classes = ['status'];
+    if (change._revision_number !== change._current_revision_number) {
+      classes.push('notCurrent');
+    } else if (this._isIndirectAncestor(change)) {
+      classes.push('indirectAncestor');
+    } else if (change.submittable) {
+      classes.push('submittable');
+    } else if (change.status === ChangeStatus.NEW) {
+      classes.push('hidden');
+    }
+    return classes.join(' ');
+  }
+
+  _computeChangeStatus(change: RelatedChangeAndCommitInfo) {
+    switch (change.status) {
+      case ChangeStatus.MERGED:
+        return 'Merged';
+      case ChangeStatus.ABANDONED:
+        return 'Abandoned';
+    }
+    if (change._revision_number !== change._current_revision_number) {
+      return 'Not current';
+    } else if (this._isIndirectAncestor(change)) {
+      return 'Indirect ancestor';
+    } else if (change.submittable) {
+      return 'Submittable';
+    }
+    return '';
+  }
+
+  _isIndirectAncestor(change: RelatedChangeAndCommitInfo) {
+    return (
+      this.connectedRevisions &&
+      !this.connectedRevisions.includes(change.commit.commit)
+    );
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'gr-related-change': GrRelatedChange;
+  }
+}
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts
index 77bdf48..be48038 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 import {html, nothing} from 'lit-html';
+import './gr-related-change';
 import {classMap} from 'lit-html/directives/class-map';
 import {GrLitElement} from '../../lit/gr-lit-element';
 import {customElement, property, css} from 'lit-element';
@@ -31,14 +32,7 @@
 import {ParsedChangeInfo} from '../../../types/types';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {pluralize} from '../../../utils/string-util';
-import {ChangeStatus} from '../../../constants/constants';
-import {getRevisionKey} from '../../../utils/change-util';
-
-function isChangeInfo(
-  x: ChangeInfo | RelatedChangeAndCommitInfo | ParsedChangeInfo
-): x is ChangeInfo | ParsedChangeInfo {
-  return (x as ChangeInfo)._number !== undefined;
-}
+import {getRevisionKey, isChangeInfo} from '../../../utils/change-util';
 
 /** What is the maximum number of shown changes in collapsed list? */
 const MAX_CHANGES_WHEN_COLLAPSED = 3;
@@ -342,174 +336,9 @@
   }
 }
 
-@customElement('gr-related-change')
-export class GrRelatedChange extends GrLitElement {
-  @property()
-  change?: ChangeInfo | RelatedChangeAndCommitInfo;
-
-  @property()
-  href?: string;
-
-  @property()
-  isCurrentChange = false;
-
-  @property()
-  showSubmittableCheck = false;
-
-  @property()
-  showChangeStatus = false;
-
-  /*
-   * Needed for calculation if change is direct or indirect ancestor/descendant
-   * to current change.
-   */
-  @property()
-  connectedRevisions?: CommitId[];
-
-  static get styles() {
-    return [
-      sharedStyles,
-      css`
-        a {
-          display: block;
-        }
-        .changeContainer,
-        a {
-          max-width: 100%;
-          overflow: hidden;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-        }
-        .changeContainer {
-          display: flex;
-        }
-        .strikethrough {
-          color: var(--deemphasized-text-color);
-          text-decoration: line-through;
-        }
-        .status {
-          color: var(--deemphasized-text-color);
-          font-weight: var(--font-weight-bold);
-          margin-left: var(--spacing-xs);
-        }
-        .notCurrent {
-          color: #e65100;
-        }
-        .indirectAncestor {
-          color: #33691e;
-        }
-        .submittableCheck {
-          padding-left: var(--spacing-s);
-          color: var(--positive-green-text-color);
-          display: none;
-        }
-        .submittableCheck.submittable {
-          display: inline;
-        }
-        .hidden,
-        .mobile {
-          display: none;
-        }
-        .submittableCheck {
-          padding-left: var(--spacing-s);
-          color: var(--positive-green-text-color);
-          display: none;
-        }
-        .submittableCheck.submittable {
-          display: inline;
-        }
-        .arrowToCurrentChange {
-          position: absolute;
-        }
-      `,
-    ];
-  }
-
-  render() {
-    const change = this.change;
-    if (!change) throw new Error('Missing change');
-    const linkClass = this._computeLinkClass(change);
-    return html`<span
-        role="img"
-        class="arrowToCurrentChange"
-        aria-label="Arrow marking current change"
-        ?hidden=${!this.isCurrentChange}
-        >➔</span
-      >
-      <div class="changeContainer">
-        <a href="${this.href}" class="${linkClass}"><slot></slot></a>
-        ${this.showSubmittableCheck
-          ? html`<span
-              tabindex="-1"
-              title="Submittable"
-              class="submittableCheck ${linkClass}"
-              role="img"
-              aria-label="Submittable"
-              >✓</span
-            >`
-          : ''}
-        ${this.showChangeStatus && !isChangeInfo(change)
-          ? html`<span class="${this._computeChangeStatusClass(change)}">
-              (${this._computeChangeStatus(change)})
-            </span>`
-          : ''}
-      </div> `;
-  }
-
-  _computeLinkClass(change: ChangeInfo | RelatedChangeAndCommitInfo) {
-    const statuses = [];
-    if (change.status === ChangeStatus.ABANDONED) {
-      statuses.push('strikethrough');
-    }
-    if (change.submittable) {
-      statuses.push('submittable');
-    }
-    return statuses.join(' ');
-  }
-
-  _computeChangeStatusClass(change: RelatedChangeAndCommitInfo) {
-    const classes = ['status'];
-    if (change._revision_number !== change._current_revision_number) {
-      classes.push('notCurrent');
-    } else if (this._isIndirectAncestor(change)) {
-      classes.push('indirectAncestor');
-    } else if (change.submittable) {
-      classes.push('submittable');
-    } else if (change.status === ChangeStatus.NEW) {
-      classes.push('hidden');
-    }
-    return classes.join(' ');
-  }
-
-  _computeChangeStatus(change: RelatedChangeAndCommitInfo) {
-    switch (change.status) {
-      case ChangeStatus.MERGED:
-        return 'Merged';
-      case ChangeStatus.ABANDONED:
-        return 'Abandoned';
-    }
-    if (change._revision_number !== change._current_revision_number) {
-      return 'Not current';
-    } else if (this._isIndirectAncestor(change)) {
-      return 'Indirect ancestor';
-    } else if (change.submittable) {
-      return 'Submittable';
-    }
-    return '';
-  }
-
-  _isIndirectAncestor(change: RelatedChangeAndCommitInfo) {
-    return (
-      this.connectedRevisions &&
-      !this.connectedRevisions.includes(change.commit.commit)
-    );
-  }
-}
-
 declare global {
   interface HTMLElementTagNameMap {
     'gr-related-changes-list-experimental': GrRelatedChangesListExperimental;
     'gr-related-collapse': GrRelatedCollapse;
-    'gr-related-change': GrRelatedChange;
   }
 }
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
index ba0ca43..b4b6d31 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
@@ -26,7 +26,11 @@
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {ChangeStatus} from '../../../constants/constants';
 
-import {changeIsOpen, getRevisionKey} from '../../../utils/change-util';
+import {
+  changeIsOpen,
+  getRevisionKey,
+  isChangeInfo,
+} from '../../../utils/change-util';
 import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
 import {customElement, observe, property} from '@polymer/decorators';
 import {
@@ -48,12 +52,6 @@
   return {changes: [], non_visible_changes: 0};
 }
 
-function isChangeInfo(
-  x: ChangeInfo | RelatedChangeAndCommitInfo
-): x is ChangeInfo {
-  return (x as ChangeInfo)._number !== undefined;
-}
-
 @customElement('gr-related-changes-list')
 export class GrRelatedChangesList extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
diff --git a/polygerrit-ui/app/utils/change-util.ts b/polygerrit-ui/app/utils/change-util.ts
index 8839be1..1228863 100644
--- a/polygerrit-ui/app/utils/change-util.ts
+++ b/polygerrit-ui/app/utils/change-util.ts
@@ -21,6 +21,7 @@
   PatchSetNum,
   ChangeInfo,
   AccountInfo,
+  RelatedChangeAndCommitInfo,
 } from '../types/common';
 import {ParsedChangeInfo} from '../types/types';
 
@@ -225,3 +226,9 @@
       (!reviewer._account_id && account.email === reviewer.email)
   );
 }
+
+export function isChangeInfo(
+  x: ChangeInfo | RelatedChangeAndCommitInfo | ParsedChangeInfo
+): x is ChangeInfo | ParsedChangeInfo {
+  return (x as ChangeInfo)._number !== undefined;
+}