commit 556165471abbeac1d62eb0d3c272ccb4f8519297 Author: Dmitrii Filippov Date: Mon Oct 5 19:07:27 2020 +0200 Convert files to typescript The change converts the following files to typescript: * elements/admin/gr-admin-view/gr-admin-view.ts Change-Id: I137597cf44dd829fcf43a4d2475445942f9a6f08 diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts index b9039ae..9d40e28 100644 --- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts +++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts @@ -31,7 +31,7 @@ import {GerritNav} from '../../core/gr-navigation/gr-navigation'; import {customElement, property, observe, computed} from '@polymer/decorators'; import {AppElementAdminParams} from '../../gr-app-types'; import {GrOverlay} from '../../shared/gr-overlay/gr-overlay'; -import {GroupId, GroupInfo} from '../../../types/common'; +import {GroupId, GroupInfo, GroupName} from '../../../types/common'; import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api'; import {GrCreateGroupDialog} from '../gr-create-group-dialog/gr-create-group-dialog'; @@ -160,7 +160,7 @@ export class GrAdminGroupList extends ListViewMixin( } this._groups = Object.keys(groups).map(key => { const group = groups[key]; - group.name = key; + group.name = key as GroupName; return group; }); this._loading = false; diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts index d861681..7fb713f 100644 --- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts +++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts @@ -14,95 +14,175 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import '../../../styles/gr-menu-page-styles.js'; -import '../../../styles/gr-page-nav-styles.js'; -import '../../../styles/shared-styles.js'; -import '../../shared/gr-dropdown-list/gr-dropdown-list.js'; -import '../../shared/gr-icons/gr-icons.js'; -import '../../shared/gr-js-api-interface/gr-js-api-interface.js'; -import '../../shared/gr-page-nav/gr-page-nav.js'; -import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js'; -import '../gr-admin-group-list/gr-admin-group-list.js'; -import '../gr-group/gr-group.js'; -import '../gr-group-audit-log/gr-group-audit-log.js'; -import '../gr-group-members/gr-group-members.js'; -import '../gr-plugin-list/gr-plugin-list.js'; -import '../gr-repo/gr-repo.js'; -import '../gr-repo-access/gr-repo-access.js'; -import '../gr-repo-commands/gr-repo-commands.js'; -import '../gr-repo-dashboards/gr-repo-dashboards.js'; -import '../gr-repo-detail-list/gr-repo-detail-list.js'; -import '../gr-repo-list/gr-repo-list.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-admin-view_html.js'; -import {getBaseUrl} from '../../../utils/url-util.js'; -import {GerritNav} from '../../core/gr-navigation/gr-navigation.js'; -import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js'; -import {getAdminLinks} from '../../../utils/admin-nav-util.js'; +import '../../../styles/gr-menu-page-styles'; +import '../../../styles/gr-page-nav-styles'; +import '../../../styles/shared-styles'; +import '../../shared/gr-dropdown-list/gr-dropdown-list'; +import '../../shared/gr-icons/gr-icons'; +import '../../shared/gr-js-api-interface/gr-js-api-interface'; +import '../../shared/gr-page-nav/gr-page-nav'; +import '../../shared/gr-rest-api-interface/gr-rest-api-interface'; +import '../gr-admin-group-list/gr-admin-group-list'; +import '../gr-group/gr-group'; +import '../gr-group-audit-log/gr-group-audit-log'; +import '../gr-group-members/gr-group-members'; +import '../gr-plugin-list/gr-plugin-list'; +import '../gr-repo/gr-repo'; +import '../gr-repo-access/gr-repo-access'; +import '../gr-repo-commands/gr-repo-commands'; +import '../gr-repo-dashboards/gr-repo-dashboards'; +import '../gr-repo-detail-list/gr-repo-detail-list'; +import '../gr-repo-list/gr-repo-list'; +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-admin-view_html'; +import {getBaseUrl} from '../../../utils/url-util'; +import { + GerritNav, + GerritView, + GroupDetailView, + RepoDetailView, +} from '../../core/gr-navigation/gr-navigation'; +import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader'; +import { + AdminNavLinksOption, + getAdminLinks, + NavLink, + SubsectionInterface, +} from '../../../utils/admin-nav-util'; +import {customElement, observe, property} from '@polymer/decorators'; +import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api'; +import { + AppElementAdminParams, + AppElementGroupParams, + AppElementRepoParams, +} from '../../gr-app-types'; +import { + AccountDetailInfo, + GroupId, + GroupName, + RepoName, +} from '../../../types/common'; +import {GroupNameChangedDetail} from '../gr-group/gr-group'; +import {ValueChangeDetail} from '../../shared/gr-dropdown-list/gr-dropdown-list'; +import {GrJsApiInterface} from '../../shared/gr-js-api-interface/gr-js-api-interface-element'; const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/; -/** - * @extends PolymerElement - */ -class GrAdminView extends GestureEventListeners( - LegacyElementMixin( - PolymerElement)) { - static get template() { return htmlTemplate; } - - static get is() { return 'gr-admin-view'; } - - static get properties() { - return { - /** @type {?} */ - params: Object, - path: String, - adminView: String, - - _breadcrumbParentName: String, - _repoName: String, - _groupId: { - type: Number, - observer: '_computeGroupName', - }, - _groupIsInternal: Boolean, - _groupName: String, - _groupOwner: { - type: Boolean, - value: false, - }, - _subsectionLinks: Array, - _filteredLinks: Array, - _showDownload: { - type: Boolean, - value: false, - }, - _isAdmin: { - type: Boolean, - value: false, - }, - _showGroup: Boolean, - _showGroupAuditLog: Boolean, - _showGroupList: Boolean, - _showGroupMembers: Boolean, - _showRepoAccess: Boolean, - _showRepoCommands: Boolean, - _showRepoDashboards: Boolean, - _showRepoDetailList: Boolean, - _showRepoMain: Boolean, - _showRepoList: Boolean, - _showPluginList: Boolean, - }; +export interface GrAdminView { + $: { + restAPI: RestApiService & Element; + jsAPI: GrJsApiInterface; + }; +} + +interface AdminSubsectionLink { + text: string; + value: string; + view: GerritView; + url: string; + detailType?: GroupDetailView | RepoDetailView; + parent?: GroupId | RepoName; +} + +// The type is matched to the _showAdminView function from the gr-app-element +type AdminViewParams = + | AppElementAdminParams + | AppElementGroupParams + | AppElementRepoParams; + +function getAdminViewParamsDetail( + params: AdminViewParams +): GroupDetailView | RepoDetailView | undefined { + if (params.view !== GerritView.ADMIN) { + return params.detail; } + return undefined; +} - static get observers() { - return [ - '_paramsChanged(params)', - ]; +@customElement('gr-admin-view') +export class GrAdminView extends GestureEventListeners( + LegacyElementMixin(PolymerElement) +) { + static get template() { + return htmlTemplate; } + private _account?: AccountDetailInfo; + + @property({type: Object}) + params?: AdminViewParams; + + @property({type: String}) + path?: string; + + @property({type: String}) + adminView?: string; + + @property({type: String}) + _breadcrumbParentName?: string; + + @property({type: String}) + _repoName?: RepoName; + + @property({type: String, observer: '_computeGroupName'}) + _groupId?: GroupId; + + @property({type: Boolean}) + _groupIsInternal?: boolean; + + @property({type: String}) + _groupName?: GroupName; + + @property({type: Boolean}) + _groupOwner = false; + + @property({type: Array}) + _subsectionLinks?: AdminSubsectionLink[]; + + @property({type: Array}) + _filteredLinks?: NavLink[]; + + @property({type: Boolean}) + _showDownload = false; + + @property({type: Boolean}) + _isAdmin = false; + + @property({type: Boolean}) + _showGroup?: boolean; + + @property({type: Boolean}) + _showGroupAuditLog?: boolean; + + @property({type: Boolean}) + _showGroupList?: boolean; + + @property({type: Boolean}) + _showGroupMembers?: boolean; + + @property({type: Boolean}) + _showRepoAccess?: boolean; + + @property({type: Boolean}) + _showRepoCommands?: boolean; + + @property({type: Boolean}) + _showRepoDashboards?: boolean; + + @property({type: Boolean}) + _showRepoDetailList?: boolean; + + @property({type: Boolean}) + _showRepoMain?: boolean; + + @property({type: Boolean}) + _showRepoList?: boolean; + + @property({type: Boolean}) + _showPluginList?: boolean; + /** @override */ attached() { super.attached(); @@ -110,13 +190,13 @@ class GrAdminView extends GestureEventListeners( } reload() { - const promises = [ + const promises: [Promise, Promise] = [ this.$.restAPI.getAccount(), getPluginLoader().awaitPluginsLoaded(), ]; return Promise.all(promises).then(result => { this._account = result[0]; - let options; + let options: AdminNavLinksOption | undefined = undefined; if (this._repoName) { options = {repoName: this._repoName}; } else if (this._groupId) { @@ -129,174 +209,240 @@ class GrAdminView extends GestureEventListeners( }; } - return getAdminLinks(this._account, - params => this.$.restAPI.getAccountCapabilities(params), - () => this.$.jsAPI.getAdminMenuLinks(), - options) - .then(res => { - this._filteredLinks = res.links; - this._breadcrumbParentName = res.expandedSection ? - res.expandedSection.name : ''; - - if (!res.expandedSection) { - this._subsectionLinks = []; - return; + return getAdminLinks( + this._account, + () => + this.$.restAPI.getAccountCapabilities().then(capabilities => { + if (!capabilities) { + throw new Error('getAccountCapabilities returns undefined'); } - this._subsectionLinks = [res.expandedSection] - .concat(res.expandedSection.children).map(section => { - return { - text: !section.detailType ? 'Home' : section.name, - value: section.view + (section.detailType || ''), - view: section.view, - url: section.url, - detailType: section.detailType, - parent: this._groupId || this._repoName || '', - }; - }); + return capabilities; + }), + () => this.$.jsAPI.getAdminMenuLinks(), + options + ).then(res => { + this._filteredLinks = res.links; + this._breadcrumbParentName = res.expandedSection + ? res.expandedSection.name + : ''; + + if (!res.expandedSection) { + this._subsectionLinks = []; + return; + } + this._subsectionLinks = [res.expandedSection] + .concat(res.expandedSection.children ?? []) + .map(section => { + return { + text: !section.detailType ? 'Home' : section.name, + value: section.view + (section.detailType ?? ''), + view: section.view, + url: section.url, + detailType: section.detailType, + parent: this._groupId ?? this._repoName, + }; }); + }); }); } - _computeSelectValue(params) { - if (!params || !params.view) { return; } - return params.view + (params.detail || ''); + _computeSelectValue(params: AdminViewParams) { + if (!params || !params.view) return; + return `${params.view}${getAdminViewParamsDetail(params) ?? ''}`; } - _selectedIsCurrentPage(selected) { - return (selected.parent === (this._repoName || this._groupId) && - selected.view === this.params.view && - selected.detailType === this.params.detail); + _selectedIsCurrentPage(selected: AdminSubsectionLink) { + if (!this.params) return false; + + return ( + selected.parent === (this._repoName ?? this._groupId) && + selected.view === this.params.view && + selected.detailType === getAdminViewParamsDetail(this.params) + ); } - _handleSubsectionChange(e) { - const selected = this._subsectionLinks - .find(section => section.value === e.detail.value); + _handleSubsectionChange(e: CustomEvent) { + if (!this._subsectionLinks) return; + + // The GrDropdownList items are _subsectionLinks, so find(...) always return + // an item _subsectionLinks and never returns undefined + const selected = this._subsectionLinks.find( + section => section.value === e.detail.value + )!; // This is when it gets set initially. - if (this._selectedIsCurrentPage(selected)) { - return; - } + if (this._selectedIsCurrentPage(selected)) return; GerritNav.navigateToRelativeUrl(selected.url); } - _paramsChanged(params) { - const isGroupView = params.view === GerritNav.View.GROUP; - const isRepoView = params.view === GerritNav.View.REPO; - const isAdminView = params.view === GerritNav.View.ADMIN; - - this.set('_showGroup', isGroupView && !params.detail); - this.set('_showGroupAuditLog', isGroupView && - params.detail === GerritNav.GroupDetailView.LOG); - this.set('_showGroupMembers', isGroupView && - params.detail === GerritNav.GroupDetailView.MEMBERS); - - this.set('_showGroupList', isAdminView && - params.adminView === 'gr-admin-group-list'); - - this.set('_showRepoAccess', isRepoView && - params.detail === GerritNav.RepoDetailView.ACCESS); - this.set('_showRepoCommands', isRepoView && - params.detail === GerritNav.RepoDetailView.COMMANDS); - this.set('_showRepoDetailList', isRepoView && - (params.detail === GerritNav.RepoDetailView.BRANCHES || - params.detail === GerritNav.RepoDetailView.TAGS)); - this.set('_showRepoDashboards', isRepoView && - params.detail === GerritNav.RepoDetailView.DASHBOARDS); - this.set('_showRepoMain', isRepoView && !params.detail); - - this.set('_showRepoList', isAdminView && - params.adminView === 'gr-repo-list'); - - this.set('_showPluginList', isAdminView && - params.adminView === 'gr-plugin-list'); + @observe('params') + _paramsChanged(params: AdminViewParams) { + this.set('_showGroup', params.view === GerritView.GROUP && !params.detail); + this.set( + '_showGroupAuditLog', + params.view === GerritView.GROUP && params.detail === GroupDetailView.LOG + ); + this.set( + '_showGroupMembers', + params.view === GerritView.GROUP && + params.detail === GroupDetailView.MEMBERS + ); + + this.set( + '_showGroupList', + params.view === GerritView.ADMIN && + params.adminView === 'gr-admin-group-list' + ); + + this.set( + '_showRepoAccess', + params.view === GerritView.REPO && params.detail === RepoDetailView.ACCESS + ); + this.set( + '_showRepoCommands', + params.view === GerritView.REPO && + params.detail === RepoDetailView.COMMANDS + ); + this.set( + '_showRepoDetailList', + params.view === GerritView.REPO && + (params.detail === RepoDetailView.BRANCHES || + params.detail === RepoDetailView.TAGS) + ); + this.set( + '_showRepoDashboards', + params.view === GerritView.REPO && + params.detail === RepoDetailView.DASHBOARDS + ); + this.set( + '_showRepoMain', + params.view === GerritView.REPO && !params.detail + ); + + this.set( + '_showRepoList', + params.view === GerritView.ADMIN && params.adminView === 'gr-repo-list' + ); + + this.set( + '_showPluginList', + params.view === GerritView.ADMIN && params.adminView === 'gr-plugin-list' + ); let needsReload = false; - if (params.repo !== this._repoName) { - this._repoName = params.repo || ''; + const newRepoName = + params.view === GerritView.REPO ? params.repo : undefined; + if (newRepoName !== this._repoName) { + this._repoName = newRepoName; // Reloads the admin menu. needsReload = true; } - if (params.groupId !== this._groupId) { - this._groupId = params.groupId || ''; + const newGroupId = + params.view === GerritView.GROUP ? params.groupId : undefined; + if (newGroupId !== this._groupId) { + this._groupId = newGroupId; // Reloads the admin menu. needsReload = true; } - if (this._breadcrumbParentName && !params.groupId && !params.repo) { + if ( + this._breadcrumbParentName && + (params.view !== GerritView.GROUP || !params.groupId) && + (params.view !== GerritView.REPO || !params.repo) + ) { needsReload = true; } - if (!needsReload) { return; } + if (!needsReload) { + return; + } this.reload(); } // TODO (beckysiegel): Update these functions after router abstraction is // updated. They are currently copied from gr-dropdown (and should be // updated there as well once complete). - _computeURLHelper(host, path) { + _computeURLHelper(host: string, path: string) { return '//' + host + getBaseUrl() + path; } - _computeRelativeURL(path) { + _computeRelativeURL(path: string) { const host = window.location.host; return this._computeURLHelper(host, path); } - _computeLinkURL(link) { - if (!link || typeof link.url === 'undefined') { return ''; } - if (link.target || !link.noBaseUrl) { + _computeLinkURL(link: NavLink | SubsectionInterface) { + if (!link || typeof link.url === 'undefined') return ''; + + if ((link as NavLink).target || !(link as NavLink).noBaseUrl) { return link.url; } return this._computeRelativeURL(link.url); } - /** - * @param {string} itemView - * @param {Object} params - * @param {string=} opt_detailType - */ - _computeSelectedClass(itemView, params, opt_detailType) { + _computeSelectedClass( + itemView?: GerritView, + params?: AdminViewParams, + detailType?: GroupDetailView | RepoDetailView + ) { if (!params) return ''; // Group params are structured differently from admin params. Compute // selected differently for groups. // TODO(wyatta): Simplify this when all routes work like group params. - if (params.view === GerritNav.View.GROUP && - itemView === GerritNav.View.GROUP) { - if (!params.detail && !opt_detailType) { return 'selected'; } - if (params.detail === opt_detailType) { return 'selected'; } + if (params.view === GerritView.GROUP && itemView === GerritView.GROUP) { + if (!params.detail && !detailType) { + return 'selected'; + } + if (params.detail === detailType) { + return 'selected'; + } return ''; } - if (params.view === GerritNav.View.REPO && - itemView === GerritNav.View.REPO) { - if (!params.detail && !opt_detailType) { return 'selected'; } - if (params.detail === opt_detailType) { return 'selected'; } + if (params.view === GerritView.REPO && itemView === GerritView.REPO) { + if (!params.detail && !detailType) { + return 'selected'; + } + if (params.detail === detailType) { + return 'selected'; + } return ''; } - - if (params.detailType && params.detailType !== opt_detailType) { + // TODO(TS): The following condtion seems always false, because params + // never has detailType property. Remove it. + if ( + ((params as unknown) as AdminSubsectionLink).detailType && + ((params as unknown) as AdminSubsectionLink).detailType !== detailType + ) { return ''; } - return itemView === params.adminView ? 'selected' : ''; + return params.view === GerritView.ADMIN && itemView === params.adminView + ? 'selected' + : ''; } - _computeGroupName(groupId) { - if (!groupId) { return ''; } + _computeGroupName(groupId?: GroupId) { + if (!groupId) return; - const promises = []; + const promises: Array> = []; this.$.restAPI.getGroupConfig(groupId).then(group => { - if (!group || !group.name) { return; } + if (!group || !group.name) { + return; + } this._groupName = group.name; this._groupIsInternal = !!group.id.match(INTERNAL_GROUP_REGEX); this.reload(); - promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => { - this._isAdmin = isAdmin; - })); + promises.push( + this.$.restAPI.getIsAdmin().then(isAdmin => { + this._isAdmin = !!isAdmin; + }) + ); - promises.push(this.$.restAPI.getIsGroupOwner(group.name).then( - isOwner => { - this._groupOwner = isOwner; - })); + promises.push( + this.$.restAPI.getIsGroupOwner(group.name).then(isOwner => { + this._groupOwner = isOwner; + }) + ); return Promise.all(promises).then(() => { this.reload(); @@ -304,10 +450,14 @@ class GrAdminView extends GestureEventListeners( }); } - _updateGroupName(e) { + _updateGroupName(e: CustomEvent) { this._groupName = e.detail.name; this.reload(); } } -customElements.define(GrAdminView.is, GrAdminView); +declare global { + interface HTMLElementTagNameMap { + 'gr-admin-view': GrAdminView; + } +} diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js index 5fe479a..44fd4d6 100644 --- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js +++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js @@ -18,7 +18,7 @@ import '../../../test/common-test-setup-karma.js'; import './gr-admin-view.js'; import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js'; -import {GerritNav} from '../../core/gr-navigation/gr-navigation.js'; +import {GerritNav, GerritView} from '../../core/gr-navigation/gr-navigation.js'; import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js'; import {stubBaseUrl} from '../../../test/test-utils.js'; @@ -149,7 +149,7 @@ suite('gr-admin-view tests', () => { return element.reload().then(() => { assert.equal(element._filteredLinks.length, 3); assert.deepEqual(element._filteredLinks[1], { - capability: null, + capability: undefined, url: '/internal/link/url', name: 'internal link text', noBaseUrl: true, @@ -158,7 +158,7 @@ suite('gr-admin-view tests', () => { target: null, }); assert.deepEqual(element._filteredLinks[2], { - capability: null, + capability: undefined, url: 'http://external/link/url', name: 'external link text', noBaseUrl: false, @@ -244,10 +244,10 @@ suite('gr-admin-view tests', () => { 'getAccount') .callsFake(() => Promise.resolve({_id: 1})); sinon.stub(element, 'reload'); - element.params = {repo: 'Test Repo', adminView: 'gr-repo'}; + element.params = {repo: 'Test Repo', view: GerritView.REPO}; assert.equal(element.reload.callCount, 1); element.params = {repo: 'Test Repo 2', - adminView: 'gr-repo'}; + view: GerritView.REPO}; assert.equal(element.reload.callCount, 2); }); @@ -266,7 +266,7 @@ suite('gr-admin-view tests', () => { 'getAccount') .callsFake(() => Promise.resolve({_id: 1})); sinon.stub(element, 'reload'); - element.params = {groupId: '1', adminView: 'gr-group'}; + element.params = {groupId: '1', view: GerritView.GROUP}; assert.equal(element.reload.callCount, 1); }); diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts index e8b5d78..1d8b7db 100644 --- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts +++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts @@ -26,7 +26,7 @@ import {encodeURL, getBaseUrl} from '../../../utils/url-util'; import {page} from '../../../utils/page-wrapper-utils'; import {customElement, property, observe} from '@polymer/decorators'; import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api'; -import {GroupId} from '../../../types/common'; +import {GroupName} from '../../../types/common'; export interface GrCreateGroupDialog { $: { @@ -46,7 +46,7 @@ export class GrCreateGroupDialog extends GestureEventListeners( hasNewGroupName = false; @property({type: String}) - _name = ''; + _name: GroupName | '' = ''; @property({type: Boolean}) _groupCreated = false; @@ -61,20 +61,17 @@ export class GrCreateGroupDialog extends GestureEventListeners( } handleCreateGroup() { - return this.$.restAPI - .createGroup({name: this._name}) - .then(groupRegistered => { - if (groupRegistered.status !== 201) { - return; - } - this._groupCreated = true; - return this.$.restAPI - .getGroupConfig(this._name as GroupId) - .then(group => { - // TODO(TS): should group always defined ? - page.show(this._computeGroupUrl(group!.group_id!)); - }); + const name = this._name as GroupName; + return this.$.restAPI.createGroup({name}).then(groupRegistered => { + if (groupRegistered.status !== 201) { + return; + } + this._groupCreated = true; + return this.$.restAPI.getGroupConfig(name).then(group => { + // TODO(TS): should group always defined ? + page.show(this._computeGroupUrl(group!.group_id!)); }); + }); } } diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts index f8f1fee..ae10c03 100644 --- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts +++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts @@ -41,6 +41,7 @@ import { AccountId, AccountInfo, GroupInfo, + GroupName, } from '../../../types/common'; import {AutocompleteQuery} from '../../shared/gr-autocomplete/gr-autocomplete'; import {PolymerDomRepeatEvent} from '../../../types/types'; @@ -85,7 +86,7 @@ export class GrGroupMembers extends GestureEventListeners( _loading = true; @property({type: String}) - _groupName?: GroupId; + _groupName?: GroupName; @property({type: Object}) _groupMembers?: AccountInfo[]; @@ -155,7 +156,7 @@ export class GrGroupMembers extends GestureEventListeners( return Promise.resolve(); } - this._groupName = config.name as GroupId; + this._groupName = config.name; promises.push( this.$.restAPI.getIsAdmin().then(isAdmin => { diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts index 7bc0312..511bf5c 100644 --- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts +++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts @@ -32,7 +32,7 @@ import { AutocompleteSuggestion, AutocompleteQuery, } from '../../shared/gr-autocomplete/gr-autocomplete'; -import {GroupId, GroupInfo} from '../../../types/common'; +import {GroupId, GroupInfo, GroupName} from '../../../types/common'; import { ErrorCallback, RestApiService, @@ -59,6 +59,11 @@ export interface GrGroup { }; } +export interface GroupNameChangedDetail { + name: GroupName; + external: boolean; +} + declare global { interface HTMLElementTagNameMap { 'gr-group': GrGroup; @@ -164,7 +169,7 @@ export class GrGroup extends GestureEventListeners( ); promises.push( - this.$.restAPI.getIsGroupOwner(config.name as GroupId).then(isOwner => { + this.$.restAPI.getIsGroupOwner(config.name).then(isOwner => { this._groupOwner = !!isOwner; }) ); @@ -205,17 +210,19 @@ export class GrGroup extends GestureEventListeners( if (!this.groupId || !groupConfig || !groupConfig.name) { return Promise.reject(new Error('invalid groupId or config name')); } + const groupName = groupConfig.name; return this.$.restAPI - .saveGroupName(this.groupId, groupConfig.name) + .saveGroupName(this.groupId, groupName) .then(config => { if (config.status === 200) { - this._groupName = groupConfig.name; + this._groupName = groupName; + const detail: GroupNameChangedDetail = { + name: groupName, + external: !this._groupIsInternal, + }; this.dispatchEvent( new CustomEvent('name-changed', { - detail: { - name: groupConfig.name, - external: !this._groupIsInternal, - }, + detail, composed: true, bubbles: true, }) diff --git a/polygerrit-ui/app/elements/gr-app-element.js b/polygerrit-ui/app/elements/gr-app-element.js index e5d424c..b67bea0 100644 --- a/polygerrit-ui/app/elements/gr-app-element.js +++ b/polygerrit-ui/app/elements/gr-app-element.js @@ -419,6 +419,7 @@ class GrAppElement extends KeyboardShortcutMixin( this.set('_showChangeView', view === GerritNav.View.CHANGE); this.set('_showDiffView', view === GerritNav.View.DIFF); this.set('_showSettingsView', view === GerritNav.View.SETTINGS); + // _showAdminView must be in sync with the gr-admin-view AdminViewParams type this.set('_showAdminView', view === GerritNav.View.ADMIN || view === GerritNav.View.GROUP || view === GerritNav.View.REPO); this.set('_showCLAView', view === GerritNav.View.AGREEMENTS); 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 7f2f018..8cc9c79 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 @@ -136,6 +136,7 @@ import { BlameInfo, ActionNameToActionInfoMap, RevisionId, + GroupName, } from '../../../types/common'; import { CancelConditionCallback, @@ -517,7 +518,7 @@ export class GrRestApiInterface } getGroupConfig( - group: GroupId, + group: GroupId | GroupName, errFn?: ErrorCallback ): Promise { return this._restApiHelper.fetchJSON({ @@ -651,7 +652,7 @@ export class GrRestApiInterface }); } - getIsGroupOwner(groupName: GroupId): Promise { + getIsGroupOwner(groupName: GroupName): Promise { const encodeName = encodeURIComponent(groupName); const req = { url: `/groups/?owned&g=${encodeName}`, @@ -663,7 +664,7 @@ export class GrRestApiInterface } getGroupMembers( - groupName: GroupId, + groupName: GroupId | GroupName, errFn?: ErrorCallback ): Promise { const encodeName = encodeURIComponent(groupName); @@ -674,14 +675,16 @@ export class GrRestApiInterface }) as Promise; } - getIncludedGroup(groupName: GroupId): Promise { + getIncludedGroup( + groupName: GroupId | GroupName + ): Promise { return this._restApiHelper.fetchJSON({ url: `/groups/${encodeURIComponent(groupName)}/groups/`, anonymizedUrl: '/groups/*/groups', }) as Promise; } - saveGroupName(groupId: GroupId, name: string): Promise { + saveGroupName(groupId: GroupId | GroupName, name: string): Promise { const encodeId = encodeURIComponent(groupId); return this._restApiHelper.send({ method: HttpMethod.PUT, @@ -691,7 +694,10 @@ export class GrRestApiInterface }); } - saveGroupOwner(groupId: GroupId, ownerId: string): Promise { + saveGroupOwner( + groupId: GroupId | GroupName, + ownerId: string + ): Promise { const encodeId = encodeURIComponent(groupId); return this._restApiHelper.send({ method: HttpMethod.PUT, @@ -702,7 +708,7 @@ export class GrRestApiInterface } saveGroupDescription( - groupId: GroupId, + groupId: GroupId | GroupName, description: string ): Promise { const encodeId = encodeURIComponent(groupId); @@ -715,7 +721,7 @@ export class GrRestApiInterface } saveGroupOptions( - groupId: GroupId, + groupId: GroupId | GroupName, options: GroupOptionsInput ): Promise { const encodeId = encodeURIComponent(groupId); @@ -739,7 +745,7 @@ export class GrRestApiInterface } saveGroupMember( - groupName: GroupId, + groupName: GroupId | GroupName, groupMember: AccountId ): Promise { const encodeName = encodeURIComponent(groupName); @@ -753,7 +759,7 @@ export class GrRestApiInterface } saveIncludedGroup( - groupName: GroupId, + groupName: GroupId | GroupName, includedGroup: GroupId, errFn?: ErrorCallback ): Promise { @@ -776,7 +782,7 @@ export class GrRestApiInterface } deleteGroupMember( - groupName: GroupId, + groupName: GroupId | GroupName, groupMember: AccountId ): Promise { const encodeName = encodeURIComponent(groupName); @@ -790,7 +796,7 @@ export class GrRestApiInterface deleteIncludedGroup( groupName: GroupId, - includedGroup: GroupId + includedGroup: GroupId | GroupName ): Promise { const encodeName = encodeURIComponent(groupName); const encodeIncludedGroup = encodeURIComponent(includedGroup); 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 0438ab1..836082b 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 @@ -92,6 +92,7 @@ import { ImagesForDiff, ActionNameToActionInfoMap, RevisionId, + GroupName, } from '../../../types/common'; import {ParsedChangeInfo} from '../../../elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser'; import {HttpMethod, IgnoreWhitespaceType} from '../../../constants/constants'; @@ -361,17 +362,23 @@ export interface RestApiService { ): Promise; getGroupConfig( - group: GroupId, + group: GroupId | GroupName, errFn?: ErrorCallback ): Promise; getIsAdmin(): Promise; - getIsGroupOwner(groupName: GroupId): Promise; + getIsGroupOwner(groupName: GroupName): Promise; - saveGroupName(groupId: GroupId, name: string): Promise; + saveGroupName( + groupId: GroupId | GroupName, + name: GroupName + ): Promise; - saveGroupOwner(groupId: GroupId, ownerId: string): Promise; + saveGroupOwner( + groupId: GroupId | GroupName, + ownerId: string + ): Promise; saveGroupDescription( groupId: GroupId, @@ -637,30 +644,32 @@ export interface RestApiService { ): Promise; getGroupMembers( - groupName: GroupId, + groupName: GroupId | GroupName, errFn?: ErrorCallback ): Promise; - getIncludedGroup(groupName: GroupId): Promise; + getIncludedGroup( + groupName: GroupId | GroupName + ): Promise; saveGroupMember( - groupName: GroupId, + groupName: GroupId | GroupName, groupMember: AccountId ): Promise; saveIncludedGroup( - groupName: GroupId, + groupName: GroupId | GroupName, includedGroup: GroupId, errFn?: ErrorCallback ): Promise; deleteGroupMember( - groupName: GroupId, + groupName: GroupId | GroupName, groupMember: AccountId ): Promise; deleteIncludedGroup( - groupName: GroupId, + groupName: GroupId | GroupName, includedGroup: GroupId ): Promise; diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts index 199bf7c..9baeba6 100644 --- a/polygerrit-ui/app/types/common.ts +++ b/polygerrit-ui/app/types/common.ts @@ -132,6 +132,7 @@ export type Hashtag = BrandType; export type StarLabel = BrandType; export type CommitId = BrandType; export type LabelName = BrandType; +export type GroupName = BrandType; // The UUID of the group export type GroupId = BrandType; @@ -369,17 +370,17 @@ export interface GroupAuditEventInfo { */ export interface GroupBaseInfo { id: GroupId; - name: string; + name: GroupName; } /** * The GroupInfo entity contains information about a group. This can be a * Gerrit internal group, or an external group that is known to Gerrit. - * https://gerrit-review.googlesource.com/Documentation/rest-api-groups.html + * https://gerrit-review.googlesource.com/Documentation/rest-api-groups.html#group-info */ export interface GroupInfo { id: GroupId; - name?: string; + name?: GroupName; url?: string; options?: GroupOptionsInfo; description?: string; @@ -397,10 +398,10 @@ export type GroupNameToGroupInfoMap = {[groupName: string]: GroupInfo}; /** * The 'GroupInput' entity contains information for the creation of a new * internal group. - * https://gerrit-review.googlesource.com/Documentation/rest-api-groups.html + * https://gerrit-review.googlesource.com/Documentation/rest-api-groups.html#group-input */ export interface GroupInput { - name?: string; + name?: GroupName; uuid?: string; description?: string; visible_to_all?: string; diff --git a/polygerrit-ui/app/utils/admin-nav-util.ts b/polygerrit-ui/app/utils/admin-nav-util.ts index bb95066..06f4e3a 100644 --- a/polygerrit-ui/app/utils/admin-nav-util.ts +++ b/polygerrit-ui/app/utils/admin-nav-util.ts @@ -24,7 +24,7 @@ import { RepoName, GroupId, AccountDetailInfo, - CapabilityInfo, + AccountCapabilityInfo, } from '../types/common'; import {MenuLink} from '../elements/plugins/gr-admin-api/gr-admin-api'; import {hasOwnProperty} from './common-util'; @@ -54,12 +54,27 @@ const ADMIN_LINKS: NavLink[] = [ }, ]; +export interface AdminLink { + url: string; + text: string; + capability: string | null; + noBaseUrl: boolean; + view: null; + viewableToAll: boolean; + target: '_blank' | null; +} + +export interface AdminLinks { + links: NavLink[]; + expandedSection?: SubsectionInterface; +} + export function getAdminLinks( - account: AccountDetailInfo, - getAccountCapabilities: (params?: string[]) => Promise, + account: AccountDetailInfo | undefined, + getAccountCapabilities: () => Promise, getAdminMenuLinks: () => MenuLink[], options?: AdminNavLinksOption -) { +): Promise { if (!account) { return Promise.resolve( _filterLinks(link => !!link.viewableToAll, getAdminMenuLinks, options) @@ -78,9 +93,9 @@ function _filterLinks( filterFn: (link: NavLink) => boolean, getAdminMenuLinks: () => MenuLink[], options?: AdminNavLinksOption -) { - let links = ADMIN_LINKS.slice(0); - let expandedSection; +): AdminLinks { + let links: NavLink[] = ADMIN_LINKS.slice(0); + let expandedSection: SubsectionInterface | undefined = undefined; const isExternalLink = (link: MenuLink) => link.url[0] !== '/'; @@ -90,18 +105,18 @@ function _filterLinks( return { url: link.url, name: link.text, - capability: link.capability || null, + capability: link.capability || undefined, noBaseUrl: !isExternalLink(link), view: null, viewableToAll: !link.capability, target: isExternalLink(link) ? '_blank' : null, - } as NavLink; + }; }) ); links = links.filter(filterFn); - const filteredLinks = []; + const filteredLinks: NavLink[] = []; const repoName = options && options.repoName; const groupId = options && options.groupId; const groupName = options && options.groupName; diff --git a/polygerrit-ui/app/utils/display-name-util.ts b/polygerrit-ui/app/utils/display-name-util.ts index 21c4e09..7114f98 100644 --- a/polygerrit-ui/app/utils/display-name-util.ts +++ b/polygerrit-ui/app/utils/display-name-util.ts @@ -84,5 +84,5 @@ function _accountEmail(email?: string) { export const _testOnly_accountEmail = _accountEmail; export function getGroupDisplayName(group: GroupInfo) { - return (group.name || '') + ' (group)'; + return `${group.name || ''} (group)`; }