Add subsection dropdown to gr-admin-view

Bug: Issue 8671
Change-Id: I9f84e6d11477f3a18ea966dd6ded3ca79f9e10ac
This commit is contained in:
Becky Siegel
2018-04-20 10:08:01 +02:00
parent 4c60d8c698
commit e88c3a2d8c
4 changed files with 291 additions and 40 deletions

View File

@@ -24,6 +24,8 @@ limitations under the License.
<link rel="import" href="../../../styles/gr-page-nav-styles.html">
<link rel="import" href="../../../styles/shared-styles.html">
<link rel="import" href="../../core/gr-navigation/gr-navigation.html">
<link rel="import" href="../../shared/gr-dropdown-list/gr-dropdown-list.html">
<link rel="import" href="../../shared/gr-icons/gr-icons.html">
<link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
<link rel="import" href="../../shared/gr-page-nav/gr-page-nav.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
@@ -43,7 +45,38 @@ limitations under the License.
<template>
<style include="shared-styles"></style>
<style include="gr-menu-page-styles"></style>
<style include="gr-page-nav-styles"></style>
<style include="gr-page-nav-styles">
gr-dropdown-list {
--trigger-style: {
text-transform: none;
}
}
.breadcrumbText {
/* Same as dropdown trigger so chevron spacing is consistent. */
padding: 5px 4px;
}
iron-icon {
margin: 0 .2em;
}
.breadcrumb {
align-items: center;
display: flex;
}
.mainHeader {
align-items: baseline;
border-bottom: 1px solid var(--border-color);
display: flex;
}
.selectText {
display: none;
}
.selectText.show {
display: inline-block;
}
main.breadcrumbs:not(.table) {
margin-top: 1em;
}
</style>
<gr-page-nav class="navStyles">
<ul class="sectionContent">
<template id="adminNav" is="dom-repeat" items="[[_filteredLinks]]">
@@ -75,29 +108,26 @@ limitations under the License.
</template>
</ul>
</gr-page-nav>
<template is="dom-if" if="[[_subsectionLinks.length]]">
<section class="mainHeader">
<span class="breadcrumb">
<span class="breadcrumbText">[[_breadcrumbParentName]]</span>
<iron-icon icon="gr-icons:chevron-right"></iron-icon>
</span>
<gr-dropdown-list
lowercase
id="pageSelect"
value="[[_computeSelectValue(params)]]"
items="[[_subsectionLinks]]"
on-value-change="_handleSubsectionChange">
</gr-dropdown-list>
</section>
</template>
<template is="dom-if" if="[[_showRepoList]]" restamp="true">
<main class="table">
<gr-repo-list class="table" params="[[params]]"></gr-repo-list>
</main>
</template>
<template is="dom-if" if="[[_showRepoMain]]" restamp="true">
<main>
<gr-repo repo="[[params.repo]]"></gr-repo>
</main>
</template>
<template is="dom-if" if="[[_showGroup]]" restamp="true">
<main>
<gr-group
group-id="[[params.groupId]]"
on-name-changed="_updateGroupName"></gr-group>
</main>
</template>
<template is="dom-if" if="[[_showGroupMembers]]" restamp="true">
<main>
<gr-group-members
group-id="[[params.groupId]]"></gr-group-members>
</main>
</template>
<template is="dom-if" if="[[_showGroupList]]" restamp="true">
<main class="table">
<gr-admin-group-list class="table" params="[[params]]">
@@ -109,35 +139,53 @@ limitations under the License.
<gr-plugin-list class="table" params="[[params]]"></gr-plugin-list>
</main>
</template>
<template is="dom-if" if="[[_showRepoMain]]" restamp="true">
<main class="breadcrumbs">
<gr-repo repo="[[params.repo]]"></gr-repo>
</main>
</template>
<template is="dom-if" if="[[_showGroup]]" restamp="true">
<main class="breadcrumbs">
<gr-group
group-id="[[params.groupId]]"
on-name-changed="_updateGroupName"></gr-group>
</main>
</template>
<template is="dom-if" if="[[_showGroupMembers]]" restamp="true">
<main class="breadcrumbs">
<gr-group-members
group-id="[[params.groupId]]"></gr-group-members>
</main>
</template>
<template is="dom-if" if="[[_showRepoDetailList]]" restamp="true">
<main class="table">
<main class="table breadcrumbs">
<gr-repo-detail-list
params="[[params]]"
class="table"></gr-repo-detail-list>
</main>
</template>
<template is="dom-if" if="[[_showGroupAuditLog]]" restamp="true">
<main class="table">
<main class="table breadcrumbs">
<gr-group-audit-log
group-id="[[params.groupId]]"
class="table"></gr-group-audit-log>
</main>
</template>
<template is="dom-if" if="[[_showRepoCommands]]" restamp="true">
<main>
<main class="breadcrumbs">
<gr-repo-commands
repo="[[params.repo]]"></gr-repo-commands>
</main>
</template>
<template is="dom-if" if="[[_showRepoAccess]]" restamp="true">
<main class="table">
<main class="breadcrumbs">
<gr-repo-access
path="[[path]]"
repo="[[params.repo]]"></gr-repo-access>
</main>
</template>
<template is="dom-if" if="[[_showRepoDashboards]]" restamp="true">
<main class="table">
<main class="table breadcrumbs">
<gr-repo-dashboards repo="[[params.repo]]"></gr-repo-dashboards>
</main>
</template>

