commit 8814de118cb7e6d6bc1548398dc64dbba8f16a66 Author: Dmitrii Filippov Date: Sat Oct 10 16:31:21 2020 +0200 Convert files to typescript The change converts the following files to typescript: * elements/change-list/gr-change-list-view/gr-change-list-view.ts Change-Id: I002d430831f586c7c0e1d73c371e456fb989edcc 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 fee5247..b5d2d53 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 @@ -68,6 +68,11 @@ export enum LabelCategory { REJECTED = 'REJECTED', } +export interface ChangeListToggleReviewedDetail { + change: ChangeInfo; + reviewed: boolean; +} + // How many reviewers should be shown with an account-label? const PRIMARY_REVIEWERS_COUNT = 2; @@ -393,13 +398,18 @@ export class GrChangeListItem extends ChangeTableMixin( } toggleReviewed() { + if (!this.change) return; const newVal = !this.change?.reviewed; this.set('change.reviewed', newVal); + const detail: ChangeListToggleReviewedDetail = { + change: this.change, + reviewed: newVal, + }; this.dispatchEvent( new CustomEvent('toggle-reviewed', { bubbles: true, composed: true, - detail: {change: this.change, reviewed: newVal}, + detail, }) ); } diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts index b6bc03c..63bbaee 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts +++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts @@ -15,18 +15,34 @@ * limitations under the License. */ -import '../../shared/gr-icons/gr-icons.js'; -import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js'; -import '../gr-change-list/gr-change-list.js'; -import '../gr-repo-header/gr-repo-header.js'; -import '../gr-user-header/gr-user-header.js'; -import '../../../styles/shared-styles.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-view_html.js'; -import {page} from '../../../utils/page-wrapper-utils.js'; -import {GerritNav} from '../../core/gr-navigation/gr-navigation.js'; +import '../../shared/gr-icons/gr-icons'; +import '../../shared/gr-rest-api-interface/gr-rest-api-interface'; +import '../gr-change-list/gr-change-list'; +import '../gr-repo-header/gr-repo-header'; +import '../gr-user-header/gr-user-header'; +import '../../../styles/shared-styles'; +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-view_html'; +import {page} from '../../../utils/page-wrapper-utils'; +import {GerritNav, GerritView} from '../../core/gr-navigation/gr-navigation'; +import {customElement, property} from '@polymer/decorators'; +import {AppElementParams} from '../../gr-app-types'; +import { + AccountDetailInfo, + AccountId, + ChangeId, + ChangeInfo, + EmailAddress, + PatchRange, + PreferencesInput, +} from '../../../types/common'; +import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api'; +import {ChangeListToggleReviewedDetail} from '../gr-change-list-item/gr-change-list-item'; +import {ChangeStarToggleStarDetail} from '../../shared/gr-change-star/gr-change-star'; +import {hasOwnProperty} from '../../../utils/common-util'; +import {DiffViewMode} from '../../../constants/constants'; const LookupQueryPatterns = { CHANGE_ID: /^\s*i?[0-9a-f]{7,40}\s*$/i, @@ -36,118 +52,86 @@ const LookupQueryPatterns = { const USER_QUERY_PATTERN = /^owner:\s?("[^"]+"|[^ ]+)$/; -const REPO_QUERY_PATTERN = - /^project:\s?("[^"]+"|[^ ]+)(\sstatus\s?:(open|"open"))?$/; +const REPO_QUERY_PATTERN = /^project:\s?("[^"]+"|[^ ]+)(\sstatus\s?:(open|"open"))?$/; const LIMIT_OPERATOR_PATTERN = /\blimit:(\d+)/i; -/** - * @extends PolymerElement - */ -class GrChangeListView extends GestureEventListeners( - LegacyElementMixin( - PolymerElement)) { - static get template() { return htmlTemplate; } +export interface ChangeListViewState { + changeNum?: ChangeId; + patchRange?: PatchRange; + selectedFileIndex?: number; + showReplyDialog?: boolean; + showDownloadDialog?: boolean; + diffMode?: DiffViewMode; + numFilesShown?: number; + scrollTop?: number; + query?: string; + offset?: number; +} + +export interface GrChangeListView { + $: { + restAPI: RestApiService & Element; + prevArrow: HTMLAnchorElement; + nextArrow: HTMLAnchorElement; + }; +} + +@customElement('gr-change-list-view') +export class GrChangeListView extends GestureEventListeners( + LegacyElementMixin(PolymerElement) +) { + static get template() { + return htmlTemplate; + } - static get is() { return 'gr-change-list-view'; } /** * Fired when the title of the page should change. * * @event title-change */ - static get properties() { - return { - /** - * URL params passed from the router. - */ - params: { - type: Object, - observer: '_paramsChanged', - }, - - /** - * True when user is logged in. - */ - _loggedIn: { - type: Boolean, - computed: '_computeLoggedIn(account)', - }, - - account: { - type: Object, - value: null, - }, - - /** - * State persisted across restamps of the element. - * - * Need sub-property declaration since it is used in template before - * assignment. - * - * @type {{ selectedChangeIndex: (number|undefined) }} - * - */ - viewState: { - type: Object, - notify: true, - value() { return {}; }, - }, - - preferences: Object, - - _changesPerPage: Number, - - /** - * Currently active query. - */ - _query: { - type: String, - value: '', - }, - - /** - * Offset of currently visible query results. - */ - _offset: Number, - - /** - * Change objects loaded from the server. - */ - _changes: { - type: Array, - observer: '_changesChanged', - }, - - /** - * For showing a "loading..." string during ajax requests. - */ - _loading: { - type: Boolean, - value: true, - }, - - /** @type {?string} */ - _userId: { - type: String, - value: null, - }, - - /** @type {?string} */ - _repo: { - type: String, - value: null, - }, - }; - } + @property({type: Object, observer: '_paramsChanged'}) + params?: AppElementParams; + + @property({type: Boolean, computed: '_computeLoggedIn(account)'}) + _loggedIn?: boolean; + + @property({type: Object}) + account: AccountDetailInfo | null = null; + + @property({type: Object, notify: true}) + viewState: ChangeListViewState = {}; + + @property({type: Object}) + preferences?: PreferencesInput; + + @property({type: Number}) + _changesPerPage?: number; + + @property({type: String}) + _query = ''; + + @property({type: Number}) + _offset?: number; + + @property({type: Array, observer: '_changesChanged'}) + _changes?: ChangeInfo[]; + + @property({type: Boolean}) + _loading = true; + + @property({type: String}) + _userId: AccountId | EmailAddress | null = null; + + @property({type: String}) + _repo: string | null = null; /** @override */ created() { super.created(); - this.addEventListener('next-page', - () => this._handleNextPage()); - this.addEventListener('previous-page', - () => this._handlePreviousPage()); + this.addEventListener('next-page', () => this._handleNextPage()); + this.addEventListener('previous-page', () => this._handlePreviousPage()); } /** @override */ @@ -156,14 +140,17 @@ class GrChangeListView extends GestureEventListeners( this._loadPreferences(); } - _paramsChanged(value) { - if (value.view !== GerritNav.View.SEARCH) { return; } + _paramsChanged(value: AppElementParams) { + if (value.view !== GerritView.SEARCH) return; this._loading = true; this._query = value.query; - this._offset = value.offset || 0; - if (this.viewState.query != this._query || - this.viewState.offset != this._offset) { + const offset = Number(value.offset); + this._offset = isNaN(offset) ? 0 : offset; + if ( + this.viewState.query !== this._query || + this.viewState.offset !== this._offset + ) { this.set('viewState.selectedChangeIndex', 0); this.set('viewState.query', this._query); this.set('viewState.offset', this._offset); @@ -171,38 +158,56 @@ class GrChangeListView extends GestureEventListeners( // NOTE: This method may be called before attachment. Fire title-change // in an async so that attachment to the DOM can take place first. - this.async(() => this.dispatchEvent(new CustomEvent('title-change', { - detail: {title: this._query}, - composed: true, bubbles: true, - }))); - - this._getPreferences() - .then(prefs => { - this._changesPerPage = prefs.changes_per_page; - return this._getChanges(); + this.async(() => + this.dispatchEvent( + new CustomEvent('title-change', { + detail: {title: this._query}, + composed: true, + bubbles: true, }) - .then(changes => { - changes = changes || []; - if (this._query && changes.length === 1) { - for (const query in LookupQueryPatterns) { - if (LookupQueryPatterns.hasOwnProperty(query) && - this._query.match(LookupQueryPatterns[query])) { - // "Back"/"Forward" buttons work correctly only with - // opt_redirect options - GerritNav.navigateToChange(changes[0], null, null, null, true); - return; - } + ) + ); + + this.$.restAPI + .getPreferences() + .then(prefs => { + if (!prefs) { + throw new Error('getPreferences returned undefined'); + } + this._changesPerPage = prefs.changes_per_page; + return this._getChanges(); + }) + .then(changes => { + changes = changes || []; + if (this._query && changes.length === 1) { + let query: keyof typeof LookupQueryPatterns; + for (query in LookupQueryPatterns) { + if ( + hasOwnProperty(LookupQueryPatterns, query) && + this._query.match(LookupQueryPatterns[query]) + ) { + // "Back"/"Forward" buttons work correctly only with + // opt_redirect options + GerritNav.navigateToChange( + changes[0], + undefined, + undefined, + undefined, + true + ); + return; } } - this._changes = changes; - this._loading = false; - }); + } + this._changes = changes; + this._loading = false; + }); } _loadPreferences() { return this.$.restAPI.getLoggedIn().then(loggedIn => { if (loggedIn) { - this._getPreferences().then(preferences => { + this.$.restAPI.getPreferences().then(preferences => { this.preferences = preferences; }); } else { @@ -212,15 +217,14 @@ class GrChangeListView extends GestureEventListeners( } _getChanges() { - return this.$.restAPI.getChanges(this._changesPerPage, this._query, - this._offset); - } - - _getPreferences() { - return this.$.restAPI.getPreferences(); + return this.$.restAPI.getChanges( + this._changesPerPage, + this._query, + this._offset + ); } - _limitFor(query, defaultLimit) { + _limitFor(query: string, defaultLimit: number) { const match = query.match(LIMIT_OPERATOR_PATTERN); if (!match) { return defaultLimit; @@ -228,40 +232,46 @@ class GrChangeListView extends GestureEventListeners( return parseInt(match[1], 10); } - _computeNavLink(query, offset, direction, changesPerPage) { - // Offset could be a string when passed from the router. - offset = +(offset || 0); + _computeNavLink( + query: string, + offset: number | undefined, + direction: number, + changesPerPage: number + ) { + offset = offset ?? 0; const limit = this._limitFor(query, changesPerPage); - const newOffset = Math.max(0, offset + (limit * direction)); + const newOffset = Math.max(0, offset + limit * direction); return GerritNav.getUrlForSearchQuery(query, newOffset); } - _computePrevArrowClass(offset) { + _computePrevArrowClass(offset?: number) { return offset === 0 ? 'hide' : ''; } - _computeNextArrowClass(changes) { - const more = changes.length && changes[changes.length - 1]._more_changes; + _computeNextArrowClass(changes?: ChangeInfo[]) { + const more = changes?.length && changes[changes.length - 1]._more_changes; return more ? '' : 'hide'; } - _computeNavClass(loading) { + _computeNavClass(loading?: boolean) { return loading || !this._changes || !this._changes.length ? 'hide' : ''; } _handleNextPage() { - if (this.$.nextArrow.hidden) { return; } - page.show(this._computeNavLink( - this._query, this._offset, 1, this._changesPerPage)); + if (this.$.nextArrow.hidden || !this._changesPerPage) return; + page.show( + this._computeNavLink(this._query, this._offset, 1, this._changesPerPage) + ); } _handlePreviousPage() { - if (this.$.prevArrow.hidden) { return; } - page.show(this._computeNavLink( - this._query, this._offset, -1, this._changesPerPage)); + if (this.$.prevArrow.hidden || !this._changesPerPage) return; + page.show( + this._computeNavLink(this._query, this._offset, -1, this._changesPerPage) + ); } - _changesChanged(changes) { + _changesChanged(changes?: ChangeInfo[]) { this._userId = null; this._repo = null; if (!changes || !changes.length) { @@ -280,27 +290,33 @@ class GrChangeListView extends GestureEventListeners( } } - _computeHeaderClass(id) { + _computeHeaderClass(id?: string) { return id ? '' : 'hide'; } - _computePage(offset, changesPerPage) { + _computePage(offset?: number, changesPerPage?: number) { + if (offset === undefined || changesPerPage === undefined) return; return offset / changesPerPage + 1; } - _computeLoggedIn(account) { + _computeLoggedIn(account?: AccountDetailInfo) { return !!(account && Object.keys(account).length > 0); } - _handleToggleStar(e) { - this.$.restAPI.saveChangeStarred(e.detail.change._number, - e.detail.starred); + _handleToggleStar(e: CustomEvent) { + this.$.restAPI.saveChangeStarred(e.detail.change._number, e.detail.starred); } - _handleToggleReviewed(e) { - this.$.restAPI.saveChangeReviewed(e.detail.change._number, - e.detail.reviewed); + _handleToggleReviewed(e: CustomEvent) { + this.$.restAPI.saveChangeReviewed( + e.detail.change._number, + e.detail.reviewed + ); } } -customElements.define(GrChangeListView.is, GrChangeListView); +declare global { + interface HTMLElementTagNameMap { + 'gr-change-list-view': GrChangeListView; + } +} diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js index 4c52ce9..af3acd8 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js +++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js @@ -109,6 +109,7 @@ suite('gr-change-list-view tests', () => { test('_handleNextPage', () => { const showStub = sinon.stub(page, 'show'); + element._changesPerPage = 10; element.$.nextArrow.hidden = true; element._handleNextPage(); assert.isFalse(showStub.called); @@ -119,6 +120,7 @@ suite('gr-change-list-view tests', () => { test('_handlePreviousPage', () => { const showStub = sinon.stub(page, 'show'); + element._changesPerPage = 10; element.$.prevArrow.hidden = true; element._handlePreviousPage(); assert.isFalse(showStub.called); diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts index 0aa077e..1ecaf7f 100644 --- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts +++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts @@ -30,6 +30,11 @@ declare global { } } +export interface ChangeStarToggleStarDetail { + change: ChangeInfo; + starred: boolean; +} + @customElement('gr-change-star') export class GrChangeStar extends KeyboardShortcutMixin( GestureEventListeners(LegacyElementMixin(PolymerElement)) @@ -69,11 +74,15 @@ export class GrChangeStar extends KeyboardShortcutMixin( } const newVal = !this.change.starred; this.set('change.starred', newVal); + const detail: ChangeStarToggleStarDetail = { + change: this.change, + starred: newVal, + }; this.dispatchEvent( new CustomEvent('toggle-star', { bubbles: true, composed: true, - detail: {change: this.change, starred: newVal}, + detail, }) ); } diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts index f4acf7a..916e5b1 100644 --- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts +++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts @@ -2424,7 +2424,10 @@ export class GrRestApiInterface }); } - saveChangeStarred(changeNum: NumericChangeId, starred: boolean) { + saveChangeStarred( + changeNum: NumericChangeId, + starred: boolean + ): Promise { // Some servers may require the project name to be provided // alongside the change number, so resolve the project name // first. diff --git a/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts b/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts index 0b0ad9e..74a37db 100644 --- a/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts +++ b/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts @@ -777,4 +777,14 @@ export interface RestApiService { email: string, errFn?: ErrorCallback ): Promise; + + saveChangeReviewed( + changeNum: NumericChangeId, + reviewed: boolean + ): Promise; + + saveChangeStarred( + changeNum: NumericChangeId, + starred: boolean + ): Promise; }