commit d883c79dcac6bd7086f64f9043574bb630267cd2 Author: Dmitrii Filippov Date: Fri Oct 9 16:10:51 2020 +0200 Convert files to typescript The change converts the following files to typescript: * elements/settings/gr-settings-view/gr-settings-view.ts Change-Id: I758f919418b98d077efeb2ea42d23908e064e216 diff --git a/polygerrit-ui/app/constants/constants.ts b/polygerrit-ui/app/constants/constants.ts index 2db076f..b326001 100644 --- a/polygerrit-ui/app/constants/constants.ts +++ b/polygerrit-ui/app/constants/constants.ts @@ -296,6 +296,16 @@ export enum EmailStrategy { } /** + * The type of email format to use. + * Doesn't mentioned in doc, but exists in Java class GeneralPreferencesInfo. + */ + +export enum EmailFormat { + PLAINTEXT = 'PLAINTEXT', + HTML_PLAINTEXT = 'HTML_PLAINTEXT', +} + +/** * The base which should be pre-selected in the 'Diff Against' drop-down list when the change screen is opened for a merge commit * https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#preferences-input */ diff --git a/polygerrit-ui/app/elements/gr-app-types.ts b/polygerrit-ui/app/elements/gr-app-types.ts index ef382ad..2af925e 100644 --- a/polygerrit-ui/app/elements/gr-app-types.ts +++ b/polygerrit-ui/app/elements/gr-app-types.ts @@ -87,6 +87,12 @@ export interface AppElementAgreementParam { } export interface AppElementJustRegisteredParams { + // We use params.view === ... as a type guard. + // The view?: never tells to the compiler that + // AppElementJustRegisteredParams can't have view property. + // Otherwise, the compiler reports an error when the code tries to use + // the property 'view' of AppElementParams. + view?: never; justRegistered: true; } diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts index 06d9183..cd0d7b8 100644 --- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts +++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts @@ -14,40 +14,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import '@polymer/iron-input/iron-input.js'; -import '@polymer/paper-toggle-button/paper-toggle-button.js'; -import '../../../styles/gr-form-styles.js'; -import '../../../styles/gr-menu-page-styles.js'; -import '../../../styles/gr-page-nav-styles.js'; -import '../../../styles/shared-styles.js'; -import {applyTheme as applyDarkTheme, removeTheme as removeDarkTheme} from '../../../styles/themes/dark-theme.js'; -import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js'; -import '../gr-change-table-editor/gr-change-table-editor.js'; -import '../../shared/gr-button/gr-button.js'; -import '../../shared/gr-date-formatter/gr-date-formatter.js'; -import '../../shared/gr-diff-preferences/gr-diff-preferences.js'; -import '../../shared/gr-page-nav/gr-page-nav.js'; -import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js'; -import '../../shared/gr-select/gr-select.js'; -import '../gr-account-info/gr-account-info.js'; -import '../gr-agreements-list/gr-agreements-list.js'; -import '../gr-edit-preferences/gr-edit-preferences.js'; -import '../gr-email-editor/gr-email-editor.js'; -import '../gr-gpg-editor/gr-gpg-editor.js'; -import '../gr-group-list/gr-group-list.js'; -import '../gr-http-password/gr-http-password.js'; -import '../gr-identities/gr-identities.js'; -import '../gr-menu-editor/gr-menu-editor.js'; -import '../gr-ssh-editor/gr-ssh-editor.js'; -import '../gr-watched-projects-editor/gr-watched-projects-editor.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-settings-view_html.js'; -import {getDocsBaseUrl} from '../../../utils/url-util.js'; -import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin.js'; - -const PREFS_SECTION_FIELDS = [ +import '@polymer/iron-input/iron-input'; +import '@polymer/paper-toggle-button/paper-toggle-button'; +import '../../../styles/gr-form-styles'; +import '../../../styles/gr-menu-page-styles'; +import '../../../styles/gr-page-nav-styles'; +import '../../../styles/shared-styles'; +import { + applyTheme as applyDarkTheme, + removeTheme as removeDarkTheme, +} from '../../../styles/themes/dark-theme'; +import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator'; +import '../gr-change-table-editor/gr-change-table-editor'; +import '../../shared/gr-button/gr-button'; +import '../../shared/gr-date-formatter/gr-date-formatter'; +import '../../shared/gr-diff-preferences/gr-diff-preferences'; +import '../../shared/gr-page-nav/gr-page-nav'; +import '../../shared/gr-rest-api-interface/gr-rest-api-interface'; +import '../../shared/gr-select/gr-select'; +import '../gr-account-info/gr-account-info'; +import '../gr-agreements-list/gr-agreements-list'; +import '../gr-edit-preferences/gr-edit-preferences'; +import '../gr-email-editor/gr-email-editor'; +import '../gr-gpg-editor/gr-gpg-editor'; +import '../gr-group-list/gr-group-list'; +import '../gr-http-password/gr-http-password'; +import '../gr-identities/gr-identities'; +import '../gr-menu-editor/gr-menu-editor'; +import '../gr-ssh-editor/gr-ssh-editor'; +import '../gr-watched-projects-editor/gr-watched-projects-editor'; +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-settings-view_html'; +import {getDocsBaseUrl} from '../../../utils/url-util'; +import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin'; +import {customElement, property, observe} from '@polymer/decorators'; +import {AppElementParams} from '../../gr-app-types'; +import {GrAccountInfo} from '../gr-account-info/gr-account-info'; +import {GrWatchedProjectsEditor} from '../gr-watched-projects-editor/gr-watched-projects-editor'; +import {GrGroupList} from '../gr-group-list/gr-group-list'; +import {GrIdentities} from '../gr-identities/gr-identities'; +import {GrEditPreferences} from '../gr-edit-preferences/gr-edit-preferences'; +import {GrDiffPreferences} from '../../shared/gr-diff-preferences/gr-diff-preferences'; +import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api'; +import { + PreferencesInput, + ServerInfo, + TopMenuItemInfo, +} from '../../../types/common'; +import {GrSshEditor} from '../gr-ssh-editor/gr-ssh-editor'; +import {GrGpgEditor} from '../gr-gpg-editor/gr-gpg-editor'; +import {GerritView} from '../../core/gr-navigation/gr-navigation'; +import {GrEmailEditor} from '../gr-email-editor/gr-email-editor'; +import {CustomKeyboardEvent} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin'; + +const PREFS_SECTION_FIELDS: Array = [ 'changes_per_page', 'date_format', 'time_format', @@ -62,26 +84,49 @@ const PREFS_SECTION_FIELDS = [ 'relative_date_in_change_table', ]; -const GERRIT_DOCS_BASE_URL = 'https://gerrit-review.googlesource.com/' + - 'Documentation'; +const GERRIT_DOCS_BASE_URL = + 'https://gerrit-review.googlesource.com/' + 'Documentation'; const GERRIT_DOCS_FILTER_PATH = '/user-notify.html'; const ABSOLUTE_URL_PATTERN = /^https?:/; const TRAILING_SLASH_PATTERN = /\/$/; -const HTTP_AUTH = [ - 'HTTP', - 'HTTP_LDAP', -]; +const HTTP_AUTH = ['HTTP', 'HTTP_LDAP']; -/** - * @extends PolymerElement - */ -class GrSettingsView extends ChangeTableMixin(GestureEventListeners( - LegacyElementMixin( - PolymerElement))) { - static get template() { return htmlTemplate; } +enum CopyPrefsDirection { + PrefsToLocalPrefs, + LocalPrefsToPrefs, +} + +type LocalMenuItemInfo = Omit; + +export interface GrSettingsView { + $: { + restAPI: RestApiService & Element; + accountInfo: GrAccountInfo; + watchedProjectsEditor: GrWatchedProjectsEditor; + groupList: GrGroupList; + identities: GrIdentities; + editPrefs: GrEditPreferences; + diffPrefs: GrDiffPreferences; + sshEditor: GrSshEditor; + gpgEditor: GrGpgEditor; + emailEditor: GrEmailEditor; + insertSignedOff: HTMLInputElement; + workInProgressByDefault: HTMLInputElement; + showSizeBarsInFileList: HTMLInputElement; + publishCommentsOnPush: HTMLInputElement; + relativeDateInChangeTable: HTMLInputElement; + }; +} + +@customElement('gr-settings-view') +export class GrSettingsView extends ChangeTableMixin( + GestureEventListeners(LegacyElementMixin(PolymerElement)) +) { + static get template() { + return htmlTemplate; + } - static get is() { return 'gr-settings-view'; } /** * Fired when the title of the page should change. * @@ -94,99 +139,79 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( * @event show-alert */ - static get properties() { - return { - prefs: { - type: Object, - value() { return {}; }, - }, - params: { - type: Object, - value() { return {}; }, - }, - _accountInfoChanged: Boolean, - _changeTableColumnsNotDisplayed: Array, - /** @type {?} */ - _localPrefs: { - type: Object, - value() { return {}; }, - }, - _localChangeTableColumns: { - type: Array, - value() { return []; }, - }, - _localMenu: { - type: Array, - value() { return []; }, - }, - _loading: { - type: Boolean, - value: true, - }, - _changeTableChanged: { - type: Boolean, - value: false, - }, - _prefsChanged: { - type: Boolean, - value: false, - }, - /** @type {?} */ - _diffPrefsChanged: Boolean, - /** @type {?} */ - _editPrefsChanged: Boolean, - _menuChanged: { - type: Boolean, - value: false, - }, - _watchedProjectsChanged: { - type: Boolean, - value: false, - }, - _keysChanged: { - type: Boolean, - value: false, - }, - _gpgKeysChanged: { - type: Boolean, - value: false, - }, - _newEmail: String, - _addingEmail: { - type: Boolean, - value: false, - }, - _lastSentVerificationEmail: { - type: String, - value: null, - }, - /** @type {?} */ - _serverConfig: Object, - /** @type {?string} */ - _docsBaseUrl: String, - _emailsChanged: Boolean, - - /** - * For testing purposes. - */ - _loadingPromise: Object, - - _showNumber: Boolean, - - _isDark: { - type: Boolean, - value: false, - }, - }; - } - - static get observers() { - return [ - '_handlePrefsChanged(_localPrefs.*)', - '_handleMenuChanged(_localMenu.splices)', - '_handleChangeTableChanged(_localChangeTableColumns, _showNumber)', - ]; - } + @property({type: Object}) + prefs: PreferencesInput = {}; + + @property({type: Object}) + params?: AppElementParams; + + @property({type: Boolean}) + _accountInfoChanged?: boolean; + + @property({type: Array}) + _changeTableColumnsNotDisplayed?: string[]; + + @property({type: Object}) + _localPrefs: PreferencesInput = {}; + + @property({type: Array}) + _localChangeTableColumns: string[] = []; + + @property({type: Array}) + _localMenu: LocalMenuItemInfo[] = []; + + @property({type: Boolean}) + _loading = true; + + @property({type: Boolean}) + _changeTableChanged = false; + + @property({type: Boolean}) + _prefsChanged = false; + + @property({type: Boolean}) + _diffPrefsChanged?: boolean; + + @property({type: Boolean}) + _editPrefsChanged?: boolean; + + @property({type: Boolean}) + _menuChanged = false; + + @property({type: Boolean}) + _watchedProjectsChanged = false; + + @property({type: Boolean}) + _keysChanged = false; + + @property({type: Boolean}) + _gpgKeysChanged = false; + + @property({type: String}) + _newEmail?: string; + + @property({type: Boolean}) + _addingEmail = false; + + @property({type: String}) + _lastSentVerificationEmail?: string | null = null; + + @property({type: Object}) + _serverConfig?: ServerInfo; + + @property({type: String}) + _docsBaseUrl?: string | null; + + @property({type: Boolean}) + _emailsChanged?: boolean; + + @property({type: Boolean}) + _showNumber?: boolean; + + @property({type: Boolean}) + _isDark = false; + + public _testOnly_loadingPromise?: Promise; /** @override */ attached() { @@ -194,14 +219,17 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( // Polymer 2: anchor tag won't work on shadow DOM // we need to manually calling scrollIntoView when hash changed this.listen(window, 'location-change', '_handleLocationChange'); - this.dispatchEvent(new CustomEvent('title-change', { - detail: {title: 'Settings'}, - composed: true, bubbles: true, - })); + this.dispatchEvent( + new CustomEvent('title-change', { + detail: {title: 'Settings'}, + composed: true, + bubbles: true, + }) + ); this._isDark = !!window.localStorage.getItem('dark-theme'); - const promises = [ + const promises: Array> = [ this.$.accountInfo.loadData(), this.$.watchedProjectsEditor.loadData(), this.$.groupList.loadData(), @@ -210,51 +238,70 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( this.$.diffPrefs.loadData(), ]; - promises.push(this.$.restAPI.getPreferences().then(prefs => { - this.prefs = prefs; - this._showNumber = !!prefs.legacycid_in_change_table; - this._copyPrefs('_localPrefs', 'prefs'); - this._cloneMenu(prefs.my); - this._cloneChangeTableColumns(); - })); - - promises.push(this.$.restAPI.getConfig().then(config => { - this._serverConfig = config; - const configPromises = []; - - if (this._serverConfig && this._serverConfig.sshd) { - configPromises.push(this.$.sshEditor.loadData()); - } - - if (this._serverConfig && + promises.push( + this.$.restAPI.getPreferences().then(prefs => { + if (!prefs) { + throw new Error('getPreferences returned undefined'); + } + this.prefs = prefs; + this._showNumber = !!prefs.legacycid_in_change_table; + this._copyPrefs(CopyPrefsDirection.PrefsToLocalPrefs); + this._cloneMenu(prefs.my); + this._cloneChangeTableColumns(prefs.change_table); + }) + ); + + promises.push( + this.$.restAPI.getConfig().then(config => { + this._serverConfig = config; + const configPromises: Array> = []; + + if (this._serverConfig && this._serverConfig.sshd) { + configPromises.push(this.$.sshEditor.loadData()); + } + + if ( + this._serverConfig && this._serverConfig.receive && - this._serverConfig.receive.enable_signed_push) { - configPromises.push(this.$.gpgEditor.loadData()); - } - - configPromises.push( - getDocsBaseUrl(config, this.$.restAPI) - .then(baseUrl => { this._docsBaseUrl = baseUrl; })); - - return Promise.all(configPromises); - })); - - if (this.params.emailToken) { - promises.push(this.$.restAPI.confirmEmail(this.params.emailToken).then( - message => { - if (message) { - this.dispatchEvent(new CustomEvent('show-alert', { + this._serverConfig.receive.enable_signed_push + ) { + configPromises.push(this.$.gpgEditor.loadData()); + } + + configPromises.push( + getDocsBaseUrl(config, this.$.restAPI).then(baseUrl => { + this._docsBaseUrl = baseUrl; + }) + ); + + return Promise.all(configPromises); + }) + ); + + if ( + this.params && + this.params.view === GerritView.SETTINGS && + this.params.emailToken + ) { + promises.push( + this.$.restAPI.confirmEmail(this.params.emailToken).then(message => { + if (message) { + this.dispatchEvent( + new CustomEvent('show-alert', { detail: {message}, - composed: true, bubbles: true, - })); - } - this.$.emailEditor.loadData(); - })); + composed: true, + bubbles: true, + }) + ); + } + this.$.emailEditor.loadData(); + }) + ); } else { promises.push(this.$.emailEditor.loadData()); } - this._loadingPromise = Promise.all(promises).then(() => { + this._testOnly_loadingPromise = Promise.all(promises).then(() => { this._loading = false; // Handle anchor tag for initial load @@ -262,7 +309,6 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( }); } - /** @override */ detached() { super.detached(); this.unlisten(window, 'location-change', '_handleLocationChange'); @@ -281,24 +327,29 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( } reloadAccountDetail() { - Promise.all([ - this.$.accountInfo.loadData(), - this.$.emailEditor.loadData(), - ]); + Promise.all([this.$.accountInfo.loadData(), this.$.emailEditor.loadData()]); } _isLoading() { return this._loading || this._loading === undefined; } - _copyPrefs(to, from) { + _copyPrefs(direction: CopyPrefsDirection) { + let to; + let from; + if (direction === CopyPrefsDirection.LocalPrefsToPrefs) { + from = this._localPrefs; + to = 'prefs'; + } else { + from = this.prefs; + to = '_localPrefs'; + } for (let i = 0; i < PREFS_SECTION_FIELDS.length; i++) { - this.set([to, PREFS_SECTION_FIELDS[i]], - this[from][PREFS_SECTION_FIELDS[i]]); + this.set([to, PREFS_SECTION_FIELDS[i]], from[PREFS_SECTION_FIELDS[i]]); } } - _cloneMenu(prefs) { + _cloneMenu(prefs: TopMenuItemInfo[]) { const menu = []; for (const item of prefs) { menu.push({ @@ -310,61 +361,73 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( this._localMenu = menu; } - _cloneChangeTableColumns() { - let columns = this.getVisibleColumns(this.prefs.change_table); + _cloneChangeTableColumns(changeTable: string[]) { + let columns = this.getVisibleColumns(changeTable); if (columns.length === 0) { columns = this.columnNames; this._changeTableColumnsNotDisplayed = []; } else { this._changeTableColumnsNotDisplayed = this.getComplementColumns( - this.prefs.change_table); + changeTable + ); } this._localChangeTableColumns = columns; } - _formatChangeTableColumns(changeTableArray) { - return changeTableArray.map(item => { - return {column: item}; - }); - } - + @observe('_localChangeTableColumns', '_showNumber') _handleChangeTableChanged() { - if (this._isLoading()) { return; } + if (this._isLoading()) { + return; + } this._changeTableChanged = true; } - _handlePrefsChanged(prefs) { - if (this._isLoading()) { return; } + @observe('_localPrefs.*') + _handlePrefsChanged() { + if (this._isLoading()) { + return; + } this._prefsChanged = true; } _handleRelativeDateInChangeTable() { - this.set('_localPrefs.relative_date_in_change_table', - this.$.relativeDateInChangeTable.checked); + this.set( + '_localPrefs.relative_date_in_change_table', + this.$.relativeDateInChangeTable.checked + ); } _handleShowSizeBarsInFileListChanged() { - this.set('_localPrefs.size_bar_in_change_table', - this.$.showSizeBarsInFileList.checked); + this.set( + '_localPrefs.size_bar_in_change_table', + this.$.showSizeBarsInFileList.checked + ); } _handlePublishCommentsOnPushChanged() { - this.set('_localPrefs.publish_comments_on_push', - this.$.publishCommentsOnPush.checked); + this.set( + '_localPrefs.publish_comments_on_push', + this.$.publishCommentsOnPush.checked + ); } _handleWorkInProgressByDefault() { - this.set('_localPrefs.work_in_progress_by_default', - this.$.workInProgressByDefault.checked); + this.set( + '_localPrefs.work_in_progress_by_default', + this.$.workInProgressByDefault.checked + ); } _handleInsertSignedOff() { this.set('_localPrefs.signed_off_by', this.$.insertSignedOff.checked); } + @observe('_localMenu.splices') _handleMenuChanged() { - if (this._isLoading()) { return; } + if (this._isLoading()) { + return; + } this._menuChanged = true; } @@ -373,7 +436,7 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( } _handleSavePreferences() { - this._copyPrefs('prefs', '_localPrefs'); + this._copyPrefs(CopyPrefsDirection.LocalPrefsToPrefs); return this.$.restAPI.savePreferences(this.prefs).then(() => { this._prefsChanged = false; @@ -383,7 +446,7 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( _handleSaveChangeTable() { this.set('prefs.change_table', this._localChangeTableColumns); this.set('prefs.legacycid_in_change_table', this._showNumber); - this._cloneChangeTableColumns(); + this._cloneChangeTableColumns(this._localChangeTableColumns); return this.$.restAPI.savePreferences(this.prefs).then(() => { this._changeTableChanged = false; }); @@ -399,7 +462,7 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( _handleSaveMenu() { this.set('prefs.my', this._localMenu); - this._cloneMenu(this.prefs.my); + this._cloneMenu(this._localMenu); return this.$.restAPI.savePreferences(this.prefs).then(() => { this._menuChanged = false; }); @@ -407,7 +470,7 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( _handleResetMenuButton() { return this.$.restAPI.getDefaultPreferences().then(data => { - if (data && data.my) { + if (data?.my) { this._cloneMenu(data.my); } }); @@ -417,7 +480,7 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( this.$.watchedProjectsEditor.save(); } - _computeHeaderClass(changed) { + _computeHeaderClass(changed?: boolean) { return changed ? 'edited' : ''; } @@ -425,37 +488,40 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( this.$.emailEditor.save(); } - _handleNewEmailKeydown(e) { - if (e.keyCode === 13) { // Enter + _handleNewEmailKeydown(e: CustomKeyboardEvent) { + if (e.keyCode === 13) { + // Enter e.stopPropagation(); this._handleAddEmailButton(); } } - _isNewEmailValid(newEmail) { - return newEmail && newEmail.includes('@'); + _isNewEmailValid(newEmail?: string): newEmail is string { + return !!newEmail && newEmail.includes('@'); } - _computeAddEmailButtonEnabled(newEmail, addingEmail) { + _computeAddEmailButtonEnabled(newEmail?: string, addingEmail?: boolean) { return this._isNewEmailValid(newEmail) && !addingEmail; } _handleAddEmailButton() { - if (!this._isNewEmailValid(this._newEmail)) { return; } + if (!this._isNewEmailValid(this._newEmail)) return; this._addingEmail = true; this.$.restAPI.addAccountEmail(this._newEmail).then(response => { this._addingEmail = false; // If it was unsuccessful. - if (response.status < 200 || response.status >= 300) { return; } + if (response.status < 200 || response.status >= 300) { + return; + } this._lastSentVerificationEmail = this._newEmail; this._newEmail = ''; }); } - _getFilterDocsLink(docsBaseUrl) { + _getFilterDocsLink(docsBaseUrl?: string) { let base = docsBaseUrl; if (!base || !ABSOLUTE_URL_PATTERN.test(base)) { base = GERRIT_DOCS_BASE_URL; @@ -476,20 +542,22 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( applyDarkTheme(); } this._isDark = !!window.localStorage.getItem('dark-theme'); - this.dispatchEvent(new CustomEvent('show-alert', { - detail: { - message: `Theme changed to ${this._isDark ? 'dark' : 'light'}.`, - }, - bubbles: true, - composed: true, - })); - } - - _showHttpAuth(config) { - if (config && config.auth && - config.auth.git_basic_auth_policy) { + this.dispatchEvent( + new CustomEvent('show-alert', { + detail: { + message: `Theme changed to ${this._isDark ? 'dark' : 'light'}.`, + }, + bubbles: true, + composed: true, + }) + ); + } + + _showHttpAuth(config?: ServerInfo) { + if (config && config.auth && config.auth.git_basic_auth_policy) { return HTTP_AUTH.includes( - config.auth.git_basic_auth_policy.toUpperCase()); + config.auth.git_basic_auth_policy.toUpperCase() + ); } return false; @@ -498,9 +566,13 @@ class GrSettingsView extends ChangeTableMixin(GestureEventListeners( /** * Work around a issue on iOS when clicking turns into double tap */ - _onTapDarkToggle(e) { + _onTapDarkToggle(e: Event) { e.preventDefault(); } } -customElements.define(GrSettingsView.is, GrSettingsView); +declare global { + interface HTMLElementTagNameMap { + 'gr-settings-view': GrSettingsView; + } +} diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js index 1929f4e..0535e15 100644 --- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js +++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js @@ -19,6 +19,7 @@ import '../../../test/common-test-setup-karma.js'; import {getComputedStyleValue} from '../../../utils/dom-util.js'; import './gr-settings-view.js'; import {flush} from '@polymer/polymer/lib/legacy/polymer.dom.js'; +import {GerritView} from '../../core/gr-navigation/gr-navigation.js'; const basicFixture = fixtureFromElement('gr-settings-view'); const blankFixture = fixtureFromElement('div'); @@ -95,7 +96,7 @@ suite('gr-settings-view tests', () => { element = basicFixture.instantiate(); // Allow the element to render. - element._loadingPromise.then(done); + element._testOnly_loadingPromise.then(done); }); test('theme changing', () => { @@ -485,7 +486,7 @@ suite('gr-settings-view tests', () => { .callsFake( () => new Promise( resolve => { resolveConfirm = resolve; })); - element.params = {emailToken: 'foo'}; + element.params = {view: GerritView.SETTINGS, emailToken: 'foo'}; element.attached(); }); @@ -499,7 +500,7 @@ suite('gr-settings-view tests', () => { }); test('user emails are loaded after email confirmed', done => { - element._loadingPromise.then(() => { + element._testOnly_loadingPromise.then(() => { assert.isTrue(element.$.emailEditor.loadData.calledOnce); done(); }); @@ -508,7 +509,7 @@ suite('gr-settings-view tests', () => { test('show-alert is fired when email is confirmed', done => { sinon.spy(element, 'dispatchEvent'); - element._loadingPromise.then(() => { + element._testOnly_loadingPromise.then(() => { assert.equal( element.dispatchEvent.lastCall.args[0].type, 'show-alert'); assert.deepEqual( 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 8cc9c79..f4acf7a 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 @@ -1200,11 +1200,11 @@ export class GrRestApiInterface ); } - getDefaultPreferences() { + getDefaultPreferences(): Promise { return this._fetchSharedCacheURL({ url: '/config/server/preferences', reportUrlAsIs: true, - }); + }) as Promise; } getPreferences(): Promise { @@ -3180,7 +3180,7 @@ export class GrRestApiInterface }); } - confirmEmail(token: string) { + confirmEmail(token: string): Promise { const req = { method: HttpMethod.PUT, url: '/config/server/email.confirm', 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 836082b..0b0ad9e 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 @@ -766,4 +766,15 @@ export interface RestApiService { changeNum: NumericChangeId, patchNum: PatchSetNum ): Promise; + + confirmEmail(token: string): Promise; + + getDefaultPreferences(): Promise; + + addAccountEmail(email: string): Promise; + + addAccountEmail( + email: string, + errFn?: ErrorCallback + ): Promise; } diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts index a3f9962..481828a 100644 --- a/polygerrit-ui/app/types/common.ts +++ b/polygerrit-ui/app/types/common.ts @@ -42,6 +42,7 @@ import { DiffViewMode, DraftsAction, NotifyType, + EmailFormat, } from '../constants/constants'; import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces'; @@ -1036,15 +1037,24 @@ export interface ServerInfo { download: DownloadInfo; gerrit: GerritInfo; index: IndexConfigInfo; - note_db_enabled: boolean; + note_db_enabled?: boolean; plugin: PluginConfigInfo; receive?: ReceiveInfo; + sshd?: SshdInfo; suggest: SuggestInfo; user: UserConfigInfo; default_theme?: string; } /** + * The SshdInfo entity contains information about Gerrit configuration from the sshd section. + * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#sshd-info + * This entity doesn’t contain any data, but the presence of this (empty) entity + * in the ServerInfo entity means that SSHD is enabled on the server. + */ +export type SshdInfo = {}; + +/** * The SuggestInfo entity contains information about Gerritconfiguration from * the suggest section. * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#suggest-info @@ -1737,25 +1747,11 @@ export interface EditPreferencesInfo { /** * The PreferencesInput entity contains information for setting the user preferences. Fields which are not set will not be updated * https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#preferences-input + * + * Note: the doc missed several properties. Java code uses the same class (GeneralPreferencesInfo) + * both for input data and for response data. */ -export interface PreferencesInput { - changes_per_page?: 10 | 25 | 50 | 100; - theme?: AppTheme; - expand_inline_diffs?: boolean; - download_scheme?: string; - date_format?: DateFormat; - time_format?: TimeFormat; - relative_date_in_change_table?: boolean; - diff_view?: DiffViewMode; - size_bar_in_change_table?: boolean; - legacycid_in_change_table?: boolean; - mute_common_path_prefixes?: boolean; - signed_off_by?: boolean; - my?: TopMenuItemInfo[]; - change_table?: string[]; - email_strategy?: EmailStrategy; - default_base_for_merges?: DefaultBase; -} +export type PreferencesInput = Partial; /** * The DiffPreferencesInput entity contains information for setting the diff preferences of a user. Fields which are not set will not be updated @@ -1852,6 +1848,8 @@ export interface PreferencesInfo { default_base_for_merges: DefaultBase; publish_comments_on_push?: boolean; work_in_progress_by_default?: boolean; + // The email_format doesn't mentioned in doc, but exists in Java class GeneralPreferencesInfo + email_format?: EmailFormat; // The following property doesn't exist in RestAPI, it is added by GrRestApiInterface default_diff_view?: DiffViewMode; } diff --git a/polygerrit-ui/app/utils/url-util.ts b/polygerrit-ui/app/utils/url-util.ts index 612f05c..0c6fabc 100644 --- a/polygerrit-ui/app/utils/url-util.ts +++ b/polygerrit-ui/app/utils/url-util.ts @@ -29,13 +29,10 @@ let getDocsBaseUrlCachedPromise: Promise | undefined; /** * Get the docs base URL from either the server config or by probing. * - * @param config The server config. - * @param restApi A REST API instance - * @return A promise that resolves with the docs base - * URL. + * @return A promise that resolves with the docs base URL. */ export function getDocsBaseUrl( - config: ServerInfo, + config: ServerInfo | undefined, restApi: RestApiService ): Promise { if (!getDocsBaseUrlCachedPromise) {