View File

@@ -29,6 +29,7 @@
path: String,
adminView: String,
_breadcrumbParentName: String,
_repoName: String,
_groupId: {
type: Number,
@@ -103,6 +104,8 @@
options)
.then(res => {
this._filteredLinks = res.links;
this._breadcrumbParentName = res.expandedSection ?
res.expandedSection.name : '';
if (!res.expandedSection) {
this._subsectionLinks = [];
@@ -112,7 +115,7 @@
.concat(res.expandedSection.children).map(section => {
return {
text: !section.detailType ? 'Home' : section.name,
value: section.view + section.detailType,
value: section.view + (section.detailType || ''),
view: section.view,
url: section.url,
detailType: section.detailType,
@@ -123,6 +126,17 @@
});
},
_computeSelectValue(params) {
if (!params || !params.view) { return; }
return params.view + (params.detail || '');
},
_selectedIsCurrentPage(selected) {
return (selected.parent === (this._repoName || this._groupId) &&
selected.view === this.params.view &&
selected.detailType === this.params.detail);
},
_handleSubsectionChange(e) {
const selected = this._subsectionLinks
.find(section => section.value === e.detail.value);
@@ -165,16 +179,22 @@
this.set('_showPluginList', isAdminView &&
params.adminView === 'gr-plugin-list');
let needsReload = false;
if (params.repo !== this._repoName) {
this._repoName = params.repo || '';
// Reloads the admin menu.
this.reload();
needsReload = true;
}
if (params.groupId !== this._groupId) {
this._groupId = params.groupId || '';
// Reloads the admin menu.
this.reload();
needsReload = true;
}
if (this._breadcrumbParentName && !params.groupId && !params.repo) {
needsReload = true;
}
if (!needsReload) { return; }
this.reload();
},
_computeSelectedTitle(params) {

View File

@@ -79,7 +79,6 @@ limitations under the License.
name: 'Repositories',
url: '/admin/repos',
view: 'gr-repo-list',
children: [],
}];
element.params = {
@@ -189,17 +188,10 @@ limitations under the License.
});
element.reload().then(() => {
flushAsynchronousOperations();
assert.equal(element._filteredLinks.length, 3);
// Repos
assert.equal(element._filteredLinks[0].subsection.children.length, 5);
assert.equal(element._filteredLinks[0].subsection.name, 'Test Repo');
// Groups
assert.isNotOk(element._filteredLinks[1].subsection);
// Plugins
assert.isNotOk(element._filteredLinks[2].subsection);
assert.equal(Polymer.dom(element.root)
.querySelectorAll('.sectionTitle').length, 3);
assert.equal(element.$$('.breadcrumbText').innerText, 'Test Repo');
assert.equal(element.$$('#pageSelect').items.length, 6);
done();
});
});
@@ -287,6 +279,188 @@ limitations under the License.
element.$$('gr-group').fire('name-changed', {name: newName});
});
test('dropdown displays if there is a subsection', () => {
assert.isNotOk(element.$$('.mainHeader'));
element._subsectionLinks = [
{
text: 'Home',
value: 'repo',
view: 'repo',
url: '',
parent: 'my-repo',
detailType: undefined,
},
];
flushAsynchronousOperations();
assert.isOk(element.$$('.mainHeader'));
element._subsectionLinks = undefined;
flushAsynchronousOperations();
assert.equal(getComputedStyle(element.$$('.mainHeader')).display, 'none');
});
test('Dropdown only triggers navigation on explicit select', done => {
element._repoName = 'my-repo';
element.params = {
repo: 'my-repo',
view: Gerrit.Nav.View.REPO,
detail: Gerrit.Nav.RepoDetailView.ACCESS,
};
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
return Promise.resolve({
createGroup: true,
createProject: true,
viewPlugins: true,
});
});
sandbox.stub(element.$.restAPI, 'getAccount', () => {
return Promise.resolve({_id: 1});
});
flushAsynchronousOperations();
const expectedFilteredLinks = [
{
name: 'Repositories',
noBaseUrl: true,
url: '/admin/repos',
view: 'gr-repo-list',
viewableToAll: true,
subsection: {
name: 'my-repo',
view: 'repo',
url: '',
children: [
{
name: 'Access',
view: 'repo',
detailType: 'access',
url: '',
},
{
name: 'Commands',
view: 'repo',
detailType: 'commands',
url: '',
},
{
name: 'Branches',
view: 'repo',
detailType: 'branches',
url: '',
},
{
name: 'Tags',
view: 'repo',
detailType: 'tags',
url: '',
},
{
name: 'Dashboards',
view: 'repo',
detailType: 'dashboards',
url: '',
},
],
},
},
{
name: 'Groups',
section: 'Groups',
noBaseUrl: true,
url: '/admin/groups',
view: 'gr-admin-group-list',
},
{
name: 'Plugins',
capability: 'viewPlugins',
section: 'Plugins',
noBaseUrl: true,
url: '/admin/plugins',
view: 'gr-plugin-list',
},
];
const expectedSubsectionLinks = [
{
text: 'Home',
value: 'repo',
view: 'repo',
url: '',
parent: 'my-repo',
detailType: undefined,
},
{
text: 'Access',
value: 'repoaccess',
view: 'repo',
url: '',
detailType: 'access',
parent: 'my-repo',
},
{
text: 'Commands',
value: 'repocommands',
view: 'repo',
url: '',
detailType: 'commands',
parent: 'my-repo',
},
{
text: 'Branches',
value: 'repobranches',
view: 'repo',
url: '',
detailType: 'branches',
parent: 'my-repo',
},
{
text: 'Tags',
value: 'repotags',
view: 'repo',
url: '',
detailType: 'tags',
parent: 'my-repo',
},
{
text: 'Dashboards',
value: 'repodashboards',
view: 'repo',
url: '',
detailType: 'dashboards',
parent: 'my-repo',
},
];
sandbox.stub(Gerrit.Nav, 'navigateToRelativeUrl');
sandbox.spy(element, '_selectedIsCurrentPage');
sandbox.spy(element, '_handleSubsectionChange');
element.reload().then(() => {
assert.deepEqual(element._filteredLinks, expectedFilteredLinks);
assert.deepEqual(element._subsectionLinks, expectedSubsectionLinks);
assert.equal(element.$$('#pageSelect').value, 'repoaccess');
assert.isTrue(element._selectedIsCurrentPage.calledOnce);
// Doesn't trigger navigation from the page select menu.
assert.isFalse(Gerrit.Nav.navigateToRelativeUrl.called);
// When explicitly changed, navigation is called
element.$$('#pageSelect').value = 'repo';
assert.isTrue(element._selectedIsCurrentPage.calledTwice);
assert.isTrue(Gerrit.Nav.navigateToRelativeUrl.calledOnce);
done();
});
});
test('_selectedIsCurrentPage', () => {
element._repoName = 'my-repo';
element.params = {view: 'repo', repo: 'my-repo'};
const selected = {
view: 'repo',
detailType: undefined,
parent: 'my-repo',
};
assert.isTrue(element._selectedIsCurrentPage(selected));
selected.parent = 'my-second-repo';
assert.isFalse(element._selectedIsCurrentPage(selected));
selected.detailType = 'detailType';
assert.isFalse(element._selectedIsCurrentPage(selected));
});
suite('_computeSelectedClass', () => {
setup(() => {
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {

View File

@@ -25,7 +25,12 @@ limitations under the License.
margin: 2em auto;
max-width: 50em;
}
main.table {
.mainHeader {
margin-left: 14em;
padding: 1em 0 1em 2em;
}
main.table,
.mainHeader {
margin-top: 0;
margin-right: 0;
margin-left: 14em;
@@ -57,6 +62,10 @@ limitations under the License.
main.table {
margin: 0;
}
.mainHeader {
margin-left: 0;
padding: .5em 0 .5em 1em;
}
}
</style>
</template>