Convert gr-change-list-item to typescript
The change converts the following files to typescript:
* elements/change-list/gr-change-list-item/gr-change-list-item.ts
Change-Id: I9cb551f96e5ed6bf2c4c1ad15a0af22eaae2d51f
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
index 673332b..5d898bd 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
@@ -15,128 +15,145 @@
* limitations under the License.
*/
-import '../../../styles/gr-change-list-styles.js';
-import '../../shared/gr-account-link/gr-account-link.js';
-import '../../shared/gr-change-star/gr-change-star.js';
-import '../../shared/gr-change-status/gr-change-status.js';
-import '../../shared/gr-date-formatter/gr-date-formatter.js';
-import '../../shared/gr-icons/gr-icons.js';
-import '../../shared/gr-limited-text/gr-limited-text.js';
-import '../../shared/gr-tooltip-content/gr-tooltip-content.js';
-import '../../../styles/shared-styles.js';
-import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
-import '../../plugins/gr-endpoint-param/gr-endpoint-param.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-list-item_html.js';
-import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin.js';
-import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {getDisplayName} from '../../../utils/display-name-util.js';
-import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {appContext} from '../../../services/app-context.js';
-import {truncatePath} from '../../../utils/path-list-util.js';
-import {changeStatuses} from '../../../utils/change-util.js';
-import {isServiceUser} from '../../../utils/account-util.js';
+import '../../../styles/gr-change-list-styles';
+import '../../shared/gr-account-link/gr-account-link';
+import '../../shared/gr-change-star/gr-change-star';
+import '../../shared/gr-change-status/gr-change-status';
+import '../../shared/gr-date-formatter/gr-date-formatter';
+import '../../shared/gr-icons/gr-icons';
+import '../../shared/gr-limited-text/gr-limited-text';
+import '../../shared/gr-tooltip-content/gr-tooltip-content';
+import '../../../styles/shared-styles';
+import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
+import '../../plugins/gr-endpoint-param/gr-endpoint-param';
+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-list-item_html';
+import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {getDisplayName} from '../../../utils/display-name-util';
+import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
+import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
+import {appContext} from '../../../services/app-context';
+import {truncatePath} from '../../../utils/path-list-util';
+import {changeStatuses} from '../../../utils/change-util';
+import {isServiceUser} from '../../../utils/account-util';
+import {customElement, property} from '@polymer/decorators';
+import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
+import {
+ ChangeInfo,
+ ServerInfo,
+ AccountInfo,
+ QuickLabelInfo,
+} from '../../../types/common';
+import {hasOwnProperty} from '../../../utils/common-util';
-const CHANGE_SIZE = {
- XS: 10,
- SMALL: 50,
- MEDIUM: 250,
- LARGE: 1000,
-};
+enum CHANGE_SIZE {
+ XS = 10,
+ SMALL = 50,
+ MEDIUM = 250,
+ LARGE = 1000,
+}
// How many reviewers should be shown with an account-label?
const PRIMARY_REVIEWERS_COUNT = 2;
-/**
- * @extends PolymerElement
- */
-class GrChangeListItem extends ChangeTableMixin(GestureEventListeners(
- LegacyElementMixin(PolymerElement))) {
- static get template() { return htmlTemplate; }
-
- static get is() { return 'gr-change-list-item'; }
-
- static get properties() {
- return {
- /** The logged-in user's account, or null if no user is logged in. */
- account: {
- type: Object,
- value: null,
- },
- visibleChangeTableColumns: Array,
- labelNames: {
- type: Array,
- },
-
- /** @type {?} */
- change: Object,
- config: Object,
- /** Name of the section in the change-list. Used for reporting. */
- sectionName: String,
- changeURL: {
- type: String,
- computed: '_computeChangeURL(change)',
- },
- statuses: {
- type: Array,
- computed: '_changeStatuses(change)',
- },
- showStar: {
- type: Boolean,
- value: false,
- },
- showNumber: Boolean,
- _changeSize: {
- type: String,
- computed: '_computeChangeSize(change)',
- },
- _dynamicCellEndpoints: {
- type: Array,
- },
- };
+@customElement('gr-change-list-item')
+class GrChangeListItem extends ChangeTableMixin(
+ GestureEventListeners(LegacyElementMixin(PolymerElement))
+) {
+ static get template() {
+ return htmlTemplate;
}
- constructor() {
- super();
- this.reporting = appContext.reportingService;
- }
+ /** The logged-in user's account, or null if no user is logged in. */
+ @property({type: Object})
+ account: AccountInfo | null = null;
+
+ @property({type: Array})
+ visibleChangeTableColumns?: string[];
+
+ @property({type: Array})
+ labelNames?: string[];
+
+ @property({type: Object})
+ change?: ChangeInfo;
+
+ @property({type: Object})
+ config?: ServerInfo;
+
+ /** Name of the section in the change-list. Used for reporting. */
+ @property({type: String})
+ sectionName?: string;
+
+ @property({type: String, computed: '_computeChangeURL(change)'})
+ changeURL?: string;
+
+ @property({type: Array, computed: '_changeStatuses(change)'})
+ statuses?: string[];
+
+ @property({type: Boolean})
+ showStar = false;
+
+ @property({type: Boolean})
+ showNumber = false;
+
+ @property({type: String, computed: '_computeChangeSize(change)'})
+ _changeSize?: string;
+
+ @property({type: Array})
+ _dynamicCellEndpoints?: string[];
+
+ reporting: ReportingService = appContext.reportingService;
/** @override */
attached() {
super.attached();
- getPluginLoader().awaitPluginsLoaded()
- .then(() => {
- this._dynamicCellEndpoints = getPluginEndpoints().getDynamicEndpoints(
- 'change-list-item-cell');
- });
+ getPluginLoader()
+ .awaitPluginsLoaded()
+ .then(() => {
+ this._dynamicCellEndpoints = getPluginEndpoints().getDynamicEndpoints(
+ 'change-list-item-cell'
+ );
+ });
}
- _changeStatuses(change) {
+ _changeStatuses(change?: ChangeInfo) {
+ if (!change) return [];
return changeStatuses(change);
}
- _computeChangeURL(change) {
+ _computeChangeURL(change?: ChangeInfo) {
+ if (!change) return '';
return GerritNav.getUrlForChange(change);
}
- _computeLabelTitle(change, labelName) {
- const label = change.labels[labelName];
- if (!label) { return 'Label not applicable'; }
- const significantLabel = label.rejected || label.approved ||
- label.disliked || label.recommended;
+ _computeLabelTitle(change: ChangeInfo | undefined, labelName: string) {
+ const label: QuickLabelInfo | undefined = change?.labels?.[labelName];
+ if (!label) {
+ return 'Label not applicable';
+ }
+ const significantLabel =
+ label.rejected || label.approved || label.disliked || label.recommended;
if (significantLabel && significantLabel.name) {
- return labelName + '\nby ' + significantLabel.name;
+ return `${labelName}\nby ${significantLabel.name}`;
}
return labelName;
}
- _computeLabelClass(change, labelName) {
- const label = change.labels[labelName];
+ _computeLabelClass(change: ChangeInfo | undefined, labelName: string) {
+ const label: QuickLabelInfo | undefined = change?.labels?.[labelName];
// Mimic a Set.
- const classes = {
+ // TODO(TS): replace with `u_green` to remove the quotes and brackets
+ const classes: {
+ cell: boolean;
+ label: boolean;
+ ['u-green']?: boolean;
+ ['u-monospace']?: boolean;
+ ['u-red']?: boolean;
+ ['u-gray-background']?: boolean;
+ } = {
cell: true,
label: true,
};
@@ -144,10 +161,10 @@
if (label.approved) {
classes['u-green'] = true;
}
- if (label.value == 1) {
+ if (label.value === 1) {
classes['u-monospace'] = true;
classes['u-green'] = true;
- } else if (label.value == -1) {
+ } else if (label.value === -1) {
classes['u-monospace'] = true;
classes['u-red'] = true;
}
@@ -157,40 +174,52 @@
} else {
classes['u-gray-background'] = true;
}
- return Object.keys(classes).sort()
- .join(' ');
+ return Object.keys(classes).sort().join(' ');
}
- _computeLabelValue(change, labelName) {
- const label = change.labels[labelName];
- if (!label) { return ''; }
+ _computeLabelValue(change: ChangeInfo | undefined, labelName: string) {
+ const label: QuickLabelInfo | undefined = change?.labels?.[labelName];
+ if (!label) {
+ return '';
+ }
if (label.approved) {
return '✓';
}
if (label.rejected) {
return '✕';
}
- if (label.value > 0) {
- return '+' + label.value;
+ if (label.value && label.value > 0) {
+ return `+${label.value}`;
}
- if (label.value < 0) {
+ if (label.value && label.value < 0) {
return label.value;
}
return '';
}
- _computeRepoUrl(change) {
- return GerritNav.getUrlForProjectChanges(change.project, true,
- change.internalHost);
+ _computeRepoUrl(change?: ChangeInfo) {
+ if (!change) return '';
+ return GerritNav.getUrlForProjectChanges(
+ change.project,
+ true,
+ change.internalHost
+ );
}
- _computeRepoBranchURL(change) {
- return GerritNav.getUrlForBranch(change.branch, change.project, null,
- change.internalHost);
+ _computeRepoBranchURL(change?: ChangeInfo) {
+ if (!change) return '';
+ return GerritNav.getUrlForBranch(
+ change.branch,
+ change.project,
+ undefined,
+ change.internalHost
+ );
}
- _computeTopicURL(change) {
- if (!change.topic) { return ''; }
+ _computeTopicURL(change?: ChangeInfo) {
+ if (!change?.topic) {
+ return '';
+ }
return GerritNav.getUrlForTopic(change.topic, change.internalHost);
}
@@ -198,42 +227,48 @@
* Computes the display string for the project column. If there is a host
* specified in the change detail, the string will be prefixed with it.
*
- * @param {!Object} change
- * @param {string=} truncate whether or not the project name should be
- * truncated. If this value is truthy, the name will be truncated.
- * @return {string}
+ * @param truncate whether or not the project name should be
+ * truncated. If this value is truthy, the name will be truncated.
*/
- _computeRepoDisplay(change, truncate) {
- if (!change || !change.project) { return ''; }
+ _computeRepoDisplay(change: ChangeInfo | undefined, truncate: boolean) {
+ if (!change?.project) {
+ return '';
+ }
let str = '';
- if (change.internalHost) { str += change.internalHost + '/'; }
+ if (change.internalHost) {
+ str += change.internalHost + '/';
+ }
str += truncate ? truncatePath(change.project, 2) : change.project;
return str;
}
- _computeSizeTooltip(change) {
- if (change.insertions + change.deletions === 0 ||
- isNaN(change.insertions + change.deletions)) {
+ _computeSizeTooltip(change?: ChangeInfo) {
+ if (
+ !change ||
+ change.insertions + change.deletions === 0 ||
+ isNaN(change.insertions + change.deletions)
+ ) {
return 'Size unknown';
} else {
return `added ${change.insertions}, removed ${change.deletions} lines`;
}
}
- _hasAttention(account) {
+ _hasAttention(account: AccountInfo) {
if (!this.change || !this.change.attention_set) return false;
- return this.change.attention_set.hasOwnProperty(account._account_id);
+ return hasOwnProperty(this.change.attention_set, account._account_id);
}
/**
* Computes the array of all reviewers with sorting the reviewers in the
* attention set before others, and the current user first.
*/
- _computeReviewers(change) {
- if (!change || !change.reviewers || !change.reviewers.REVIEWER) return [];
- const reviewers = [...change.reviewers.REVIEWER].filter(r =>
- (!change.owner || change.owner._account_id !== r._account_id) &&
- !isServiceUser(r)
+ _computeReviewers(change?: ChangeInfo) {
+ if (!change?.reviewers || !change?.reviewers.REVIEWER) return [];
+ const reviewers = [...change.reviewers.REVIEWER].filter(
+ r =>
+ (!change.owner || change.owner._account_id !== r._account_id) &&
+ !isServiceUser(r)
);
reviewers.sort((r1, r2) => {
if (this.account) {
@@ -247,26 +282,29 @@
return reviewers;
}
- _computePrimaryReviewers(change) {
+ _computePrimaryReviewers(change?: ChangeInfo) {
return this._computeReviewers(change).slice(0, PRIMARY_REVIEWERS_COUNT);
}
- _computeAdditionalReviewers(change) {
+ _computeAdditionalReviewers(change?: ChangeInfo) {
return this._computeReviewers(change).slice(PRIMARY_REVIEWERS_COUNT);
}
- _computeAdditionalReviewersCount(change) {
+ _computeAdditionalReviewersCount(change?: ChangeInfo) {
return this._computeAdditionalReviewers(change).length;
}
- _computeAdditionalReviewersTitle(change, config) {
+ _computeAdditionalReviewersTitle(
+ change: ChangeInfo | undefined,
+ config: ServerInfo
+ ) {
if (!change || !config) return '';
return this._computeAdditionalReviewers(change)
- .map(user => getDisplayName(config, user, true))
- .join(', ');
+ .map(user => getDisplayName(config, user, true))
+ .join(', ');
}
- _computeComments(unresolved_comment_count) {
+ _computeComments(unresolved_comment_count?: number) {
if (!unresolved_comment_count || unresolved_comment_count < 1) return '';
return `${unresolved_comment_count} unresolved`;
}
@@ -275,7 +313,8 @@
* TShirt sizing is based on the following paper:
* http://dirkriehle.com/wp-content/uploads/2008/09/hicss-42-csdistr-final-web.pdf
*/
- _computeChangeSize(change) {
+ _computeChangeSize(change?: ChangeInfo) {
+ if (!change) return null;
const delta = change.insertions + change.deletions;
if (isNaN(delta) || delta === 0) {
return null; // Unknown
@@ -294,22 +333,24 @@
}
toggleReviewed() {
- const newVal = !this.change.reviewed;
+ const newVal = !this.change?.reviewed;
this.set('change.reviewed', newVal);
- this.dispatchEvent(new CustomEvent('toggle-reviewed', {
- bubbles: true,
- composed: true,
- detail: {change: this.change, reviewed: newVal},
- }));
+ this.dispatchEvent(
+ new CustomEvent('toggle-reviewed', {
+ bubbles: true,
+ composed: true,
+ detail: {change: this.change, reviewed: newVal},
+ })
+ );
}
- _handleChangeClick(e) {
+ _handleChangeClick() {
// Don't prevent the default and neither stop bubbling. We just want to
// report the click, but then let the browser handle the click on the link.
const selfId = (this.account && this.account._account_id) || -1;
- const ownerId = (this.change && this.change.owner
- && this.change.owner._account_id) || -1;
+ const ownerId =
+ (this.change && this.change.owner && this.change.owner._account_id) || -1;
this.reporting.reportInteraction('change-row-clicked', {
section: this.sectionName,
@@ -318,4 +359,8 @@
}
}
-customElements.define(GrChangeListItem.is, GrChangeListItem);
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-change-list-item': GrChangeListItem;
+ }
+}
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.js
index 6d51310..1970928 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.js
@@ -278,7 +278,7 @@
assert.deepEqual(GerritNav.getUrlForProjectChanges.lastCall.args,
[change.project, true, change.internalHost]);
assert.deepEqual(GerritNav.getUrlForBranch.lastCall.args,
- [change.branch, change.project, null, change.internalHost]);
+ [change.branch, change.project, undefined, change.internalHost]);
assert.deepEqual(GerritNav.getUrlForTopic.lastCall.args,
[change.topic, change.internalHost]);
});
diff --git a/polygerrit-ui/app/utils/change-util.ts b/polygerrit-ui/app/utils/change-util.ts
index 298ae9d..de43884c 100644
--- a/polygerrit-ui/app/utils/change-util.ts
+++ b/polygerrit-ui/app/utils/change-util.ts
@@ -16,16 +16,7 @@
*/
import {getBaseUrl} from './url-util';
import {ChangeStatus} from '../constants/constants';
-import {LegacyChangeId, PatchSetNum} from '../types/common';
-
-// This can be wrong! See WARNING above
-interface Change {
- status: string; // This can be wrong! See WARNING above
- mergeable: boolean; // This can be wrong! See WARNING above
- work_in_progress: boolean; // This can be wrong! See WARNING above
- is_private: boolean; // This can be wrong! See WARNING above
- submittable: boolean; // This can be wrong! See WARNING above
-}
+import {LegacyChangeId, PatchSetNum, ChangeInfo} from '../types/common';
// This can be wrong! See WARNING above
interface ChangeStatusesOptions {
@@ -132,12 +123,12 @@
return `${getBaseUrl()}/c/${changeNum}`;
}
-export function changeIsOpen(change?: Change) {
+export function changeIsOpen(change?: ChangeInfo) {
return change?.status === ChangeStatus.NEW;
}
export function changeStatuses(
- change: Change,
+ change: ChangeInfo,
opt_options?: ChangeStatusesOptions
) {
const states = [];
@@ -175,6 +166,6 @@
return states;
}
-export function changeStatusString(change: Change) {
+export function changeStatusString(change: ChangeInfo) {
return changeStatuses(change).join(', ');
}