Merge "Add project specific nav to sidebar"

This commit is contained in:
Becky Siegel 2017-06-27 18:27:52 +00:00 committed by Gerrit Code Review
commit 046d4df941
4 changed files with 99 additions and 37 deletions
polygerrit-ui/app/elements

@ -17,6 +17,7 @@ limitations under the License.
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
<link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
<link rel="import" href="../../../styles/gr-menu-page-styles.html">
<link rel="import" href="../../../styles/shared-styles.html">
<link rel="import" href="../../shared/gr-page-nav/gr-page-nav.html">
@ -34,17 +35,32 @@ limitations under the License.
<style include="gr-menu-page-styles"></style>
<gr-page-nav class$="[[_computeLoadingClass(_loading)]]">
<ul class="sectionContent">
<template is="dom-repeat" items="[[_filteredLinks]]">
<template id="adminNav" is="dom-repeat" items="[[_filteredLinks]]">
<li class$="sectionTitle [[_computeSelectedClass(item.view, params)]]">
<a class="title" href="[[_computeLinkURL(item)]]"
rel$="[[_computeLinkRel(item)]]">[[item.name]]</a>
</li>
<template is="dom-repeat" items="[[item.children]]">
<li class$="[[_computeSelectedClass(item.view, params)]]">
<a href="[[_computeLinkURL(item)]]"
rel$="[[_computeLinkRel(item)]]">[[item.name]]</a>
<template is="dom-repeat" items="[[item.children]]" as="child">
<li class$="[[_computeSelectedClass(child.view, params)]]">
<a href$="[[_computeLinkURL(child)]]"
rel="noopener">[[child.name]]</a>
</li>
</template>
<template is="dom-if" if="[[item.subsection]]">
<!--If a section has a subsection, render that.-->
<li class$="[[_computeSelectedClass(item.subsection.view, params)]]">
<a class="title" href$="[[_computeLinkURL(item.subsection)]]"
rel$="[[_computeLinkRel(item.subsection)]]">
[[item.subsection.name]]</a>
</li>
<!--Loop through the links in the sub-section.-->
<template is="dom-repeat"
items="[[item.subsection.children]]" as="child">
<li class$="subsectionItem [[_computeSelectedClass(child.view, params)]]">
<a href$="[[_computeLinkURL(child)]]">[[child.name]]</a>
</li>
</template>
</template>
</template>
</ul>
</gr-page-nav>

@ -55,6 +55,7 @@
path: String,
adminView: String,
_project: String,
_filteredLinks: Array,
_showDownload: {
type: Boolean,
@ -69,6 +70,7 @@
behaviors: [
Gerrit.BaseUrlBehavior,
Gerrit.URLEncodingBehavior,
],
observers: [
@ -94,10 +96,23 @@
_filterLinks(filterFn) {
const links = ADMIN_LINKS.filter(filterFn);
const filteredLinks = [];
for (const link of links) {
link.children = link.children ? link.children.filter(filterFn) : [];
const linkCopy = Object.assign({}, link);
linkCopy.children = linkCopy.children ?
linkCopy.children.filter(filterFn) : [];
if (linkCopy.name === 'Projects' && this._project) {
linkCopy.subsection = {
name: `${this._project}`,
view: 'gr-admin-project',
url: `/admin/projects/${this.encodeURL(this._project, true)}`,
// TODO(beckysiegel): Branches
children: [],
};
}
filteredLinks.push(linkCopy);
}
return links;
return filteredLinks;
},
_loadAccountCapabilities() {
@ -110,29 +125,6 @@
});
},
_computeSideLinks(unformattedLinks) {
const topLevelLinks = unformattedLinks.filter(link => {
return link.topLevel;
});
const nestedLinks = unformattedLinks.filter(link => {
return !link.topLevel;
});
return topLevelLinks.map(item => {
const section = {
name: item.name,
url: item.url,
view: item.view,
};
const newLinks = nestedLinks.filter(group => {
return group.section === section.name;
});
section.links = newLinks;
return section;
});
},
_paramsChanged(params) {
this.set('_showCreateProject',
params.adminView === 'gr-admin-create-project');
@ -141,6 +133,11 @@
params.adminView === 'gr-admin-project-list');
this.set('_showGroupList', params.adminView === 'gr-admin-group-list');
this.set('_showPluginList', params.adminView === 'gr-admin-plugin-list');
if (params.project !== this._project) {
this._project = params.project || '';
// Reloads the admin menu.
this.reload();
}
},
// TODO (beckysiegel): Update these functions after router abstraction is
@ -156,19 +153,13 @@
},
_computeLinkURL(link) {
if (typeof link.url === 'undefined') {
return '';
}
if (!link || typeof link.url === 'undefined') { return ''; }
if (link.target) {
return link.url;
}
return this._computeRelativeURL(link.url);
},
_computeLinkRel(link) {
return link.target ? 'noopener' : null;
},
_computeSelectedClass(itemView, params) {
return itemView === params.adminView ? 'selected' : '';
},

@ -39,6 +39,11 @@ limitations under the License.
setup(() => {
sandbox = sinon.sandbox.create();
element = fixture('basic');
stub('gr-rest-api-interface', {
getProjectConfig() {
return Promise.resolve({});
},
});
});
teardown(() => {
@ -99,6 +104,7 @@ limitations under the License.
// Projects
assert.equal(element._filteredLinks[0].children.length, 1);
assert.isNotOk(element._filteredLinks[0].subsection);
// Groups
assert.equal(element._filteredLinks[1].children.length, 1);
@ -118,6 +124,7 @@ limitations under the License.
// Projects
assert.equal(element._filteredLinks[0].children.length, 0);
assert.isNotOk(element._filteredLinks[0].subsection);
// Groups
assert.equal(element._filteredLinks[1].children.length, 0);
@ -131,8 +138,53 @@ limitations under the License.
// Projects
assert.equal(element._filteredLinks[0].children.length, 0);
assert.isNotOk(element._filteredLinks[0].subsection);
done();
});
});
test('Project shows up in nav', done => {
element._project = 'Test Project';
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
return Promise.resolve({
createGroup: true,
createProject: true,
viewPlugins: true,
});
});
element._loadAccountCapabilities().then(() => {
assert.equal(element._filteredLinks.length, 3);
// Projects
assert.equal(element._filteredLinks[0].children.length, 1);
assert.equal(element._filteredLinks[0].subsection.name, 'Test Project');
// Groups
assert.equal(element._filteredLinks[1].children.length, 1);
// Plugins
assert.equal(element._filteredLinks[2].children.length, 0);
done();
});
});
test('Nav is reloaded when project changes', () => {
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
return Promise.resolve({
createGroup: true,
createProject: true,
viewPlugins: true,
});
});
sandbox.stub(element.$.restAPI, 'getAccount', () => {
return Promise.resolve({_id: 1});
});
sandbox.stub(element, 'reload');
element.params = {project: 'Test Project', adminView: 'gr-admin-project'};
assert.equal(element.reload.callCount, 1);
element.params = {project: 'Test Project 2',
adminView: 'gr-admin-project'};
assert.equal(element.reload.callCount, 2);
});
});
</script>

@ -40,6 +40,9 @@ limitations under the License.
border-top: 1px solid transparent;
padding: 0 2em;
}
#nav ::content li a {
word-break: break-all;
}
#nav ::content .subsectionItem {
padding-left: 3em;
}