Introduce gr-admin-nav-behavior and use in gr-admin-view
gr-admin-nav-behavior will also be used by the main header. For this change, the behavior replaces work previously done in gr-admin-view. In a follow-up change, gr-admin-view will display the current section's options in a gr-dropdown-list and the gr-main-header will display top level admin links in a dropdown menu. Change-Id: Ief0ca439528929f35335309c292512579bb696c3
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
<!--
|
||||
@license
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<script>
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
const ACCOUNT_CAPABILITIES = ['createProject', 'createGroup', 'viewPlugins'];
|
||||
|
||||
const ADMIN_LINKS = [{
|
||||
name: 'Repositories',
|
||||
noBaseUrl: true,
|
||||
url: '/admin/repos',
|
||||
view: 'gr-repo-list',
|
||||
viewableToAll: true,
|
||||
}, {
|
||||
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',
|
||||
}];
|
||||
|
||||
window.Gerrit = window.Gerrit || {};
|
||||
|
||||
/** @polymerBehavior Gerrit.AdminNavBehavior */
|
||||
Gerrit.AdminNavBehavior = {
|
||||
/**
|
||||
* @param {!Object} account
|
||||
* @param {!Function} getAccountCapabilities
|
||||
* @param {!Function} getAdminMenuLinks
|
||||
* Possible aguments in options:
|
||||
* repoName?: string
|
||||
* groupId?: string,
|
||||
* groupName?: string,
|
||||
* groupIsInternal?: boolean,
|
||||
* isAdmin?: boolean,
|
||||
* groupOwner?: boolean,
|
||||
* @param {!Object=} opt_options
|
||||
* @return {Promise<!Object>}
|
||||
*/
|
||||
getAdminLinks(account, getAccountCapabilities, getAdminMenuLinks,
|
||||
opt_options) {
|
||||
if (!account) {
|
||||
return Promise.resolve(this._filterLinks(link => link.viewableToAll,
|
||||
getAdminMenuLinks, opt_options));
|
||||
}
|
||||
return getAccountCapabilities(ACCOUNT_CAPABILITIES)
|
||||
.then(capabilities => {
|
||||
return this._filterLinks(link => {
|
||||
return !link.capability ||
|
||||
capabilities.hasOwnProperty(link.capability);
|
||||
}, getAdminMenuLinks, opt_options);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {!Function} filterFn
|
||||
* @param {!Function} getAdminMenuLinks
|
||||
* Possible aguments in options:
|
||||
* repoName?: string
|
||||
* groupId?: string,
|
||||
* groupName?: string,
|
||||
* groupIsInternal?: boolean,
|
||||
* isAdmin?: boolean,
|
||||
* groupOwner?: boolean,
|
||||
* @param {!Object|undefined} opt_options
|
||||
* @return {Promise<!Object>}
|
||||
*/
|
||||
_filterLinks(filterFn, getAdminMenuLinks, opt_options) {
|
||||
let links = ADMIN_LINKS.slice(0);
|
||||
let expandedSection;
|
||||
|
||||
// Append top-level links that are defined by plugins.
|
||||
links.push(...getAdminMenuLinks().map(link => ({
|
||||
url: link.url,
|
||||
name: link.text,
|
||||
noBaseUrl: link.url[0] === '/',
|
||||
view: null,
|
||||
viewableToAll: true,
|
||||
})));
|
||||
|
||||
links = links.filter(filterFn);
|
||||
|
||||
const filteredLinks = [];
|
||||
const repoName = opt_options && opt_options.repoName;
|
||||
const groupId = opt_options && opt_options.groupId;
|
||||
const groupName = opt_options && opt_options.groupName;
|
||||
const groupIsInternal = opt_options && opt_options.groupIsInternal;
|
||||
const isAdmin = opt_options && opt_options.isAdmin;
|
||||
const groupOwner = opt_options && opt_options.groupOwner;
|
||||
|
||||
// Don't bother to get sub-navigation items if only the top level links
|
||||
// are needed. This is used by the main header dropdown.
|
||||
if (!repoName && !groupId) { return {links, expandedSection}; }
|
||||
|
||||
// Otherwise determine the full set of links and return both the full
|
||||
// set in addition to the subsection that should be displayed if it
|
||||
// exists.
|
||||
for (const link of links) {
|
||||
const linkCopy = Object.assign({}, link);
|
||||
if (linkCopy.name === 'Repositories' && repoName) {
|
||||
linkCopy.subsection = this.getRepoSubsections(repoName);
|
||||
expandedSection = linkCopy.subsection;
|
||||
} else if (linkCopy.name === 'Groups' && groupId && groupName) {
|
||||
linkCopy.subsection = this.getGroupSubsections(groupId, groupName,
|
||||
groupIsInternal, isAdmin, groupOwner);
|
||||
expandedSection = linkCopy.subsection;
|
||||
}
|
||||
filteredLinks.push(linkCopy);
|
||||
}
|
||||
return {links: filteredLinks, expandedSection};
|
||||
},
|
||||
|
||||
getGroupSubsections(groupId, groupName, groupIsInternal, isAdmin,
|
||||
groupOwner) {
|
||||
const subsection = {
|
||||
name: groupName,
|
||||
view: Gerrit.Nav.View.GROUP,
|
||||
url: Gerrit.Nav.getUrlForGroup(groupId),
|
||||
children: [],
|
||||
};
|
||||
if (groupIsInternal) {
|
||||
subsection.children.push({
|
||||
name: 'Members',
|
||||
detailType: Gerrit.Nav.GroupDetailView.MEMBERS,
|
||||
view: Gerrit.Nav.View.GROUP,
|
||||
url: Gerrit.Nav.getUrlForGroupMembers(groupId),
|
||||
});
|
||||
}
|
||||
if (groupIsInternal && (isAdmin || groupOwner)) {
|
||||
subsection.children.push(
|
||||
{
|
||||
name: 'Audit Log',
|
||||
detailType: Gerrit.Nav.GroupDetailView.LOG,
|
||||
view: Gerrit.Nav.View.GROUP,
|
||||
url: Gerrit.Nav.getUrlForGroupLog(groupId),
|
||||
}
|
||||
);
|
||||
}
|
||||
return subsection;
|
||||
},
|
||||
|
||||
getRepoSubsections(repoName) {
|
||||
return {
|
||||
name: repoName,
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
url: Gerrit.Nav.getUrlForRepo(repoName),
|
||||
children: [{
|
||||
name: 'Access',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.ACCESS,
|
||||
url: Gerrit.Nav.getUrlForRepoAccess(repoName),
|
||||
},
|
||||
{
|
||||
name: 'Commands',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.COMMANDS,
|
||||
url: Gerrit.Nav.getUrlForRepoCommands(repoName),
|
||||
},
|
||||
{
|
||||
name: 'Branches',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.BRANCHES,
|
||||
url: Gerrit.Nav.getUrlForRepoBranches(repoName),
|
||||
},
|
||||
{
|
||||
name: 'Tags',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.TAGS,
|
||||
url: Gerrit.Nav.getUrlForRepoTags(repoName),
|
||||
},
|
||||
{
|
||||
name: 'Dashboards',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.DASHBOARDS,
|
||||
url: Gerrit.Nav.getUrlForRepoDashboards(repoName),
|
||||
}],
|
||||
};
|
||||
},
|
||||
};
|
||||
})(window);
|
||||
</script>
|
@@ -0,0 +1,303 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
@license
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>keyboard-shortcut-behavior</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<link rel="import" href="../../test/common-test-setup.html"/>
|
||||
<link rel="import" href="gr-admin-nav-behavior.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<test-element></test-element>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-admin-nav-behavior tests', () => {
|
||||
let element;
|
||||
let sandbox;
|
||||
let capabilityStub;
|
||||
let menuLinkStub;
|
||||
|
||||
suiteSetup(() => {
|
||||
// Define a Polymer element that uses this behavior.
|
||||
Polymer({
|
||||
is: 'test-element',
|
||||
behaviors: [
|
||||
Gerrit.AdminNavBehavior,
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
element = fixture('basic');
|
||||
sandbox = sinon.sandbox.create();
|
||||
capabilityStub = sinon.stub();
|
||||
menuLinkStub = sinon.stub().returns([]);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
const testAdminLinks = (account, options, expected, done) => {
|
||||
element.getAdminLinks(account,
|
||||
capabilityStub,
|
||||
menuLinkStub,
|
||||
options)
|
||||
.then(res => {
|
||||
assert.equal(expected.totalLength, res.links.length);
|
||||
assert.equal(res.links[0].name, 'Repositories');
|
||||
// Repos
|
||||
if (expected.groupListShown) {
|
||||
assert.equal(res.links[1].name, 'Groups');
|
||||
}
|
||||
|
||||
if (expected.pluginListShown) {
|
||||
assert.equal(res.links[2].name, 'Plugins');
|
||||
assert.isNotOk(res.links[2].subsection);
|
||||
}
|
||||
|
||||
if (expected.projectPageShown) {
|
||||
assert.isOk(res.links[0].subsection);
|
||||
assert.equal(res.links[0].subsection.children.length, 5);
|
||||
} else {
|
||||
assert.isNotOk(res.links[0].subsection);
|
||||
}
|
||||
// Groups
|
||||
if (expected.groupPageShown) {
|
||||
assert.isOk(res.links[1].subsection);
|
||||
assert.equal(res.links[1].subsection.children.length,
|
||||
expected.groupSubpageLength);
|
||||
} else if ( expected.totalLength > 1) {
|
||||
assert.isNotOk(res.links[1].subsection);
|
||||
}
|
||||
|
||||
if (expected.pluginGeneratedLinks) {
|
||||
for (const link of expected.pluginGeneratedLinks) {
|
||||
assert.isTrue(!!res.links.find(l => {
|
||||
return (l.url === link.url && l.name === link.text);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Current section
|
||||
if (expected.projectPageShown || expected.groupPageShown) {
|
||||
assert.isOk(res.expandedSection);
|
||||
assert.isOk(res.expandedSection.children);
|
||||
} else {
|
||||
assert.isNotOk(res.expandedSection);
|
||||
}
|
||||
if (expected.projectPageShown) {
|
||||
assert.equal(res.expandedSection.name, 'my-repo');
|
||||
assert.equal(res.expandedSection.children.length, 5);
|
||||
} else if (expected.groupPageShown) {
|
||||
assert.equal(res.expandedSection.name, 'my-group');
|
||||
assert.equal(res.expandedSection.children.length,
|
||||
expected.groupSubpageLength);
|
||||
}
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
suite('logged out', () => {
|
||||
let account;
|
||||
let expected;
|
||||
|
||||
setup(() => {
|
||||
expected = {
|
||||
groupListShown: false,
|
||||
groupPageShown: false,
|
||||
pluginListShown: false,
|
||||
};
|
||||
});
|
||||
|
||||
test('without a specific repo or group', done => {
|
||||
let options;
|
||||
expected = Object.assign(expected, {
|
||||
totalLength: 1,
|
||||
projectPageShown: false,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('with a repo', done => {
|
||||
const options = {repoName: 'my-repo'};
|
||||
expected = Object.assign(expected, {
|
||||
totalLength: 1,
|
||||
projectPageShown: true,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('with plugin generated links', done => {
|
||||
let options;
|
||||
const generatedLinks = [
|
||||
{text: 'internal link text', url: '/internal/link/url'},
|
||||
{text: 'external link text', url: 'http://external/link/url'},
|
||||
];
|
||||
menuLinkStub.returns(generatedLinks);
|
||||
expected = Object.assign(expected, {
|
||||
totalLength: 3,
|
||||
projectPageShown: false,
|
||||
pluginGeneratedLinks: generatedLinks,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('no plugin capability logged in', () => {
|
||||
const account = {
|
||||
name: 'test-user',
|
||||
};
|
||||
let expected;
|
||||
|
||||
setup(() => {
|
||||
expected = {
|
||||
totalLength: 2,
|
||||
pluginListShown: false,
|
||||
};
|
||||
capabilityStub.returns(Promise.resolve({}));
|
||||
});
|
||||
|
||||
test('without a specific project or group', done => {
|
||||
let options;
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: false,
|
||||
groupListShown: true,
|
||||
groupPageShown: false,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('with a repo', done => {
|
||||
const account = {
|
||||
name: 'test-user',
|
||||
};
|
||||
const options = {repoName: 'my-repo'};
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: true,
|
||||
groupListShown: true,
|
||||
groupPageShown: false,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('view plugin capability logged in', () => {
|
||||
const account = {
|
||||
name: 'test-user',
|
||||
};
|
||||
let expected;
|
||||
|
||||
setup(() => {
|
||||
capabilityStub.returns(Promise.resolve({viewPlugins: true}));
|
||||
expected = {
|
||||
totalLength: 3,
|
||||
groupListShown: true,
|
||||
pluginListShown: true,
|
||||
};
|
||||
});
|
||||
|
||||
test('without a specific repo or group', done => {
|
||||
let options;
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: false,
|
||||
groupPageShown: false,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('with a repo', done => {
|
||||
const options = {repoName: 'my-repo'};
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: true,
|
||||
groupPageShown: false,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('admin with internal group', done => {
|
||||
const options = {
|
||||
groupId: 'a15262',
|
||||
groupName: 'my-group',
|
||||
groupIsInternal: true,
|
||||
isAdmin: true,
|
||||
groupOwner: false,
|
||||
};
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: false,
|
||||
groupPageShown: true,
|
||||
groupSubpageLength: 2,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('group owner with internal group', done => {
|
||||
const options = {
|
||||
groupId: 'a15262',
|
||||
groupName: 'my-group',
|
||||
groupIsInternal: true,
|
||||
isAdmin: false,
|
||||
groupOwner: true,
|
||||
};
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: false,
|
||||
groupPageShown: true,
|
||||
groupSubpageLength: 2,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('non owner or admin with internal group', done => {
|
||||
const options = {
|
||||
groupId: 'a15262',
|
||||
groupName: 'my-group',
|
||||
groupIsInternal: true,
|
||||
isAdmin: false,
|
||||
groupOwner: false,
|
||||
};
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: false,
|
||||
groupPageShown: true,
|
||||
groupSubpageLength: 1,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
|
||||
test('admin with external group', done => {
|
||||
const options = {
|
||||
groupId: 'a15262',
|
||||
groupName: 'my-group',
|
||||
groupIsInternal: false,
|
||||
isAdmin: true,
|
||||
groupOwner: true,
|
||||
};
|
||||
expected = Object.assign(expected, {
|
||||
projectPageShown: false,
|
||||
groupPageShown: true,
|
||||
groupSubpageLength: 0,
|
||||
});
|
||||
testAdminLinks(account, options, expected, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
@@ -18,6 +18,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-admin-nav-behavior/gr-admin-nav-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/gr-page-nav-styles.html">
|
||||
|
@@ -17,35 +17,9 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Note: noBaseUrl: true is set on entries where the URL is not yet supported
|
||||
// by router abstraction.
|
||||
const ADMIN_LINKS = [{
|
||||
name: 'Repositories',
|
||||
noBaseUrl: true,
|
||||
url: '/admin/repos',
|
||||
view: 'gr-repo-list',
|
||||
viewableToAll: true,
|
||||
children: [],
|
||||
}, {
|
||||
name: 'Groups',
|
||||
section: 'Groups',
|
||||
noBaseUrl: true,
|
||||
url: '/admin/groups',
|
||||
view: 'gr-admin-group-list',
|
||||
children: [],
|
||||
}, {
|
||||
name: 'Plugins',
|
||||
capability: 'viewPlugins',
|
||||
section: 'Plugins',
|
||||
noBaseUrl: true,
|
||||
url: '/admin/plugins',
|
||||
view: 'gr-plugin-list',
|
||||
}];
|
||||
|
||||
const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
|
||||
|
||||
const ACCOUNT_CAPABILITIES = ['createProject', 'createGroup', 'viewPlugins'];
|
||||
|
||||
Polymer({
|
||||
is: 'gr-admin-view',
|
||||
|
||||
@@ -66,6 +40,7 @@
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_subsectionLinks: Array,
|
||||
_filteredLinks: Array,
|
||||
_showDownload: {
|
||||
type: Boolean,
|
||||
@@ -89,6 +64,7 @@
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AdminNavBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
@@ -108,113 +84,54 @@
|
||||
];
|
||||
return Promise.all(promises).then(result => {
|
||||
this._account = result[0];
|
||||
if (!this._account) {
|
||||
// Return so that account capabilities don't load with no account.
|
||||
return this._filteredLinks = this._filterLinks(link => {
|
||||
return link.viewableToAll;
|
||||
});
|
||||
let options;
|
||||
if (this._repoName) {
|
||||
options = {repoName: this._repoName};
|
||||
} else if (this._groupId) {
|
||||
options = {
|
||||
groupId: this._groupId,
|
||||
groupName: this._groupName,
|
||||
groupIsInternal: this._groupIsInternal,
|
||||
isAdmin: this._isAdmin,
|
||||
groupOwner: this._groupOwner,
|
||||
};
|
||||
}
|
||||
this._loadAccountCapabilities();
|
||||
|
||||
return this.getAdminLinks(this._account,
|
||||
this.$.restAPI.getAccountCapabilities.bind(this.$.restAPI),
|
||||
this.$.jsAPI.getAdminMenuLinks.bind(this.$.jsAPI),
|
||||
options)
|
||||
.then(res => {
|
||||
this._filteredLinks = res.links;
|
||||
|
||||
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 || '',
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_filterLinks(filterFn) {
|
||||
let links = ADMIN_LINKS.slice(0);
|
||||
_handleSubsectionChange(e) {
|
||||
const selected = this._subsectionLinks
|
||||
.find(section => section.value === e.detail.value);
|
||||
|
||||
// Append top-level links that are defined by plugins.
|
||||
links.push(...this.$.jsAPI.getAdminMenuLinks().map(link => ({
|
||||
url: link.url,
|
||||
name: link.text,
|
||||
children: [],
|
||||
noBaseUrl: link.url[0] === '/',
|
||||
view: null,
|
||||
viewableToAll: true,
|
||||
})));
|
||||
|
||||
links = links.filter(filterFn);
|
||||
|
||||
const filteredLinks = [];
|
||||
for (const link of links) {
|
||||
const linkCopy = Object.assign({}, link);
|
||||
linkCopy.children = linkCopy.children ?
|
||||
linkCopy.children.filter(filterFn) : [];
|
||||
if (linkCopy.name === 'Repositories' && this._repoName) {
|
||||
linkCopy.subsection = {
|
||||
name: this._repoName,
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
url: Gerrit.Nav.getUrlForRepo(this._repoName),
|
||||
children: [{
|
||||
name: 'Access',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.ACCESS,
|
||||
url: Gerrit.Nav.getUrlForRepoAccess(this._repoName),
|
||||
},
|
||||
{
|
||||
name: 'Commands',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.COMMANDS,
|
||||
url: Gerrit.Nav.getUrlForRepoCommands(this._repoName),
|
||||
},
|
||||
{
|
||||
name: 'Branches',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.BRANCHES,
|
||||
url: Gerrit.Nav.getUrlForRepoBranches(this._repoName),
|
||||
},
|
||||
{
|
||||
name: 'Tags',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.TAGS,
|
||||
url: Gerrit.Nav.getUrlForRepoTags(this._repoName),
|
||||
},
|
||||
{
|
||||
name: 'Dashboards',
|
||||
view: Gerrit.Nav.View.REPO,
|
||||
detailType: Gerrit.Nav.RepoDetailView.DASHBOARDS,
|
||||
url: Gerrit.Nav.getUrlForRepoDashboards(this._repoName),
|
||||
}],
|
||||
};
|
||||
}
|
||||
if (linkCopy.name === 'Groups' && this._groupId && this._groupName) {
|
||||
linkCopy.subsection = {
|
||||
name: this._groupName,
|
||||
view: Gerrit.Nav.View.GROUP,
|
||||
url: Gerrit.Nav.getUrlForGroup(this._groupId),
|
||||
children: [],
|
||||
};
|
||||
if (this._groupIsInternal) {
|
||||
linkCopy.subsection.children.push({
|
||||
name: 'Members',
|
||||
detailType: Gerrit.Nav.GroupDetailView.MEMBERS,
|
||||
view: Gerrit.Nav.View.GROUP,
|
||||
url: Gerrit.Nav.getUrlForGroupMembers(this._groupId),
|
||||
});
|
||||
}
|
||||
if (this._groupIsInternal && (this._isAdmin || this._groupOwner)) {
|
||||
linkCopy.subsection.children.push(
|
||||
{
|
||||
name: 'Audit Log',
|
||||
detailType: Gerrit.Nav.GroupDetailView.LOG,
|
||||
view: Gerrit.Nav.View.GROUP,
|
||||
url: Gerrit.Nav.getUrlForGroupLog(this._groupId),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
filteredLinks.push(linkCopy);
|
||||
// This is when it gets set initially.
|
||||
if (this._selectedIsCurrentPage(selected)) {
|
||||
return;
|
||||
}
|
||||
return filteredLinks;
|
||||
},
|
||||
|
||||
_loadAccountCapabilities() {
|
||||
return this.$.restAPI.getAccountCapabilities(ACCOUNT_CAPABILITIES)
|
||||
.then(capabilities => {
|
||||
this._filteredLinks = this._filterLinks(link => {
|
||||
return !link.capability ||
|
||||
capabilities.hasOwnProperty(link.capability);
|
||||
});
|
||||
});
|
||||
Gerrit.Nav.navigateToRelativeUrl(selected.url);
|
||||
},
|
||||
|
||||
_paramsChanged(params) {
|
||||
@@ -260,6 +177,10 @@
|
||||
}
|
||||
},
|
||||
|
||||
_computeSelectedTitle(params) {
|
||||
return this.getSelectedTitle(params.view);
|
||||
},
|
||||
|
||||
// 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).
|
||||
|
@@ -95,6 +95,9 @@ limitations under the License.
|
||||
});
|
||||
|
||||
test('_filteredLinks admin', done => {
|
||||
sandbox.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
|
||||
name: 'test-user',
|
||||
}));
|
||||
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
|
||||
return Promise.resolve({
|
||||
createGroup: true,
|
||||
@@ -102,35 +105,36 @@ limitations under the License.
|
||||
viewPlugins: true,
|
||||
});
|
||||
});
|
||||
element._loadAccountCapabilities().then(() => {
|
||||
element.reload().then(() => {
|
||||
assert.equal(element._filteredLinks.length, 3);
|
||||
|
||||
// Repos
|
||||
assert.equal(element._filteredLinks[0].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[0].subsection);
|
||||
|
||||
// Groups
|
||||
assert.equal(element._filteredLinks[1].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[0].subsection);
|
||||
|
||||
// Plugins
|
||||
assert.equal(element._filteredLinks[2].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[0].subsection);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('_filteredLinks non admin authenticated', done => {
|
||||
sandbox.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
|
||||
name: 'test-user',
|
||||
}));
|
||||
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
|
||||
return Promise.resolve({});
|
||||
});
|
||||
element._loadAccountCapabilities().then(() => {
|
||||
element.reload().then(() => {
|
||||
assert.equal(element._filteredLinks.length, 2);
|
||||
|
||||
// Repos
|
||||
assert.equal(element._filteredLinks[0].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[0].subsection);
|
||||
|
||||
// Groups
|
||||
assert.equal(element._filteredLinks[1].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[0].subsection);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -140,7 +144,6 @@ limitations under the License.
|
||||
assert.equal(element._filteredLinks.length, 1);
|
||||
|
||||
// Repos
|
||||
assert.equal(element._filteredLinks[0].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[0].subsection);
|
||||
done();
|
||||
});
|
||||
@@ -156,7 +159,6 @@ limitations under the License.
|
||||
assert.deepEqual(element._filteredLinks[1], {
|
||||
url: '/internal/link/url',
|
||||
name: 'internal link text',
|
||||
children: [],
|
||||
noBaseUrl: true,
|
||||
view: null,
|
||||
viewableToAll: true,
|
||||
@@ -164,7 +166,6 @@ limitations under the License.
|
||||
assert.deepEqual(element._filteredLinks[2], {
|
||||
url: 'http://external/link/url',
|
||||
name: 'external link text',
|
||||
children: [],
|
||||
noBaseUrl: false,
|
||||
view: null,
|
||||
viewableToAll: true,
|
||||
@@ -174,6 +175,9 @@ limitations under the License.
|
||||
|
||||
test('Repo shows up in nav', done => {
|
||||
element._repoName = 'Test Repo';
|
||||
sandbox.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
|
||||
name: 'test-user',
|
||||
}));
|
||||
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
|
||||
return Promise.resolve({
|
||||
createGroup: true,
|
||||
@@ -181,18 +185,52 @@ limitations under the License.
|
||||
viewPlugins: true,
|
||||
});
|
||||
});
|
||||
element._loadAccountCapabilities().then(() => {
|
||||
element.reload().then(() => {
|
||||
flushAsynchronousOperations();
|
||||
assert.equal(element._filteredLinks.length, 3);
|
||||
|
||||
// Repos
|
||||
assert.equal(element._filteredLinks[0].children.length, 0);
|
||||
assert.equal(element._filteredLinks[0].subsection.children.length, 5);
|
||||
assert.equal(element._filteredLinks[0].subsection.name, 'Test Repo');
|
||||
|
||||
// Groups
|
||||
assert.equal(element._filteredLinks[1].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[1].subsection);
|
||||
|
||||
// Plugins
|
||||
assert.equal(element._filteredLinks[2].children.length, 0);
|
||||
assert.isNotOk(element._filteredLinks[2].subsection);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('Group shows up in nav', done => {
|
||||
element._groupId = 'a15262';
|
||||
element._groupName = 'my-group';
|
||||
element._groupIsInternal = true;
|
||||
element._isAdmin = true;
|
||||
element._groupOwner = false;
|
||||
sandbox.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
|
||||
name: 'test-user',
|
||||
}));
|
||||
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
|
||||
return Promise.resolve({
|
||||
createGroup: true,
|
||||
createProject: true,
|
||||
viewPlugins: true,
|
||||
});
|
||||
});
|
||||
element.reload().then(() => {
|
||||
flushAsynchronousOperations();
|
||||
assert.equal(element._filteredLinks.length, 3);
|
||||
|
||||
// Repos
|
||||
assert.isNotOk(element._filteredLinks[0].subsection);
|
||||
|
||||
// Groups
|
||||
assert.equal(element._filteredLinks[1].subsection.children.length, 2);
|
||||
assert.equal(element._filteredLinks[1].subsection.name, 'my-group');
|
||||
|
||||
// Plugins
|
||||
assert.isNotOk(element._filteredLinks[2].subsection);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@@ -196,6 +196,7 @@ limitations under the License.
|
||||
'keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html',
|
||||
'rest-client-behavior/rest-client-behavior_test.html',
|
||||
'gr-access-behavior/gr-access-behavior_test.html',
|
||||
'gr-admin-nav-behavior/gr-admin-nav-behavior_test.html',
|
||||
'gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html',
|
||||
'gr-change-table-behavior/gr-change-table-behavior_test.html',
|
||||
'gr-patch-set-behavior/gr-patch-set-behavior_test.html',
|
||||
|
Reference in New Issue
Block a user