Rename projects admin interface to repo

This also includes backwards compatibility with the old /projects/ url.

This only renames it for the admin interface. It does not rename it for
changes or anything else.

Bug: Issue 7754
Change-Id: Ia31d3f26871556729fb3c5b5b28ceca12da1ec7c
This commit is contained in:
Paladox none 2017-11-16 18:54:02 +00:00
parent aeeba877f7
commit 2bd5c217d0
49 changed files with 758 additions and 727 deletions

View File

@ -224,15 +224,15 @@ Note: TODO
Note: TODO
[plugin-project]
=== project
`plugin.project()`
[plugin-repo]
=== repo
`plugin.repo()`
.Params:
- none
.Returns:
- Instance of link:pg-plugin-project-api.html[GrProjectApi].
- Instance of link:pg-plugin-repo-api.html[GrRepoApi].
=== put
`plugin.put(url, payload, opt_callback)`

View File

@ -1,36 +0,0 @@
= Gerrit Code Review - Project admin customization API
This API is provided by link:pg-plugin-dev.html#plugin-project[plugin.project()]
and provides customization to admin page.
== createCommand
`projectApi.createCommand(title, checkVisibleCallback)`
Create a project command in the admin panel.
.Params
- *title* String title.
- *checkVisibleCallback* function to configure command visibility.
.Returns
- GrProjectApi for chaining.
`checkVisibleCallback(projectName, projectConfig)`
.Params
- *projectName* String project name.
- *projectConfig* Object REST API response for project config.
.Returns
- `false` to hide the command for the specific project.
== onTap
`projectApi.onTap(tapCalback)`
Add a command tap callback.
.Params
- *tapCallback* function that's excuted on command tap.
.Returns
- Nothing

View File

@ -0,0 +1,36 @@
= Gerrit Code Review - Repo admin customization API
This API is provided by link:pg-plugin-dev.html#plugin-repo[plugin.repo()]
and provides customization to admin page.
== createCommand
`repoApi.createCommand(title, checkVisibleCallback)`
Create a repo command in the admin panel.
.Params
- *title* String title.
- *checkVisibleCallback* function to configure command visibility.
.Returns
- GrRepoApi for chaining.
`checkVisibleCallback(repoName, repoConfig)`
.Params
- *repoName* String project name.
- *repoConfig* Object REST API response for repo config.
.Returns
- `false` to hide the command for the specific project.
== onTap
`repoApi.onTap(tapCalback)`
Add a command tap callback.
.Params
- *tapCallback* function that's excuted on command tap.
.Returns
- Nothing

View File

@ -29,11 +29,11 @@ limitations under the License.
<link rel="import" href="../gr-group-audit-log/gr-group-audit-log.html">
<link rel="import" href="../gr-group-members/gr-group-members.html">
<link rel="import" href="../gr-plugin-list/gr-plugin-list.html">
<link rel="import" href="../gr-project/gr-project.html">
<link rel="import" href="../gr-project-access/gr-project-access.html">
<link rel="import" href="../gr-project-commands/gr-project-commands.html">
<link rel="import" href="../gr-project-detail-list/gr-project-detail-list.html">
<link rel="import" href="../gr-project-list/gr-project-list.html">
<link rel="import" href="../gr-repo/gr-repo.html">
<link rel="import" href="../gr-repo-access/gr-repo-access.html">
<link rel="import" href="../gr-repo-commands/gr-repo-commands.html">
<link rel="import" href="../gr-repo-detail-list/gr-repo-detail-list.html">
<link rel="import" href="../gr-repo-list/gr-repo-list.html">
<dom-module id="gr-admin-view">
<template>
@ -71,14 +71,14 @@ limitations under the License.
</template>
</ul>
</gr-page-nav>
<template is="dom-if" if="[[_showProjectList]]" restamp="true">
<template is="dom-if" if="[[_showRepoList]]" restamp="true">
<main class="table">
<gr-project-list class="table" params="[[params]]"></gr-project-list>
<gr-repo-list class="table" params="[[params]]"></gr-repo-list>
</main>
</template>
<template is="dom-if" if="[[_showProjectMain]]" restamp="true">
<template is="dom-if" if="[[_showRepoMain]]" restamp="true">
<main>
<gr-project project="[[params.project]]"></gr-project>
<gr-repo repo="[[params.repo]]"></gr-repo>
</main>
</template>
<template is="dom-if" if="[[_showGroup]]" restamp="true">
@ -105,11 +105,11 @@ limitations under the License.
<gr-plugin-list class="table" params="[[params]]"></gr-plugin-list>
</main>
</template>
<template is="dom-if" if="[[_showProjectDetailList]]" restamp="true">
<template is="dom-if" if="[[_showRepoDetailList]]" restamp="true">
<main class="table">
<gr-project-detail-list
<gr-repo-detail-list
params="[[params]]"
class="table"></gr-project-detail-list>
class="table"></gr-repo-detail-list>
</main>
</template>
<template is="dom-if" if="[[_showGroupAuditLog]]" restamp="true">
@ -119,17 +119,17 @@ limitations under the License.
class="table"></gr-group-audit-log>
</main>
</template>
<template is="dom-if" if="[[_showProjectCommands]]" restamp="true">
<template is="dom-if" if="[[_showRepoCommands]]" restamp="true">
<main>
<gr-project-commands
project="[[params.project]]"></gr-project-commands>
<gr-repo-commands
repo="[[params.repo]]"></gr-repo-commands>
</main>
</template>
<template is="dom-if" if="[[_showProjectAccess]]" restamp="true">
<template is="dom-if" if="[[_showRepoAccess]]" restamp="true">
<main class="table">
<gr-project-access
<gr-repo-access
path="[[path]]"
project="[[params.project]]"></gr-project-access>
repo="[[params.repo]]"></gr-repo-access>
</main>
</template>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>

View File

@ -17,10 +17,10 @@
// Note: noBaseUrl: true is set on entries where the URL is not yet supported
// by router abstraction.
const ADMIN_LINKS = [{
name: 'Projects',
name: 'Repositories',
noBaseUrl: true,
url: '/admin/projects',
view: 'gr-project-list',
url: '/admin/repos',
view: 'gr-repo-list',
viewableToAll: true,
children: [],
}, {
@ -50,7 +50,7 @@
path: String,
adminView: String,
_projectName: String,
_repoName: String,
_groupId: {
type: Number,
observer: '_computeGroupName',
@ -73,12 +73,12 @@
_showGroupAuditLog: Boolean,
_showGroupList: Boolean,
_showGroupMembers: Boolean,
_showProjectCommands: Boolean,
_showProjectMain: Boolean,
_showProjectList: Boolean,
_showProjectDetailList: Boolean,
_showRepoAccess: Boolean,
_showRepoCommands: Boolean,
_showRepoDetailList: Boolean,
_showRepoMain: Boolean,
_showRepoList: Boolean,
_showPluginList: Boolean,
_showProjectAccess: Boolean,
},
behaviors: [
@ -114,43 +114,43 @@
const linkCopy = Object.assign({}, link);
linkCopy.children = linkCopy.children ?
linkCopy.children.filter(filterFn) : [];
if (linkCopy.name === 'Projects' && this._projectName) {
if (linkCopy.name === 'Repositories' && this._repoName) {
linkCopy.subsection = {
name: this._projectName,
view: 'gr-project',
name: this._repoName,
view: 'gr-repo',
noBaseUrl: true,
url: `/admin/projects/${this.encodeURL(this._projectName, true)}`,
url: `/admin/repos/${this.encodeURL(this._repoName, true)}`,
children: [{
name: 'Access',
detailType: 'access',
view: 'gr-project-access',
view: 'gr-repo-access',
noBaseUrl: true,
url: `/admin/projects/` +
`${this.encodeURL(this._projectName, true)},access`,
url: `/admin/repos/` +
`${this.encodeURL(this._repoName, true)},access`,
},
{
name: 'Commands',
detailType: 'commands',
view: 'gr-project-commands',
view: 'gr-repo-commands',
noBaseUrl: true,
url: `/admin/projects/` +
`${this.encodeURL(this._projectName, true)},commands`,
url: `/admin/repos/` +
`${this.encodeURL(this._repoName, true)},commands`,
},
{
name: 'Branches',
detailType: 'branches',
view: 'gr-project-detail-list',
view: 'gr-repo-detail-list',
noBaseUrl: true,
url: `/admin/projects/` +
`${this.encodeURL(this._projectName, true)},branches`,
url: `/admin/repos/` +
`${this.encodeURL(this._repoName, true)},branches`,
},
{
name: 'Tags',
detailType: 'tags',
view: 'gr-project-detail-list',
view: 'gr-repo-detail-list',
noBaseUrl: true,
url: `/admin/projects/` +
`${this.encodeURL(this._projectName, true)},tags`,
url: `/admin/repos/` +
`${this.encodeURL(this._repoName, true)},tags`,
}],
};
}
@ -207,21 +207,21 @@
this.set('_showGroupList', isAdminView &&
params.adminView === 'gr-admin-group-list');
this.set('_showProjectCommands', isAdminView &&
params.adminView === 'gr-project-commands');
this.set('_showProjectMain', isAdminView &&
params.adminView === 'gr-project');
this.set('_showProjectList', isAdminView &&
params.adminView === 'gr-project-list');
this.set('_showProjectDetailList', isAdminView &&
params.adminView === 'gr-project-detail-list');
this.set('_showRepoAccess', isAdminView &&
params.adminView === 'gr-repo-access');
this.set('_showRepoCommands', isAdminView &&
params.adminView === 'gr-repo-commands');
this.set('_showRepoDetailList', isAdminView &&
params.adminView === 'gr-repo-detail-list');
this.set('_showRepoMain', isAdminView &&
params.adminView === 'gr-repo');
this.set('_showRepoList', isAdminView &&
params.adminView === 'gr-repo-list');
this.set('_showPluginList', isAdminView &&
params.adminView === 'gr-plugin-list');
this.set('_showProjectAccess', isAdminView &&
params.adminView === 'gr-project-access');
if (params.project !== this._projectName) {
this._projectName = params.project || '';
if (params.repo !== this._repoName) {
this._repoName = params.repo || '';
// Reloads the admin menu.
this.reload();
}

View File

@ -74,22 +74,22 @@ limitations under the License.
test('current page gets selected and is displayed', () => {
element._filteredLinks = [{
name: 'Projects',
url: '/admin/projects',
view: 'gr-project-list',
name: 'Repositories',
url: '/admin/repos',
view: 'gr-repo-list',
children: [],
}];
element.params = {
view: 'admin',
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
};
flushAsynchronousOperations();
assert.equal(Polymer.dom(element.root).querySelectorAll(
'.selected').length, 1);
assert.ok(element.$$('gr-project-list'));
assert.isNotOk(element.$$('gr-admin-create-project'));
assert.ok(element.$$('gr-repo-list'));
assert.isNotOk(element.$$('gr-admin-create-repo'));
});
test('_filteredLinks admin', done => {
@ -103,7 +103,7 @@ limitations under the License.
element._loadAccountCapabilities().then(() => {
assert.equal(element._filteredLinks.length, 3);
// Projects
// Repos
assert.equal(element._filteredLinks[0].children.length, 0);
assert.isNotOk(element._filteredLinks[0].subsection);
@ -123,7 +123,7 @@ limitations under the License.
element._loadAccountCapabilities().then(() => {
assert.equal(element._filteredLinks.length, 2);
// Projects
// Repos
assert.equal(element._filteredLinks[0].children.length, 0);
assert.isNotOk(element._filteredLinks[0].subsection);
@ -137,15 +137,15 @@ limitations under the License.
element.reload().then(() => {
assert.equal(element._filteredLinks.length, 1);
// Projects
// Repos
assert.equal(element._filteredLinks[0].children.length, 0);
assert.isNotOk(element._filteredLinks[0].subsection);
done();
});
});
test('Project shows up in nav', done => {
element._projectName = 'Test Project';
test('Repo shows up in nav', done => {
element._repoName = 'Test Repo';
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
return Promise.resolve({
createGroup: true,
@ -156,9 +156,9 @@ limitations under the License.
element._loadAccountCapabilities().then(() => {
assert.equal(element._filteredLinks.length, 3);
// Projects
// Repos
assert.equal(element._filteredLinks[0].children.length, 0);
assert.equal(element._filteredLinks[0].subsection.name, 'Test Project');
assert.equal(element._filteredLinks[0].subsection.name, 'Test Repo');
// Groups
assert.equal(element._filteredLinks[1].children.length, 0);
@ -169,7 +169,7 @@ limitations under the License.
});
});
test('Nav is reloaded when project changes', () => {
test('Nav is reloaded when repo changes', () => {
sandbox.stub(element.$.restAPI, 'getAccountCapabilities', () => {
return Promise.resolve({
createGroup: true,
@ -181,10 +181,10 @@ limitations under the License.
return Promise.resolve({_id: 1});
});
sandbox.stub(element, 'reload');
element.params = {project: 'Test Project', adminView: 'gr-project'};
element.params = {repo: 'Test Repo', adminView: 'gr-repo'};
assert.equal(element.reload.callCount, 1);
element.params = {project: 'Test Project 2',
adminView: 'gr-project'};
element.params = {repo: 'Test Repo 2',
adminView: 'gr-repo'};
assert.equal(element.reload.callCount, 2);
});
@ -235,34 +235,34 @@ limitations under the License.
return element.reload();
});
suite('projects', () => {
suite('repos', () => {
setup(() => {
stub('gr-project-access', {
_projectChanged: () => {},
stub('gr-repo-access', {
_repoChanged: () => {},
});
});
test('project list', done => {
test('repo list', done => {
element.params = {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
openCreateModal: false,
};
flush(() => {
const selected = element.$$('gr-page-nav .selected');
assert.isOk(selected);
assert.equal(selected.textContent.trim(), 'Projects');
assert.equal(selected.textContent.trim(), 'Repositories');
done();
});
});
test('project', done => {
test('repo', done => {
element.params = {
view: Gerrit.Nav.View.ADMIN,
project: 'foo',
adminView: 'gr-project',
adminView: 'gr-repo',
};
element._projectName = 'foo';
element._repoName = 'foo';
element.reload().then(() => {
flush(() => {
const selected = element.$$('gr-page-nav .selected');
@ -273,14 +273,14 @@ limitations under the License.
});
});
test('project access', done => {
test('repo access', done => {
element.params = {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-access',
adminView: 'gr-repo-access',
detailType: 'access',
project: 'foo',
repo: 'foo',
};
element._projectName = 'foo';
element._repoName = 'foo';
element.reload().then(() => {
flush(() => {
const selected = element.$$('gr-page-nav .selected');

View File

@ -90,7 +90,7 @@ limitations under the License.
<input
type="checkbox"
id="privateChangeCheckBox"
checked$="[[_projectConfig.private_by_default.inherited_value]]">
checked$="[[_repoConfig.private_by_default.inherited_value]]">
</section>
<section>
<label for="wipChangeCheckBox">WIP Change</label>

View File

@ -21,16 +21,16 @@
is: 'gr-create-change-dialog',
properties: {
projectName: String,
repoName: String,
branch: String,
/** @type {?} */
_projectConfig: Object,
_repoConfig: Object,
subject: String,
topic: String,
_query: {
type: Function,
value() {
return this._getProjectBranchesSuggestions.bind(this);
return this._getRepoBranchesSuggestions.bind(this);
},
},
canCreate: {
@ -46,8 +46,8 @@
],
attached() {
this.$.restAPI.getProjectConfig(this.projectName).then(config => {
this._projectConfig = config;
this.$.restAPI.getProjectConfig(this.repoName).then(config => {
this._repoConfig = config;
});
},
@ -62,7 +62,7 @@
handleCreateChange() {
const isPrivate = this.$.privateChangeCheckBox.checked;
const isWip = this.$.wipChangeCheckBox.checked;
return this.$.restAPI.createChange(this.projectName, this.branch,
return this.$.restAPI.createChange(this.repoName, this.branch,
this.subject, this.topic, isPrivate, isWip)
.then(changeCreated => {
if (!changeCreated) {
@ -72,12 +72,12 @@
});
},
_getProjectBranchesSuggestions(input) {
_getRepoBranchesSuggestions(input) {
if (input.startsWith(REF_PREFIX)) {
input = input.substring(REF_PREFIX.length);
}
return this.$.restAPI.getProjectBranches(
input, this.projectName, SUGGESTIONS_LIMIT).then(response => {
return this.$.restAPI.getRepoBranches(
input, this.repoName, SUGGESTIONS_LIMIT).then(response => {
const branches = [];
let branch;
for (const key in response) {

View File

@ -40,7 +40,7 @@ limitations under the License.
sandbox = sinon.sandbox.create();
stub('gr-rest-api-interface', {
getLoggedIn() { return Promise.resolve(true); },
getProjectBranches(input) {
getRepoBranches(input) {
if (input.startsWith('test')) {
return Promise.resolve([
{
@ -55,8 +55,8 @@ limitations under the License.
},
});
element = fixture('basic');
element.projectName = 'test-project';
element._projectConfig = {
element.repoName = 'test-repo';
element._repoConfig = {
private_by_default: {},
};
});
@ -66,7 +66,7 @@ limitations under the License.
});
test('new change created with private', () => {
element._projectConfig = {
element._repoConfig = {
private_by_default: {
inherited_value: true,
},
@ -77,7 +77,6 @@ limitations under the License.
topic: 'test-topic',
subject: 'first change created with polygerrit ui',
work_in_progress: false,
project: element.projectName,
};
const saveStub = sandbox.stub(element.$.restAPI,
@ -85,7 +84,6 @@ limitations under the License.
return Promise.resolve({});
});
element.project = element.projectName;
element.branch = 'test-branch';
element.topic = 'test-topic';
element.subject = 'first change created with polygerrit ui';
@ -105,7 +103,6 @@ limitations under the License.
branch: 'test-branch',
topic: 'test-topic',
subject: 'first change created with polygerrit ui',
project: element.projectName,
};
const saveStub = sandbox.stub(element.$.restAPI,
@ -113,7 +110,6 @@ limitations under the License.
return Promise.resolve({});
});
element.project = element.projectName;
element.branch = 'test-branch';
element.topic = 'test-topic';
element.subject = 'first change created with polygerrit ui';
@ -129,15 +125,15 @@ limitations under the License.
});
});
test('_getProjectBranchesSuggestions empty', done => {
element._getProjectBranchesSuggestions('nonexistent').then(branches => {
test('_getRepoBranchesSuggestions empty', done => {
element._getRepoBranchesSuggestions('nonexistent').then(branches => {
assert.equal(branches.length, 0);
done();
});
});
test('_getProjectBranchesSuggestions non-empty', done => {
element._getProjectBranchesSuggestions('test-branch').then(branches => {
test('_getRepoBranchesSuggestions non-empty', done => {
element._getRepoBranchesSuggestions('test-branch').then(branches => {
assert.equal(branches.length, 1);
assert.equal(branches[0].name, 'test-branch');
done();

View File

@ -24,7 +24,7 @@
properties: {
detailType: String,
projectName: String,
repoName: String,
hasNewItemName: {
type: Boolean,
notify: true,
@ -51,18 +51,18 @@
_computeItemUrl(project) {
if (this.itemDetail === DETAIL_TYPES.branches) {
return this.getBaseUrl() + '/admin/projects/' +
this.encodeURL(this.projectName, true) + ',branches';
return this.getBaseUrl() + '/admin/repos/' +
this.encodeURL(this.repoName, true) + ',branches';
} else if (this.itemDetail === DETAIL_TYPES.tags) {
return this.getBaseUrl() + '/admin/projects/' +
this.encodeURL(this.projectName, true) + ',tags';
return this.getBaseUrl() + '/admin/repos/' +
this.encodeURL(this.repoName, true) + ',tags';
}
},
handleCreateItem() {
const USE_HEAD = this._itemRevision ? this._itemRevision : 'HEAD';
if (this.itemDetail === DETAIL_TYPES.branches) {
return this.$.restAPI.createProjectBranch(this.projectName,
return this.$.restAPI.createRepoBranch(this.repoName,
this._itemName, {revision: USE_HEAD})
.then(itemRegistered => {
if (itemRegistered.status === 201) {
@ -70,7 +70,7 @@
}
});
} else if (this.itemDetail === DETAIL_TYPES.tags) {
return this.$.restAPI.createProjectTag(this.projectName,
return this.$.restAPI.createRepoTag(this.repoName,
this._itemName,
{revision: USE_HEAD, message: this._itemAnnotation || null})
.then(itemRegistered => {

View File

@ -49,7 +49,7 @@ limitations under the License.
});
test('branch created', () => {
sandbox.stub(element.$.restAPI, 'createProjectBranch', () => {
sandbox.stub(element.$.restAPI, 'createRepoBranch', () => {
return Promise.resolve({});
});
@ -69,7 +69,7 @@ limitations under the License.
});
test('tag created', () => {
sandbox.stub(element.$.restAPI, 'createProjectTag', () => {
sandbox.stub(element.$.restAPI, 'createRepoTag', () => {
return Promise.resolve({});
});
@ -89,7 +89,7 @@ limitations under the License.
});
test('tag created with annotations', () => {
sandbox.stub(element.$.restAPI, 'createProjectTag', () => {
sandbox.stub(element.$.restAPI, 'createRepoTag', () => {
return Promise.resolve({});
});

View File

@ -26,7 +26,7 @@ limitations under the License.
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../shared/gr-select/gr-select.html">
<dom-module id="gr-create-project-dialog">
<dom-module id="gr-create-repo-dialog">
<template>
<style include="shared-styles"></style>
<style include="gr-form-styles">
@ -52,18 +52,18 @@ limitations under the License.
<div class="gr-form-styles">
<div id="form">
<section>
<span class="title">Project name</span>
<span class="title">Repositories name</span>
<input is="iron-input"
id="projectNameInput"
id="repoNameInput"
autocomplete="on"
bind-value="{{_projectConfig.name}}">
bind-value="{{_repoConfig.name}}">
</section>
<section>
<span class="title">Rights inherit from</span>
<span class="value">
<gr-autocomplete
id="rightsInheritFromInput"
text="{{_projectConfig.parent}}"
text="{{_repoConfig.parent}}"
query="[[_query]]"
placeholder="Optional, defaults to 'All-Projects'">
</gr-autocomplete>
@ -74,7 +74,7 @@ limitations under the License.
<span class="value">
<gr-select
id="initalCommit"
bind-value="{{_projectConfig.create_empty_commit}}">
bind-value="{{_repoConfig.create_empty_commit}}">
<select>
<option value="false">False</option>
<option value="true">True</option>
@ -83,12 +83,12 @@ limitations under the License.
</span>
</section>
<section>
<span class="title">Only serve as parent for other projects</span>
<span class="title">Only serve as parent for other repositories</span>
<span class="value">
<gr-select
id="parentProject"
id="parentRepo"
is="gr-select"
bind-value="{{_projectConfig.permissions_only}}">
bind-value="{{_repoConfig.permissions_only}}">
<select>
<option value="false">False</option>
<option value="true">True</option>
@ -100,5 +100,5 @@ limitations under the License.
</div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-create-project-dialog.js"></script>
<script src="gr-create-repo-dialog.js"></script>
</dom-module>

View File

@ -15,18 +15,18 @@
'use strict';
Polymer({
is: 'gr-create-project-dialog',
is: 'gr-create-repo-dialog',
properties: {
params: Object,
hasNewProjectName: {
hasNewRepoName: {
type: Boolean,
notify: true,
value: false,
},
/** @type {?} */
_projectConfig: {
_repoConfig: {
type: Object,
value: () => {
// Set default values for dropdowns.
@ -36,7 +36,7 @@
};
},
},
_projectCreated: {
_repoCreated: {
type: Boolean,
value: false,
},
@ -44,13 +44,13 @@
_query: {
type: Function,
value() {
return this._getProjectSuggestions.bind(this);
return this._getRepoSuggestions.bind(this);
},
},
},
observers: [
'_updateProjectName(_projectConfig.name)',
'_updateRepoName(_repoConfig.name)',
],
behaviors: [
@ -58,37 +58,37 @@
Gerrit.URLEncodingBehavior,
],
_computeProjectUrl(projectName) {
return this.getBaseUrl() + '/admin/projects/' +
this.encodeURL(projectName, true);
_computeRepoUrl(repoName) {
return this.getBaseUrl() + '/admin/repos/' +
this.encodeURL(repoName, true);
},
_updateProjectName(name) {
this.hasNewProjectName = !!name;
_updateRepoName(name) {
this.hasNewRepoName = !!name;
},
handleCreateProject() {
return this.$.restAPI.createProject(this._projectConfig)
.then(projectRegistered => {
if (projectRegistered.status === 201) {
this._projectCreated = true;
page.show(this._computeProjectUrl(this._projectConfig.name));
handleCreateRepo() {
return this.$.restAPI.createRepo(this._repoConfig)
.then(repoRegistered => {
if (repoRegistered.status === 201) {
this._repoCreated = true;
page.show(this._computeRepoUrl(this._repoConfig.name));
}
});
},
_getProjectSuggestions(input) {
_getRepoSuggestions(input) {
return this.$.restAPI.getSuggestedProjects(input)
.then(response => {
const projects = [];
const repos = [];
for (const key in response) {
if (!response.hasOwnProperty(key)) { continue; }
projects.push({
repos.push({
name: key,
value: response[key],
});
}
return projects;
return repos;
});
},
});

View File

@ -16,23 +16,23 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-create-project-dialog</title>
<title>gr-create-repo-dialog</title>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-create-project-dialog.html">
<link rel="import" href="gr-create-repo-dialog.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-create-project-dialog></gr-create-project-dialog>
<gr-create-repo-dialog></gr-create-repo-dialog>
</template>
</test-fixture>
<script>
suite('gr-create-project-dialog tests', () => {
suite('gr-create-repo-dialog tests', () => {
let element;
let sandbox;
@ -50,43 +50,43 @@ limitations under the License.
test('default values are populated', () => {
assert.isFalse(element.$.initalCommit.bindValue);
assert.isFalse(element.$.parentProject.bindValue);
assert.isFalse(element.$.parentRepo.bindValue);
});
test('project created', done => {
test('repo created', done => {
const configInputObj = {
name: 'test-project',
name: 'test-repo',
create_empty_commit: true,
parent: 'All-Project',
permissions_only: false,
};
const saveStub = sandbox.stub(element.$.restAPI,
'createProject', () => {
'createRepo', () => {
return Promise.resolve({});
});
assert.isFalse(element.hasNewProjectName);
assert.isFalse(element.hasNewRepoName);
element._projectConfig = {
name: 'test-project',
element._repoConfig = {
name: 'test-repo',
create_empty_commit: true,
parent: 'All-Project',
permissions_only: false,
};
element.$.projectNameInput.bindValue = configInputObj.name;
element.$.repoNameInput.bindValue = configInputObj.name;
element.$.rightsInheritFromInput.bindValue = configInputObj.parent;
element.$.initalCommit.bindValue =
configInputObj.create_empty_commit;
element.$.parentProject.bindValue =
element.$.parentRepo.bindValue =
configInputObj.permissions_only;
assert.isTrue(element.hasNewProjectName);
assert.isTrue(element.hasNewRepoName);
assert.deepEqual(element._projectConfig, configInputObj);
assert.deepEqual(element._repoConfig, configInputObj);
element.handleCreateProject().then(() => {
element.handleCreateRepo().then(() => {
assert.isTrue(saveStub.lastCall.calledWithExactly(configInputObj));
done();
});

View File

@ -28,7 +28,7 @@ limitations under the License.
<script src="../../../scripts/util.js"></script>
<dom-module id="gr-project-access">
<dom-module id="gr-repo-access">
<template>
<style include="shared-styles">
.gwtLink {
@ -82,5 +82,5 @@ limitations under the License.
</main>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-project-access.js"></script>
<script src="gr-repo-access.js"></script>
</dom-module>

View File

@ -56,12 +56,12 @@
Polymer({
is: 'gr-project-access',
is: 'gr-repo-access',
properties: {
project: {
repo: {
type: String,
observer: '_projectChanged',
observer: '_repoChanged',
},
// The current path
path: String,
@ -148,15 +148,15 @@
},
/**
* @param {string} project
* @param {string} repo
* @return {!Promise}
*/
_projectChanged(project) {
if (!project) { return Promise.resolve(); }
_repoChanged(repo) {
if (!repo) { return Promise.resolve(); }
const promises = [];
// Always reset sections when a project changes.
this._sections = [];
promises.push(this.$.restAPI.getProjectAccessRights(project).then(res => {
promises.push(this.$.restAPI.getRepoAccessRights(repo).then(res => {
this._inheritsFrom = res.inherits_from;
this._local = res.local;
this._groups = res.groups;
@ -167,7 +167,7 @@
return res;
}));
promises.push(this.$.restAPI.getProject(project).then(res => {
promises.push(this.$.restAPI.getRepo(repo).then(res => {
return res.labels;
}));
@ -296,9 +296,9 @@
return isAdmin ? 'admin' : '';
},
_computeParentHref(projectName) {
_computeParentHref(repoName) {
return this.getBaseUrl() +
`/admin/projects/${this.encodeURL(projectName, true)},access`;
`/admin/repos/${this.encodeURL(repoName, true)},access`;
},
});
})();

View File

@ -16,24 +16,24 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project-access</title>
<title>gr-repo-access</title>
<script src="../../../bower_components/page/page.js"></script>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-project-access.html">
<link rel="import" href="gr-repo-access.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-project-access></gr-project-access>
<gr-repo-access></gr-repo-access>
</template>
</test-fixture>
<script>
suite('gr-project-access tests', () => {
suite('gr-repo-access tests', () => {
let element;
let sandbox;
@ -71,12 +71,12 @@ limitations under the License.
},
},
};
const projectRes = {
const repoRes = {
labels: {
'Code-Review': {},
},
};
const projectAccessInput = {
const repoAccessInput = {
add: {
'refs/*': {
permissions: {
@ -110,13 +110,13 @@ limitations under the License.
sandbox.restore();
});
test('_projectChanged called when project name changes', () => {
sandbox.stub(element, '_projectChanged');
element.project = 'New Project';
assert.isTrue(element._projectChanged.called);
test('_repoChanged called when repo name changes', () => {
sandbox.stub(element, '_repoChanged');
element.repo = 'New Repo';
assert.isTrue(element._repoChanged.called);
});
test('_projectChanged', done => {
test('_repoChanged', done => {
const capabilitiesRes = {
accessDatabase: {
id: 'accessDatabase',
@ -129,31 +129,31 @@ limitations under the License.
};
const accessStub = sandbox.stub(element.$.restAPI,
'getProjectAccessRights');
'getRepoAccessRights');
accessStub.withArgs('New Project').returns(Promise.resolve(accessRes));
accessStub.withArgs('Another New Project')
accessStub.withArgs('New Repo').returns(Promise.resolve(accessRes));
accessStub.withArgs('Another New Repo')
.returns(Promise.resolve(accessRes2));
const capabilitiesStub = sandbox.stub(element.$.restAPI,
'getCapabilities');
capabilitiesStub.returns(Promise.resolve(capabilitiesRes));
const projectStub = sandbox.stub(element.$.restAPI, 'getProject').returns(
Promise.resolve(projectRes));
const repoStub = sandbox.stub(element.$.restAPI, 'getRepo').returns(
Promise.resolve(repoRes));
const adminStub = sandbox.stub(element.$.restAPI, 'getIsAdmin').returns(
Promise.resolve(true));
element._projectChanged('New Project').then(() => {
element._repoChanged('New Repo').then(() => {
assert.isTrue(accessStub.called);
assert.isTrue(capabilitiesStub.called);
assert.isTrue(projectStub.called);
assert.isTrue(repoStub.called);
assert.isTrue(adminStub.called);
assert.isNotOk(element._inheritsFrom);
assert.deepEqual(element._local, accessRes.local);
assert.deepEqual(element._sections,
element.toSortedArray(accessRes.local));
assert.deepEqual(element._labels, projectRes.labels);
return element._projectChanged('Another New Project');
assert.deepEqual(element._labels, repoRes.labels);
return element._repoChanged('Another New Repo');
})
.then(() => {
assert.deepEqual(element._sections,
@ -162,7 +162,7 @@ limitations under the License.
});
});
test('_projectChanged when project changes to undefined returns', done => {
test('_repoChanged when repo changes to undefined returns', done => {
const capabilitiesRes = {
accessDatabase: {
id: 'accessDatabase',
@ -182,30 +182,30 @@ limitations under the License.
},
},
};
const projectRes = {
const repoRes = {
labels: {
'Code-Review': {},
},
};
const accessStub = sandbox.stub(element.$.restAPI,
'getProjectAccessRights').returns(Promise.resolve(accessRes));
'getRepoAccessRights').returns(Promise.resolve(accessRes));
const capabilitiesStub = sandbox.stub(element.$.restAPI,
'getCapabilities').returns(Promise.resolve(capabilitiesRes));
const projectStub = sandbox.stub(element.$.restAPI, 'getProject').returns(
Promise.resolve(projectRes));
const repoStub = sandbox.stub(element.$.restAPI, 'getRepo').returns(
Promise.resolve(repoRes));
element._projectChanged().then(() => {
element._repoChanged().then(() => {
assert.isFalse(accessStub.called);
assert.isFalse(capabilitiesStub.called);
assert.isFalse(projectStub.called);
assert.isFalse(repoStub.called);
done();
});
});
test('_computeParentHref', () => {
const projectName = 'test-project';
assert.equal(element._computeParentHref(projectName),
'/admin/projects/test-project,access');
const repoName = 'test-repo';
assert.equal(element._computeParentHref(repoName),
'/admin/repos/test-repo,access');
});
test('_computeAdminClass', () => {
@ -220,7 +220,7 @@ limitations under the License.
assert.isNotOk(Polymer.dom(element.root).querySelector('#inheritsFrom'));
assert.isFalse(element._computeParentHref.called);
element._inheritsFrom = {
name: 'another-project',
name: 'another-repo',
};
flushAsynchronousOperations();
assert.isOk(Polymer.dom(element.root).querySelector('#inheritsFrom'));
@ -313,22 +313,22 @@ limitations under the License.
assert.deepEqual(element._computeAddAndRemove(), {add: {}, remove: {}});
const rules = element._getAllRules();
rules[0]._modified = true;
assert.deepEqual(element._computeAddAndRemove(), projectAccessInput);
assert.deepEqual(element._computeAddAndRemove(), repoAccessInput);
});
test('_handleSaveForReview', done => {
sandbox.stub(element.$.restAPI, 'getProjectAccessRights')
sandbox.stub(element.$.restAPI, 'getRepoAccessRights')
.returns(Promise.resolve(accessRes));
sandbox.stub(element.$.restAPI, 'getProject')
sandbox.stub(element.$.restAPI, 'getRepo')
.returns(Promise.resolve({}));
sandbox.stub(Gerrit.Nav, 'navigateToChange');
const saveForReviewStub = sandbox.stub(element.$.restAPI,
'setProjectAccessRightsForReview')
.returns(Promise.resolve({_number: 1}));
element.project = 'test-project';
element.repo = 'test-repo';
sandbox.stub(element, '_computeAddAndRemove')
.returns(projectAccessInput);
.returns(repoAccessInput);
element._handleSaveForReview().then(() => {
assert.isTrue(saveForReviewStub.called);
@ -339,4 +339,4 @@ limitations under the License.
});
});
});
</script>
</script>

View File

@ -17,7 +17,7 @@ limitations under the License.
<link rel="import" href="../../../styles/shared-styles.html">
<link rel="import" href="../../shared/gr-button/gr-button.html">
<dom-module id="gr-project-command">
<dom-module id="gr-repo-command">
<template>
<style include="shared-styles">
:host {
@ -28,5 +28,5 @@ limitations under the License.
<h3>[[title]]</h3>
<gr-button on-tap="_onCommandTap">[[title]]</gr-button>
</template>
<script src="gr-project-command.js"></script>
<script src="gr-repo-command.js"></script>
</dom-module>

View File

@ -15,7 +15,7 @@
'use strict';
Polymer({
is: 'gr-project-command',
is: 'gr-repo-command',
properties: {
title: String,

View File

@ -16,23 +16,23 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project-command</title>
<title>gr-repo-command</title>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-project-command.html">
<link rel="import" href="gr-repo-command.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-project-command></gr-project-command>
<gr-repo-command></gr-repo-command>
</template>
</test-fixture>
<script>
suite('gr-project-command tests', () => {
suite('gr-repo-command tests', () => {
let element;
setup(() => {

View File

@ -25,9 +25,9 @@ limitations under the License.
<link rel="import" href="../../shared/gr-overlay/gr-overlay.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-create-change-dialog/gr-create-change-dialog.html">
<link rel="import" href="../gr-project-command/gr-project-command.html">
<link rel="import" href="../gr-repo-command/gr-repo-command.html">
<dom-module id="gr-project-commands">
<dom-module id="gr-repo-commands">
<template>
<style include="shared-styles">
main {
@ -45,26 +45,26 @@ limitations under the License.
</style>
<style include="gr-form-styles"></style>
<main class="gr-form-styles read-only">
<h1 id="Title">Project Commands</h1>
<h1 id="Title">Repository Commands</h1>
<div id="loading" class$="[[_computeLoadingClass(_loading)]]">Loading...</div>
<div id="loadedContent" class$="[[_computeLoadingClass(_loading)]]">
<h2 id="options">Command</h2>
<div id="form">
<gr-project-command
<gr-repo-command
title="Create Change"
on-command-tap="_createNewChange">
</gr-project-command>
</gr-repo-command>
<gr-project-command
<gr-repo-command
title="Run GC"
hidden$="[[!_projectConfig.actions.gc.enabled]]"
hidden$="[[!_repoConfig.actions.gc.enabled]]"
on-command-tap="_handleRunningGC">
</gr-project-command>
</gr-repo-command>
<gr-endpoint-decorator name="project-command">
<gr-endpoint-param name="config" value="[[_projectConfig]]">
<gr-endpoint-decorator name="repo-command">
<gr-endpoint-param name="config" value="[[_repoConfig]]">
</gr-endpoint-param>
<gr-endpoint-param name="projectName" value="[[project]]">
<gr-endpoint-param name="repoName" value="[[repo]]">
</gr-endpoint-param>
</gr-endpoint-decorator>
</div>
@ -84,11 +84,11 @@ limitations under the License.
<gr-create-change-dialog
id="createNewChangeModal"
can-create="{{_canCreate}}"
project-name="[[project]]"></gr-create-change-dialog>
repo-name="[[repo]]"></gr-create-change-dialog>
</div>
</gr-confirm-dialog>
</gr-overlay>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-project-commands.js"></script>
<script src="gr-repo-commands.js"></script>
</dom-module>

View File

@ -17,32 +17,32 @@
const GC_MESSAGE = 'Garbage collection completed successfully.';
Polymer({
is: 'gr-project-commands',
is: 'gr-repo-commands',
properties: {
params: Object,
project: String,
repo: String,
_loading: {
type: Boolean,
value: true,
},
/** @type {?} */
_projectConfig: Object,
_repoConfig: Object,
_canCreate: Boolean,
},
attached() {
this._loadProject();
this._loadRepo();
this.fire('title-change', {title: 'Project Commands'});
this.fire('title-change', {title: 'Repo Commands'});
},
_loadProject() {
if (!this.project) { return Promise.resolve(); }
_loadRepo() {
if (!this.repo) { return Promise.resolve(); }
return this.$.restAPI.getProjectConfig(this.project).then(
return this.$.restAPI.getProjectConfig(this.repo).then(
config => {
this._projectConfig = config;
this._repoConfig = config;
this._loading = false;
});
},
@ -56,7 +56,7 @@
},
_handleRunningGC() {
return this.$.restAPI.runProjectGC(this.project).then(response => {
return this.$.restAPI.runRepoGC(this.repo).then(response => {
if (response.status === 200) {
this.dispatchEvent(new CustomEvent('show-alert',
{detail: {message: GC_MESSAGE}, bubbles: true}));

View File

@ -16,24 +16,24 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project-commands</title>
<title>gr-repo-commands</title>
<script src="../../../bower_components/page/page.js"></script>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-project-commands.html">
<link rel="import" href="gr-repo-commands.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-project-commands></gr-project-commands>
<gr-repo-commands></gr-repo-commands>
</template>
</test-fixture>
<script>
suite('gr-project-commands tests', () => {
suite('gr-repo-commands tests', () => {
let element;
let sandbox;

View File

@ -30,7 +30,7 @@ limitations under the License.
<link rel="import" href="../gr-create-pointer-dialog/gr-create-pointer-dialog.html">
<link rel="import" href="../gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.html">
<dom-module id="gr-project-detail-list">
<dom-module id="gr-repo-detail-list">
<template>
<style include="gr-form-styles"></style>
<style include="shared-styles">
@ -87,7 +87,7 @@ limitations under the License.
loading="[[_loading]]"
offset="[[_offset]]"
on-create-clicked="_handleCreateClicked"
path="[[_getPath(_project, detailType)]]">
path="[[_getPath(_repo, detailType)]]">
<table id="list" class="genericList gr-form-styles">
<tr class="headerRow">
<th class="name topHeader">Name</th>
@ -202,11 +202,11 @@ limitations under the License.
detail-type="[[_computeItemName(detailType)]]"
has-new-item-name="{{_hasNewItemName}}"
item-detail="[[detailType]]"
project-name="[[_project]]"></gr-create-pointer-dialog>
repo-name="[[_repo]]"></gr-create-pointer-dialog>
</div>
</gr-confirm-dialog>
</gr-overlay>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-project-detail-list.js"></script>
<script src="gr-repo-detail-list.js"></script>
</dom-module>

View File

@ -20,7 +20,7 @@
};
Polymer({
is: 'gr-project-detail-list',
is: 'gr-repo-detail-list',
properties: {
/**
@ -52,7 +52,7 @@
* Offset of currently visible query results.
*/
_offset: Number,
_project: Object,
_repo: Object,
_items: Array,
/**
* Because we request one more than the projectsPerPage, _shownProjects
@ -82,21 +82,21 @@
Gerrit.URLEncodingBehavior,
],
_determineIfOwner(project) {
return this.$.restAPI.getProjectAccess(project)
_determineIfOwner(repo) {
return this.$.restAPI.getRepoAccess(repo)
.then(access =>
this._isOwner = access && access[project].is_owner);
this._isOwner = access && access[repo].is_owner);
},
_paramsChanged(params) {
if (!params || !params.project) { return; }
if (!params || !params.repo) { return; }
this._project = params.project;
this._repo = params.repo;
this._getLoggedIn().then(loggedIn => {
this._loggedIn = loggedIn;
if (loggedIn) {
this._determineIfOwner(this._project);
this._determineIfOwner(this._repo);
}
});
@ -105,24 +105,24 @@
this._filter = this.getFilterValue(params);
this._offset = this.getOffsetValue(params);
return this._getItems(this._filter, this._project,
return this._getItems(this._filter, this._repo,
this._itemsPerPage, this._offset, this.detailType);
},
_getItems(filter, project, itemsPerPage, offset, detailType) {
_getItems(filter, repo, itemsPerPage, offset, detailType) {
this._loading = true;
this._items = [];
Polymer.dom.flush();
if (detailType === DETAIL_TYPES.BRANCHES) {
return this.$.restAPI.getProjectBranches(
filter, project, itemsPerPage, offset) .then(items => {
return this.$.restAPI.getRepoBranches(
filter, repo, itemsPerPage, offset) .then(items => {
if (!items) { return; }
this._items = items;
this._loading = false;
});
} else if (detailType === DETAIL_TYPES.TAGS) {
return this.$.restAPI.getProjectTags(
filter, project, itemsPerPage, offset) .then(items => {
return this.$.restAPI.getRepoTags(
filter, repo, itemsPerPage, offset) .then(items => {
if (!items) { return; }
this._items = items;
this._loading = false;
@ -130,14 +130,14 @@
}
},
_getPath(project) {
return `/admin/projects/${this.encodeURL(project, false)},` +
_getPath(repo) {
return `/admin/repos/${this.encodeURL(repo, false)},` +
`${this.detailType}`;
},
_computeWeblink(project) {
if (!project.web_links) { return ''; }
const webLinks = project.web_links;
_computeWeblink(repo) {
if (!repo.web_links) { return ''; }
const webLinks = repo.web_links;
return webLinks.length ? webLinks : null;
},
@ -172,11 +172,11 @@
},
_handleSaveRevision(e) {
this._setProjectHead(this._project, this._revisedRef, e);
this._setRepoHead(this._repo, this._revisedRef, e);
},
_setProjectHead(project, ref, e) {
return this.$.restAPI.setProjectHead(project, ref).then(res => {
_setRepoHead(repo, ref, e) {
return this.$.restAPI.setRepoHead(repo, ref).then(res => {
if (res.status < 400) {
this._isEditing = false;
e.model.set('item.revision', ref);
@ -195,22 +195,22 @@
_handleDeleteItemConfirm() {
this.$.overlay.close();
if (this.detailType === DETAIL_TYPES.BRANCHES) {
return this.$.restAPI.deleteProjectBranches(this._project,
return this.$.restAPI.deleteRepoBranches(this._repo,
this._refName)
.then(itemDeleted => {
if (itemDeleted.status === 204) {
this._getItems(
this._filter, this._project, this._itemsPerPage,
this._filter, this._repo, this._itemsPerPage,
this._offset, this.detailType);
}
});
} else if (this.detailType === DETAIL_TYPES.TAGS) {
return this.$.restAPI.deleteProjectTags(this._project,
return this.$.restAPI.deleteRepoTags(this._repo,
this._refName)
.then(itemDeleted => {
if (itemDeleted.status === 204) {
this._getItems(
this._filter, this._project, this._itemsPerPage,
this._filter, this._repo, this._itemsPerPage,
this._offset, this.detailType);
}
});

View File

@ -16,19 +16,19 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project-detail-list</title>
<title>gr-repo-detail-list</title>
<script src="../../../bower_components/page/page.js"></script>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-project-detail-list.html">
<link rel="import" href="gr-repo-detail-list.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-project-detail-list></gr-project-detail-list>
<gr-repo-detail-list></gr-repo-detail-list>
</template>
</test-fixture>
@ -83,7 +83,7 @@ limitations under the License.
sandbox.restore();
});
suite('list of project branches', () => {
suite('list of repo branches', () => {
setup(done => {
branches = [{
ref: 'HEAD',
@ -91,13 +91,13 @@ limitations under the License.
}].concat(_.times(25, branchGenerator));
stub('gr-rest-api-interface', {
getProjectBranches(num, project, offset) {
getRepoBranches(num, project, offset) {
return Promise.resolve(branches);
},
});
const params = {
project: 'test',
repo: 'test',
detailType: 'branches',
};
@ -133,7 +133,7 @@ limitations under the License.
test('Edit HEAD button not admin', done => {
sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
sandbox.stub(element.$.restAPI, 'getProjectAccess').returns(
sandbox.stub(element.$.restAPI, 'getRepoAccess').returns(
Promise.resolve({
test: {is_owner: false},
}));
@ -157,7 +157,7 @@ limitations under the License.
.querySelector('.revisionWithEditing');
sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
sandbox.stub(element.$.restAPI, 'getProjectAccess').returns(
sandbox.stub(element.$.restAPI, 'getRepoAccess').returns(
Promise.resolve({
test: {is_owner: true},
}));
@ -206,7 +206,7 @@ limitations under the License.
// Change the ref to something else
element._revisedRef = 'newRef';
element._project = 'test';
element._repo = 'test';
assert.isFalse(saveBtn.disabled);
// Save button calls handleSave. since this is stubbed, the edit
@ -234,13 +234,13 @@ limitations under the License.
test('_handleSaveRevision with invalid rev', done => {
const event = {model: {set: sandbox.stub()}};
element._isEditing = true;
sandbox.stub(element.$.restAPI, 'setProjectHead').returns(
sandbox.stub(element.$.restAPI, 'setRepoHead').returns(
Promise.resolve({
status: 400,
})
);
element._setProjectHead('test', 'newRef', event).then(() => {
element._setRepoHead('test', 'newRef', event).then(() => {
assert.isTrue(element._isEditing);
assert.isFalse(event.model.set.called);
done();
@ -250,13 +250,13 @@ limitations under the License.
test('_handleSaveRevision with valid rev', done => {
const event = {model: {set: sandbox.stub()}};
element._isEditing = true;
sandbox.stub(element.$.restAPI, 'setProjectHead').returns(
sandbox.stub(element.$.restAPI, 'setRepoHead').returns(
Promise.resolve({
status: 200,
})
);
element._setProjectHead('test', 'newRef', event).then(() => {
element._setRepoHead('test', 'newRef', event).then(() => {
assert.isFalse(element._isEditing);
assert.isTrue(event.model.set.called);
done();
@ -274,37 +274,37 @@ limitations under the License.
branches = _.times(25, branchGenerator);
stub('gr-rest-api-interface', {
getProjectBranches(num, project, offset) {
getRepoBranches(num, repo, offset) {
return Promise.resolve(branches);
},
});
const params = {
project: 'test',
repo: 'test',
detailType: 'branches',
};
element._paramsChanged(params).then(() => { flush(done); });
});
test('_shownProjectsBranches', () => {
test('_shownItems', () => {
assert.equal(element._shownItems.length, 25);
});
});
suite('filter', () => {
test('_paramsChanged', done => {
sandbox.stub(element.$.restAPI, 'getProjectBranches', () => {
sandbox.stub(element.$.restAPI, 'getRepoBranches', () => {
return Promise.resolve(branches);
});
const params = {
detailType: 'branches',
project: 'test',
repo: 'test',
filter: 'test',
offset: 25,
};
element._paramsChanged(params).then(() => {
assert.isTrue(element.$.restAPI.getProjectBranches.lastCall
assert.isTrue(element.$.restAPI.getRepoBranches.lastCall
.calledWithExactly('test', 'test', 25, 25));
done();
});
@ -329,18 +329,18 @@ limitations under the License.
sandbox.restore();
});
suite('list of project tags', () => {
suite('list of repo tags', () => {
setup(done => {
tags = _.times(26, tagGenerator);
stub('gr-rest-api-interface', {
getProjectTags(num, project, offset) {
getRepoTags(num, repo, offset) {
return Promise.resolve(tags);
},
});
const params = {
project: 'test',
repo: 'test',
detailType: 'tags',
};
@ -409,13 +409,13 @@ limitations under the License.
tags = _.times(25, tagGenerator);
stub('gr-rest-api-interface', {
getProjectTags(num, project, offset) {
getRepoTags(num, project, offset) {
return Promise.resolve(tags);
},
});
const params = {
project: 'test',
repo: 'test',
detailType: 'tags',
};
@ -429,17 +429,17 @@ limitations under the License.
suite('filter', () => {
test('_paramsChanged', done => {
sandbox.stub(element.$.restAPI, 'getProjectTags', () => {
sandbox.stub(element.$.restAPI, 'getRepoTags', () => {
return Promise.resolve(tags);
});
const params = {
project: 'test',
repo: 'test',
detailType: 'tags',
filter: 'test',
offset: 25,
};
element._paramsChanged(params).then(() => {
assert.isTrue(element.$.restAPI.getProjectTags.lastCall
assert.isTrue(element.$.restAPI.getRepoTags.lastCall
.calledWithExactly('test', 'test', 25, 25));
done();
});

View File

@ -23,26 +23,25 @@ limitations under the License.
<link rel="import" href="../../shared/gr-list-view/gr-list-view.html">
<link rel="import" href="../../shared/gr-overlay/gr-overlay.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-create-project-dialog/gr-create-project-dialog.html">
<link rel="import" href="../gr-create-repo-dialog/gr-create-repo-dialog.html">
<dom-module id="gr-project-list">
<dom-module id="gr-repo-list">
<template>
<style include="shared-styles"></style>
<style include="gr-table-styles"></style>
<gr-list-view
create-new=[[_createNewCapability]]
filter="[[_filter]]"
items-per-page="[[_projectsPerPage]]"
items="[[_projects]]"
items-per-page="[[_reposPerPage]]"
items="[[_repos]]"
loading="[[_loading]]"
offset="[[_offset]]"
on-create-clicked="_handleCreateClicked"
path="[[_path]]">
<table id="list" class="genericList">
<tr class="headerRow">
<th class="name topHeader">Project Name</th>
<th class="description topHeader">Project Description</th>
<th class="name topHeader">Repository Name</th>
<th class="description topHeader">Repository Description</th>
<th class="repositoryBrowser topHeader">Repository Browser</th>
<th class="readOnly topHeader">Read only</th>
</tr>
@ -50,10 +49,10 @@ limitations under the License.
<td>Loading...</td>
</tr>
<tbody class$="[[computeLoadingClass(_loading)]]">
<template is="dom-repeat" items="[[_shownProjects]]">
<template is="dom-repeat" items="[[_shownRepos]]">
<tr class="table">
<td class="name">
<a href$="[[_computeProjectUrl(item.name)]]">[[item.name]]</a>
<a href$="[[_computeRepoUrl(item.name)]]">[[item.name]]</a>
</td>
<td class="description">[[item.description]]</td>
<td class="repositoryBrowser">
@ -77,22 +76,22 @@ limitations under the License.
<gr-confirm-dialog
id="createDialog"
class="confirmDialog"
disabled="[[!_hasNewProjectName]]"
disabled="[[!_hasNewRepoName]]"
confirm-label="Create"
on-confirm="_handleCreateProject"
on-confirm="_handleCreateRepo"
on-cancel="_handleCloseCreate">
<div class="header" slot="header">
Create Project
Create Repository
</div>
<div class="main" slot="main">
<gr-create-project-dialog
has-new-project-name="{{_hasNewProjectName}}"
<gr-create-repo-dialog
has-new-repo-name="{{_hasNewRepoName}}"
params="[[params]]"
id="createNewModal"></gr-create-project-dialog>
id="createNewModal"></gr-create-repo-dialog>
</div>
</gr-confirm-dialog>
</gr-overlay>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-project-list.js"></script>
<script src="gr-repo-list.js"></script>
</dom-module>

View File

@ -15,7 +15,7 @@
'use strict';
Polymer({
is: 'gr-project-list',
is: 'gr-repo-list',
properties: {
/**
@ -33,25 +33,25 @@
_path: {
type: String,
readOnly: true,
value: '/admin/projects',
value: '/admin/repos',
},
_hasNewProjectName: Boolean,
_hasNewRepoName: Boolean,
_createNewCapability: {
type: Boolean,
value: false,
},
_projects: Array,
_repos: Array,
/**
* Because we request one more than the projectsPerPage, _shownProjects
* maybe one less than _projects.
* */
_shownProjects: {
_shownRepos: {
type: Array,
computed: 'computeShownItems(_projects)',
computed: 'computeShownItems(_repos)',
},
_projectsPerPage: {
_reposPerPage: {
type: Number,
value: 25,
},
@ -68,8 +68,8 @@
],
attached() {
this._getCreateProjectCapability();
this.fire('title-change', {title: 'Projects'});
this._getCreateRepoCapability();
this.fire('title-change', {title: 'Repos'});
this._maybeOpenCreateOverlay(this.params);
},
@ -78,7 +78,7 @@
this._filter = this.getFilterValue(params);
this._offset = this.getOffsetValue(params);
return this._getProjects(this._filter, this._projectsPerPage,
return this._getRepos(this._filter, this._reposPerPage,
this._offset);
},
@ -92,11 +92,11 @@
}
},
_computeProjectUrl(name) {
_computeRepoUrl(name) {
return this.getUrl(this._path + '/', name);
},
_getCreateProjectCapability() {
_getCreateRepoCapability() {
return this.$.restAPI.getAccount().then(account => {
if (!account) { return; }
return this.$.restAPI.getAccountCapabilities(['createProject'])
@ -108,25 +108,23 @@
});
},
_getProjects(filter, projectsPerPage, offset) {
this._projects = [];
return this.$.restAPI.getProjects(filter, projectsPerPage, offset)
.then(projects => {
if (!projects) {
return;
}
this._projects = Object.keys(projects)
_getRepos(filter, reposPerPage, offset) {
this._repos = [];
return this.$.restAPI.getRepos(filter, reposPerPage, offset)
.then(repos => {
if (!repos) { return; }
this._repos = Object.keys(repos)
.map(key => {
const project = projects[key];
project.name = key;
return project;
const repo = repos[key];
repo.name = key;
return repo;
});
this._loading = false;
});
},
_handleCreateProject() {
this.$.createNewModal.handleCreateProject();
_handleCreateRepo() {
this.$.createNewModal.handleCreateRepo();
},
_handleCloseCreate() {
@ -141,11 +139,9 @@
return item.state === 'READ_ONLY' ? 'Y' : '';
},
_computeWeblink(project) {
if (!project.web_links) {
return '';
}
const webLinks = project.web_links;
_computeWeblink(repo) {
if (!repo.web_links) { return ''; }
const webLinks = repo.web_links;
return webLinks.length ? webLinks : null;
},
});

View File

@ -16,25 +16,25 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project-list</title>
<title>gr-repo-list</title>
<script src="../../../bower_components/page/page.js"></script>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-project-list.html">
<link rel="import" href="gr-repo-list.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-project-list></gr-project-list>
<gr-repo-list></gr-repo-list>
</template>
</test-fixture>
<script>
let counter;
const projectGenerator = () => {
const repoGenerator = () => {
return {
id: `test${++counter}`,
state: 'ACTIVE',
@ -47,9 +47,9 @@ limitations under the License.
};
};
suite('gr-project-list tests', () => {
suite('gr-repo-list tests', () => {
let element;
let projects;
let repos;
let sandbox;
let value;
@ -63,26 +63,26 @@ limitations under the License.
sandbox.restore();
});
suite('list with projects', () => {
suite('list with repos', () => {
setup(done => {
projects = _.times(26, projectGenerator);
repos = _.times(26, repoGenerator);
stub('gr-rest-api-interface', {
getProjects(num, offset) {
return Promise.resolve(projects);
getRepos(num, offset) {
return Promise.resolve(repos);
},
});
element._paramsChanged(value).then(() => { flush(done); });
});
test('test for test project in the list', done => {
test('test for test repo in the list', done => {
flush(() => {
assert.equal(element._projects[1].id, 'test2');
assert.equal(element._repos[1].id, 'test2');
done();
});
});
test('_shownProjects', () => {
assert.equal(element._shownProjects.length, 25);
test('_shownRepos', () => {
assert.equal(element._shownRepos.length, 25);
});
test('_maybeOpenCreateOverlay', () => {
@ -98,35 +98,35 @@ limitations under the License.
});
});
suite('list with less then 25 projects', () => {
suite('list with less then 25 repos', () => {
setup(done => {
projects = _.times(25, projectGenerator);
repos = _.times(25, repoGenerator);
stub('gr-rest-api-interface', {
getProjects(num, offset) {
return Promise.resolve(projects);
getRepos(num, offset) {
return Promise.resolve(repos);
},
});
element._paramsChanged(value).then(() => { flush(done); });
});
test('_shownProjects', () => {
assert.equal(element._shownProjects.length, 25);
test('_shownRepos', () => {
assert.equal(element._shownRepos.length, 25);
});
});
suite('filter', () => {
test('_paramsChanged', done => {
sandbox.stub(element.$.restAPI, 'getProjects', () => {
return Promise.resolve(projects);
sandbox.stub(element.$.restAPI, 'getRepos', () => {
return Promise.resolve(repos);
});
const value = {
filter: 'test',
offset: 25,
};
element._paramsChanged(value).then(() => {
assert.isTrue(element.$.restAPI.getProjects.lastCall
assert.isTrue(element.$.restAPI.getRepos.lastCall
.calledWithExactly('test', 25, 25));
done();
});
@ -140,7 +140,7 @@ limitations under the License.
assert.equal(getComputedStyle(element.$.loading).display, 'block');
element._loading = false;
element._projects = _.times(25, projectGenerator);
element._repos = _.times(25, repoGenerator);
flushAsynchronousOperations();
assert.equal(element.computeLoadingClass(element._loading), '');
@ -161,10 +161,10 @@ limitations under the License.
assert.isTrue(openStub.called);
});
test('_handleCreateProject called when confirm fired', () => {
sandbox.stub(element, '_handleCreateProject');
test('_handleCreateRepo called when confirm fired', () => {
sandbox.stub(element, '_handleCreateRepo');
element.$.createDialog.fire('confirm');
assert.isTrue(element._handleCreateProject.called);
assert.isTrue(element._handleCreateRepo.called);
});
test('_handleCloseCreate called when cancel fired', () => {

View File

@ -24,7 +24,7 @@ limitations under the License.
<link rel="import" href="../../../styles/gr-form-styles.html">
<link rel="import" href="../../../styles/shared-styles.html">
<dom-module id="gr-project">
<dom-module id="gr-repo">
<template>
<style include="shared-styles">
main {
@ -44,16 +44,16 @@ limitations under the License.
#loading:not(.loading) {
display: none;
}
.projectSettings {
.repositorySettings {
display: none;
}
.projectSettings.showConfig {
.repositorySettings.showConfig {
display: block;
}
</style>
<style include="gr-form-styles"></style>
<main class="gr-form-styles read-only">
<h1 id="Title">[[project]]</h1>
<h1 id="Title">[[repo]]</h1>
<div id="loading" class$="[[_computeLoadingClass(_loading)]]">Loading...</div>
<div id="loadedContent" class$="[[_computeLoadingClass(_loading)]]">
<div id="downloadContent" class$="[[_computeDownloadClass(_schemes)]]">
@ -61,7 +61,7 @@ limitations under the License.
<fieldset>
<gr-download-commands
id="downloadCommands"
commands="[[_computeCommands(project, _schemesObj, _selectedScheme)]]"
commands="[[_computeCommands(repo, _schemesObj, _selectedScheme)]]"
schemes="[[_schemes]]"
selected-scheme="{{_selectedScheme}}"></gr-download-commands>
</fieldset>
@ -76,18 +76,18 @@ limitations under the License.
id="descriptionInput"
class="description"
autocomplete="on"
placeholder="<Insert project description here>"
bind-value="{{_projectConfig.description}}"
placeholder="<Insert repo description here>"
bind-value="{{_repoConfig.description}}"
disabled$="[[_readOnly]]"></iron-autogrow-textarea>
</fieldset>
<h3 id="Options">Project Options</h3>
<h3 id="Options">Repository Options</h3>
<fieldset id="options">
<section>
<span class="title">State</span>
<span class="value">
<gr-select
id="stateSelect"
bind-value="{{_projectConfig.state}}">
bind-value="{{_repoConfig.state}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat" items=[[_states]]>
<option value="[[item.value]]">[[item.label]]</option>
@ -101,7 +101,7 @@ limitations under the License.
<span class="value">
<gr-select
id="submitTypeSelect"
bind-value="{{_projectConfig.submit_type}}">
bind-value="{{_repoConfig.submit_type}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat" items="[[_submitTypes]]">
<option value="[[item.value]]">[[item.label]]</option>
@ -115,10 +115,10 @@ limitations under the License.
<span class="value">
<gr-select
id="contentMergeSelect"
bind-value="{{_projectConfig.use_content_merge.configured_value}}">
bind-value="{{_repoConfig.use_content_merge.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.use_content_merge)]]">
items="[[_formatBooleanSelect(_repoConfig.use_content_merge)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -132,10 +132,10 @@ limitations under the License.
<span class="value">
<gr-select
id="newChangeSelect"
bind-value="{{_projectConfig.create_new_change_for_all_not_in_target.configured_value}}">
bind-value="{{_repoConfig.create_new_change_for_all_not_in_target.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.create_new_change_for_all_not_in_target)]]">
items="[[_formatBooleanSelect(_repoConfig.create_new_change_for_all_not_in_target)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -147,10 +147,10 @@ limitations under the License.
<span class="value">
<gr-select
id="requireChangeIdSelect"
bind-value="{{_projectConfig.require_change_id.configured_value}}">
bind-value="{{_repoConfig.require_change_id.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.require_change_id)]]">
items="[[_formatBooleanSelect(_repoConfig.require_change_id)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -159,15 +159,15 @@ limitations under the License.
</section>
<section
id="enableSignedPushSettings"
class$="projectSettings [[_computeProjectsClass(_projectConfig.enable_signed_push)]]">
class$="repositorySettings [[_computeRepositoriesClass(_repoConfig.enable_signed_push)]]">
<span class="title">Enable signed push</span>
<span class="value">
<gr-select
id="enableSignedPush"
bind-value="{{_projectConfig.enable_signed_push.configured_value}}">
bind-value="{{_repoConfig.enable_signed_push.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.enable_signed_push)]]">
items="[[_formatBooleanSelect(_repoConfig.enable_signed_push)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -176,15 +176,15 @@ limitations under the License.
</section>
<section
id="requireSignedPushSettings"
class$="projectSettings [[_computeProjectsClass(_projectConfig.require_signed_push)]]">
class$="repositorySettings [[_computeRepositoriesClass(_repoConfig.require_signed_push)]]">
<span class="title">Require signed push</span>
<span class="value">
<gr-select
id="requireSignedPush"
bind-value="{{_projectConfig.require_signed_push.configured_value}}">
bind-value="{{_repoConfig.require_signed_push.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.require_signed_push)]]">
items="[[_formatBooleanSelect(_repoConfig.require_signed_push)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -197,26 +197,26 @@ limitations under the License.
<span class="value">
<gr-select
id="rejectImplicitMergesSelect"
bind-value="{{_projectConfig.reject_implicit_merges.configured_value}}">
bind-value="{{_repoConfig.reject_implicit_merges.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.reject_implicit_merges)]]">
items="[[_formatBooleanSelect(_repoConfig.reject_implicit_merges)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
</gr-select>
</span>
</section>
<section id="noteDbSettings" class$="projectSettings [[_computeProjectsClass(_noteDbEnabled)]]">
<section id="noteDbSettings" class$="repositorySettings [[_computeRepositoriesClass(_noteDbEnabled)]]">
<span class="title">
Enable adding unregistered users as reviewers and CCs on changes</span>
<span class="value">
<gr-select
id="unRegisteredCcSelect"
bind-value="{{_projectConfig.enable_reviewer_by_email.configured_value}}">
bind-value="{{_repoConfig.enable_reviewer_by_email.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.enable_reviewer_by_email)]]">
items="[[_formatBooleanSelect(_repoConfig.enable_reviewer_by_email)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -229,10 +229,10 @@ limitations under the License.
<span class="value">
<gr-select
id="setAllnewChangesPrivateByDefaultSelect"
bind-value="{{_projectConfig.private_by_default.configured_value}}">
bind-value="{{_repoConfig.private_by_default.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.private_by_default)]]">
items="[[_formatBooleanSelect(_repoConfig.private_by_default)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -244,7 +244,7 @@ limitations under the License.
<span class="value">
<input
id="maxGitObjSizeInput"
bind-value="{{_projectConfig.max_object_size_limit.configured_value}}"
bind-value="{{_repoConfig.max_object_size_limit.configured_value}}"
is="iron-input"
type="text"
disabled$="[[_readOnly]]">
@ -255,10 +255,10 @@ limitations under the License.
<span class="value">
<gr-select
id="matchAuthoredDateWithCommitterDateSelect"
bind-value="{{_projectConfig.match_author_to_committer_date.configured_value}}">
bind-value="{{_repoConfig.match_author_to_committer_date.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.match_author_to_committer_date)]]">
items="[[_formatBooleanSelect(_repoConfig.match_author_to_committer_date)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -274,10 +274,10 @@ limitations under the License.
<span class="value">
<gr-select
id="contributorAgreementSelect"
bind-value="{{_projectConfig.use_contributor_agreements.configured_value}}">
bind-value="{{_repoConfig.use_contributor_agreements.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.use_contributor_agreements)]]">
items="[[_formatBooleanSelect(_repoConfig.use_contributor_agreements)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -289,10 +289,10 @@ limitations under the License.
<span class="value">
<gr-select
id="useSignedOffBySelect"
bind-value="{{_projectConfig.use_signed_off_by.configured_value}}">
bind-value="{{_repoConfig.use_signed_off_by.configured_value}}">
<select disabled$="[[_readOnly]]">
<template is="dom-repeat"
items="[[_formatBooleanSelect(_projectConfig.use_signed_off_by)]]">
items="[[_formatBooleanSelect(_repoConfig.use_signed_off_by)]]">
<option value="[[item.value]]">[[item.label]]</option>
</template>
</select>
@ -302,7 +302,7 @@ limitations under the License.
</fieldset>
<!-- TODO @beckysiegel add plugin config widgets -->
<gr-button
on-tap="_handleSaveProjectConfig"
on-tap="_handleSaveRepoConfig"
disabled$="[[_computeButtonDisabled(_readOnly, _configChanged)]]">Save changes</gr-button>
</fieldset>
</div>
@ -310,5 +310,5 @@ limitations under the License.
</main>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-project.js"></script>
<script src="gr-repo.js"></script>
</dom-module>

View File

@ -48,11 +48,11 @@
};
Polymer({
is: 'gr-project',
is: 'gr-repo',
properties: {
params: Object,
project: String,
repo: String,
_configChanged: {
type: Boolean,
@ -68,7 +68,7 @@
observer: '_loggedInChanged',
},
/** @type {?} */
_projectConfig: Object,
_repoConfig: Object,
_readOnly: {
type: Boolean,
value: true,
@ -104,35 +104,35 @@
},
observers: [
'_handleConfigChanged(_projectConfig.*)',
'_handleConfigChanged(_repoConfig.*)',
],
attached() {
this._loadProject();
this._loadRepo();
this.fire('title-change', {title: this.project});
this.fire('title-change', {title: this.repo});
},
_loadProject() {
if (!this.project) { return Promise.resolve(); }
_loadRepo() {
if (!this.repo) { return Promise.resolve(); }
const promises = [];
promises.push(this._getLoggedIn().then(loggedIn => {
this._loggedIn = loggedIn;
if (loggedIn) {
this.$.restAPI.getProjectAccess(this.project).then(access => {
this.$.restAPI.getRepoAccess(this.repo).then(access => {
// If the user is not an owner, is_owner is not a property.
this._readOnly = !access[this.project].is_owner;
this._readOnly = !access[this.repo].is_owner;
});
}
}));
promises.push(this.$.restAPI.getProjectConfig(this.project).then(
promises.push(this.$.restAPI.getProjectConfig(this.repo).then(
config => {
if (!config.state) {
config.state = STATES.active.value;
}
this._projectConfig = config;
this._repoConfig = config;
this._loading = false;
}));
@ -191,7 +191,7 @@
return this.$.restAPI.getLoggedIn();
},
_formatProjectConfigForSave(p) {
_formatRepoConfigForSave(p) {
const configInputObj = {};
for (const key in p) {
if (p.hasOwnProperty(key)) {
@ -205,9 +205,9 @@
return configInputObj;
},
_handleSaveProjectConfig() {
return this.$.restAPI.saveProjectConfig(this.project,
this._formatProjectConfigForSave(this._projectConfig)).then(() => {
_handleSaveRepoConfig() {
return this.$.restAPI.saveRepoConfig(this.repo,
this._formatRepoConfigForSave(this._repoConfig)).then(() => {
this._configChanged = false;
});
},
@ -236,7 +236,7 @@
}
},
_computeCommands(project, schemesObj, _selectedScheme) {
_computeCommands(repo, schemesObj, _selectedScheme) {
const commands = [];
let commandObj;
if (schemesObj.hasOwnProperty(_selectedScheme)) {
@ -247,15 +247,15 @@
commands.push({
title,
command: commandObj[title]
.replace('${project}', project)
.replace('${project}', repo)
.replace('${project-base-name}',
project.substring(project.lastIndexOf('/') + 1)),
repo.substring(repo.lastIndexOf('/') + 1)),
});
}
return commands;
},
_computeProjectsClass(config) {
_computeRepositoriesClass(config) {
return config ? 'showConfig': '';
},
});

View File

@ -16,26 +16,26 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project</title>
<title>gr-repo</title>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-project.html">
<link rel="import" href="gr-repo.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-project></gr-project>
<gr-repo></gr-repo>
</template>
</test-fixture>
<script>
suite('gr-project tests', () => {
suite('gr-repo tests', () => {
let element;
let sandbox;
const PROJECT = 'test-project';
const REPO = 'test-repo';
const SCHEMES = {http: {}, repo: {}, ssh: {}};
function getFormFields() {
@ -112,7 +112,7 @@ limitations under the License.
sandbox.restore();
});
test('loading displays before project config is loaded', () => {
test('loading displays before repo config is loaded', () => {
assert.isTrue(element.$.loading.classList.contains('loading'));
assert.isFalse(getComputedStyle(element.$.loading).display === 'none');
assert.isTrue(element.$.loadedContent.classList.contains('loading'));
@ -140,30 +140,30 @@ limitations under the License.
});
test('form defaults to read only when not logged in', done => {
element.project = PROJECT;
element._loadProject().then(() => {
element.repo = REPO;
element._loadRepo().then(() => {
assert.isTrue(element._readOnly);
done();
});
});
test('form defaults to read only when logged in and not admin', done => {
element.project = PROJECT;
element.repo = REPO;
sandbox.stub(element, '_getLoggedIn', () => {
return Promise.resolve(true);
});
sandbox.stub(element.$.restAPI, 'getProjectAccess', () => {
return Promise.resolve({'test-project': {}});
sandbox.stub(element.$.restAPI, 'getRepoAccess', () => {
return Promise.resolve({'test-repo': {}});
});
element._loadProject().then(() => {
element._loadRepo().then(() => {
assert.isTrue(element._readOnly);
done();
});
});
test('all form elements are disabled when not admin', done => {
element.project = PROJECT;
element._loadProject().then(() => {
element.repo = REPO;
element._loadRepo().then(() => {
flushAsynchronousOperations();
const formFields = getFormFields();
for (const field of formFields) {
@ -223,17 +223,17 @@ limitations under the License.
suite('admin', () => {
setup(() => {
element.project = PROJECT;
element.repo = REPO;
sandbox.stub(element, '_getLoggedIn', () => {
return Promise.resolve(true);
});
sandbox.stub(element.$.restAPI, 'getProjectAccess', () => {
return Promise.resolve({'test-project': {is_owner: true}});
sandbox.stub(element.$.restAPI, 'getRepoAccess', () => {
return Promise.resolve({'test-repo': {is_owner: true}});
});
});
test('all form elements are enabled', done => {
element._loadProject().then(() => {
element._loadRepo().then(() => {
flushAsynchronousOperations();
const formFields = getFormFields();
for (const field of formFields) {
@ -245,8 +245,8 @@ limitations under the License.
});
test('state gets set correctly', done => {
element._loadProject().then(() => {
assert.equal(element._projectConfig.state, 'ACTIVE');
element._loadRepo().then(() => {
assert.equal(element._repoConfig.state, 'ACTIVE');
assert.equal(element.$.stateSelect.bindValue, 'ACTIVE');
done();
});
@ -257,12 +257,12 @@ limitations under the License.
element._noteDbEnabled = false;
assert.equal(
element._computeProjectsClass(element._noteDbEnabled), '');
element._computeRepositoriesClass(element._noteDbEnabled), '');
element._noteDbEnabled = true;
assert.equal(
element._computeProjectsClass(element._noteDbEnabled), 'showConfig');
assert.equal(element._computeRepositoriesClass(
element._noteDbEnabled), 'showConfig');
const configInputObj = {
description: 'new description',
@ -282,14 +282,14 @@ limitations under the License.
enable_reviewer_by_email: 'TRUE',
};
const saveStub = sandbox.stub(element.$.restAPI, 'saveProjectConfig'
const saveStub = sandbox.stub(element.$.restAPI, 'saveRepoConfig'
, () => {
return Promise.resolve({});
});
const button = Polymer.dom(element.root).querySelector('gr-button');
element._loadProject().then(() => {
element._loadRepo().then(() => {
assert.isTrue(button.hasAttribute('disabled'));
assert.isFalse(element.$.Title.classList.contains('edited'));
element.$.descriptionInput.bindValue = configInputObj.description;
@ -324,13 +324,13 @@ limitations under the License.
assert.isTrue(element.$.configurations.classList.contains('edited'));
const formattedObj =
element._formatProjectConfigForSave(element._projectConfig);
element._formatRepoConfigForSave(element._repoConfig);
assert.deepEqual(formattedObj, configInputObj);
element._handleSaveProjectConfig().then(() => {
element._handleSaveRepoConfig().then(() => {
assert.isTrue(button.hasAttribute('disabled'));
assert.isFalse(element.$.Title.classList.contains('edited'));
assert.isTrue(saveStub.lastCall.calledWithExactly(PROJECT,
assert.isTrue(saveStub.lastCall.calledWithExactly(REPO,
configInputObj));
done();
});

View File

@ -77,7 +77,7 @@
if (input.startsWith('refs/heads/')) {
input = input.substring('refs/heads/'.length);
}
return this.$.restAPI.getProjectBranches(
return this.$.restAPI.getRepoBranches(
input, this.project, SUGGESTIONS_LIMIT).then(response => {
const branches = [];
let branch;

View File

@ -39,7 +39,7 @@ limitations under the License.
setup(() => {
sandbox = sinon.sandbox.create();
stub('gr-rest-api-interface', {
getProjectBranches(input) {
getRepoBranches(input) {
if (input.startsWith('test')) {
return Promise.resolve([
{

View File

@ -57,7 +57,7 @@
if (input.startsWith('refs/heads/')) {
input = input.substring('refs/heads/'.length);
}
return this.$.restAPI.getProjectBranches(
return this.$.restAPI.getRepoBranches(
input, this.project, SUGGESTIONS_LIMIT).then(response => {
const branches = [];
let branch;

View File

@ -37,7 +37,7 @@ limitations under the License.
setup(() => {
stub('gr-rest-api-interface', {
getProjectBranches(input) {
getRepoBranches(input) {
if (input.startsWith('test')) {
return Promise.resolve([
{

View File

@ -164,7 +164,7 @@ limitations under the License.
<li>
<a
class="browse linksTitle"
href$="[[_computeRelativeURL('/admin/projects')]]">
href$="[[_computeRelativeURL('/admin/repos')]]">
Browse</a>
</li>
</ul>

View File

@ -55,31 +55,33 @@
// Matches /admin/create-project
LEGACY_CREATE_GROUP: /^\/admin\/create-group\/?$/,
// Matches /admin/projects/<project>
PROJECT: /^\/admin\/projects\/([^,]+)$/,
PROJECT_OLD: /^\/admin\/(projects)\/?(.+)?$/,
// Matches /admin/projects/<project>,commands.
PROJECT_COMMANDS: /^\/admin\/projects\/(.+),commands$/,
// Matches /admin/repos/<repo>
REPO: /^\/admin\/repos\/([^,]+)$/,
// Matches /admin/projects/<project>,access.
PROJECT_ACCESS: /^\/admin\/projects\/(.+),access$/,
// Matches /admin/repos/<repo>,commands.
REPO_COMMANDS: /^\/admin\/repos\/(.+),commands$/,
// Matches /admin/projects[,<offset>][/].
PROJECT_LIST_OFFSET: /^\/admin\/projects(,(\d+))?(\/)?$/,
PROJECT_LIST_FILTER: '/admin/projects/q/filter::filter',
PROJECT_LIST_FILTER_OFFSET: '/admin/projects/q/filter::filter,:offset',
// Matches /admin/repos/<repos>,access.
REPO_ACCESS: /^\/admin\/repos\/(.+),access$/,
// Matches /admin/projects/<project>,branches[,<offset>].
BRANCH_LIST_OFFSET: /^\/admin\/projects\/(.+),branches(,(.+))?$/,
BRANCH_LIST_FILTER: '/admin/projects/:project,branches/q/filter::filter',
// Matches /admin/repos[,<offset>][/].
REPO_LIST_OFFSET: /^\/admin\/repos(,(\d+))?(\/)?$/,
REPO_LIST_FILTER: '/admin/repos/q/filter::filter',
REPO_LIST_FILTER_OFFSET: '/admin/repos/q/filter::filter,:offset',
// Matches /admin/repos/<repo>,branches[,<offset>].
BRANCH_LIST_OFFSET: /^\/admin\/repos\/(.+),branches(,(.+))?$/,
BRANCH_LIST_FILTER: '/admin/repos/:repo,branches/q/filter::filter',
BRANCH_LIST_FILTER_OFFSET:
'/admin/projects/:project,branches/q/filter::filter,:offset',
'/admin/repos/:repo,branches/q/filter::filter,:offset',
// Matches /admin/projects/<project>,tags[,<offset>].
TAG_LIST_OFFSET: /^\/admin\/projects\/(.+),tags(,(.+))?$/,
TAG_LIST_FILTER: '/admin/projects/:project,tags/q/filter::filter',
// Matches /admin/repos/<repo>,tags[,<offset>].
TAG_LIST_OFFSET: /^\/admin\/repos\/(.+),tags(,(.+))?$/,
TAG_LIST_FILTER: '/admin/repos/:repo,tags/q/filter::filter',
TAG_LIST_FILTER_OFFSET:
'/admin/projects/:project,tags/q/filter::filter,:offset',
'/admin/repos/:repo,tags/q/filter::filter,:offset',
PLUGINS: /^\/plugins\/(.+)$/,
@ -662,11 +664,14 @@
this._mapRoute(RoutePattern.GROUP, '_handleGroupRoute', true);
this._mapRoute(RoutePattern.PROJECT_COMMANDS,
'_handleProjectCommandsRoute', true);
this._mapRoute(RoutePattern.PROJECT_OLD,
'_handleProjectsOldRoute');
this._mapRoute(RoutePattern.PROJECT_ACCESS,
'_handleProjectAccessRoute');
this._mapRoute(RoutePattern.REPO_COMMANDS,
'_handleRepoCommandsRoute', true);
this._mapRoute(RoutePattern.REPO_ACCESS,
'_handleRepoAccessRoute');
this._mapRoute(RoutePattern.BRANCH_LIST_OFFSET,
'_handleBranchListOffsetRoute');
@ -692,16 +697,16 @@
this._mapRoute(RoutePattern.LEGACY_CREATE_PROJECT,
'_handleCreateProjectRoute', true);
this._mapRoute(RoutePattern.PROJECT_LIST_OFFSET,
'_handleProjectListOffsetRoute');
this._mapRoute(RoutePattern.REPO_LIST_OFFSET,
'_handleRepoListOffsetRoute');
this._mapRoute(RoutePattern.PROJECT_LIST_FILTER_OFFSET,
'_handleProjectListFilterOffsetRoute');
this._mapRoute(RoutePattern.REPO_LIST_FILTER_OFFSET,
'_handleRepoListFilterOffsetRoute');
this._mapRoute(RoutePattern.PROJECT_LIST_FILTER,
'_handleProjectListFilterRoute');
this._mapRoute(RoutePattern.REPO_LIST_FILTER,
'_handleRepoListFilterRoute');
this._mapRoute(RoutePattern.PROJECT, '_handleProjectRoute');
this._mapRoute(RoutePattern.REPO, '_handleRepoRoute');
this._mapRoute(RoutePattern.PLUGINS, '_handlePassThroughRoute');
@ -967,30 +972,38 @@
});
},
_handleProjectCommandsRoute(data) {
_handleProjectsOldRoute(data) {
if (data.params[1]) {
this._redirect('/admin/repos/' + encodeURIComponent(data.params[1]));
} else {
this._redirect('/admin/repos');
}
},
_handleRepoCommandsRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-commands',
adminView: 'gr-repo-commands',
detailType: 'commands',
project: data.params[0],
repo: data.params[0],
});
},
_handleProjectAccessRoute(data) {
_handleRepoAccessRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-access',
adminView: 'gr-repo-access',
detailType: 'access',
project: data.params[0],
repo: data.params[0],
});
},
_handleBranchListOffsetRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'branches',
project: data.params[0],
repo: data.params[0],
offset: data.params[2] || 0,
filter: null,
});
@ -999,9 +1012,9 @@
_handleBranchListFilterOffsetRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'branches',
project: data.params.project,
repo: data.params.repo,
offset: data.params.offset,
filter: data.params.filter,
});
@ -1010,9 +1023,9 @@
_handleBranchListFilterRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'branches',
project: data.params.project,
repo: data.params.repo,
filter: data.params.filter || null,
});
},
@ -1020,9 +1033,9 @@
_handleTagListOffsetRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'tags',
project: data.params[0],
repo: data.params[0],
offset: data.params[2] || 0,
filter: null,
});
@ -1031,9 +1044,9 @@
_handleTagListFilterOffsetRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'tags',
project: data.params.project,
repo: data.params.repo,
offset: data.params.offset,
filter: data.params.filter,
});
@ -1042,36 +1055,36 @@
_handleTagListFilterRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'tags',
project: data.params.project,
repo: data.params.repo,
filter: data.params.filter || null,
});
},
_handleProjectListOffsetRoute(data) {
_handleRepoListOffsetRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
offset: data.params[1] || 0,
filter: null,
openCreateModal: data.hash === 'create',
});
},
_handleProjectListFilterOffsetRoute(data) {
_handleRepoListFilterOffsetRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
offset: data.params.offset,
filter: data.params.filter,
});
},
_handleProjectListFilterRoute(data) {
_handleRepoListFilterRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
filter: data.params.filter || null,
});
},
@ -1088,11 +1101,11 @@
this._redirect('/admin/groups#create');
},
_handleProjectRoute(data) {
_handleRepoRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
project: data.params[0],
adminView: 'gr-project',
repo: data.params[0],
adminView: 'gr-repo',
});
},

View File

@ -138,7 +138,7 @@ limitations under the License.
'_handlePluginListFilterRoute',
'_handlePluginListOffsetRoute',
'_handlePluginListRoute',
'_handleProjectCommandsRoute',
'_handleRepoCommandsRoute',
'_handleSettingsLegacyRoute',
'_handleSettingsRoute',
];
@ -156,12 +156,13 @@ limitations under the License.
'_handleLegacyLinenum',
'_handleImproperlyEncodedPlusRoute',
'_handlePassThroughRoute',
'_handleProjectAccessRoute',
'_handleProjectDashboardRoute',
'_handleProjectListFilterOffsetRoute',
'_handleProjectListFilterRoute',
'_handleProjectListOffsetRoute',
'_handleProjectRoute',
'_handleProjectsOldRoute',
'_handleRepoAccessRoute',
'_handleRepoListFilterOffsetRoute',
'_handleRepoListFilterRoute',
'_handleRepoListOffsetRoute',
'_handleRepoRoute',
'_handleQueryLegacySuffixRoute',
'_handleQueryRoute',
'_handleRegisterRoute',
@ -921,33 +922,33 @@ limitations under the License.
});
});
suite('project routes', () => {
test('_handleProjectRoute', () => {
suite('repo routes', () => {
test('_handleRepoRoute', () => {
const data = {params: {0: 4321}};
assertDataToParams(data, '_handleProjectRoute', {
assertDataToParams(data, '_handleRepoRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project',
project: 4321,
adminView: 'gr-repo',
repo: 4321,
});
});
test('_handleProjectCommandsRoute', () => {
test('_handleRepoCommandsRoute', () => {
const data = {params: {0: 4321}};
assertDataToParams(data, '_handleProjectCommandsRoute', {
assertDataToParams(data, '_handleRepoCommandsRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-commands',
adminView: 'gr-repo-commands',
detailType: 'commands',
project: 4321,
repo: 4321,
});
});
test('_handleProjectAccessRoute', () => {
test('_handleRepoAccessRoute', () => {
const data = {params: {0: 4321}};
assertDataToParams(data, '_handleProjectAccessRoute', {
assertDataToParams(data, '_handleRepoAccessRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-access',
adminView: 'gr-repo-access',
detailType: 'access',
project: 4321,
repo: 4321,
});
});
@ -956,9 +957,9 @@ limitations under the License.
const data = {params: {0: 4321}};
assertDataToParams(data, '_handleBranchListOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'branches',
project: 4321,
repo: 4321,
offset: 0,
filter: null,
});
@ -966,33 +967,33 @@ limitations under the License.
data.params[2] = 42;
assertDataToParams(data, '_handleBranchListOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'branches',
project: 4321,
repo: 4321,
offset: 42,
filter: null,
});
});
test('_handleBranchListFilterOffsetRoute', () => {
const data = {params: {project: 4321, filter: 'foo', offset: 42}};
const data = {params: {repo: 4321, filter: 'foo', offset: 42}};
assertDataToParams(data, '_handleBranchListFilterOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'branches',
project: 4321,
repo: 4321,
offset: 42,
filter: 'foo',
});
});
test('_handleBranchListFilterRoute', () => {
const data = {params: {project: 4321, filter: 'foo'}};
const data = {params: {repo: 4321, filter: 'foo'}};
assertDataToParams(data, '_handleBranchListFilterRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'branches',
project: 4321,
repo: 4321,
filter: 'foo',
});
});
@ -1003,99 +1004,99 @@ limitations under the License.
const data = {params: {0: 4321}};
assertDataToParams(data, '_handleTagListOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'tags',
project: 4321,
repo: 4321,
offset: 0,
filter: null,
});
});
test('_handleTagListFilterOffsetRoute', () => {
const data = {params: {project: 4321, filter: 'foo', offset: 42}};
const data = {params: {repo: 4321, filter: 'foo', offset: 42}};
assertDataToParams(data, '_handleTagListFilterOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'tags',
project: 4321,
repo: 4321,
offset: 42,
filter: 'foo',
});
});
test('_handleTagListFilterRoute', () => {
const data = {params: {project: 4321}};
const data = {params: {repo: 4321}};
assertDataToParams(data, '_handleTagListFilterRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'tags',
project: 4321,
repo: 4321,
filter: null,
});
data.params.filter = 'foo';
assertDataToParams(data, '_handleTagListFilterRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-detail-list',
adminView: 'gr-repo-detail-list',
detailType: 'tags',
project: 4321,
repo: 4321,
filter: 'foo',
});
});
});
suite('project list routes', () => {
test('_handleProjectListOffsetRoute', () => {
suite('repo list routes', () => {
test('_handleRepoListOffsetRoute', () => {
const data = {params: {}};
assertDataToParams(data, '_handleProjectListOffsetRoute', {
assertDataToParams(data, '_handleRepoListOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
offset: 0,
filter: null,
openCreateModal: false,
});
data.params[1] = 42;
assertDataToParams(data, '_handleProjectListOffsetRoute', {
assertDataToParams(data, '_handleRepoListOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
offset: 42,
filter: null,
openCreateModal: false,
});
data.hash = 'create';
assertDataToParams(data, '_handleProjectListOffsetRoute', {
assertDataToParams(data, '_handleRepoListOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
offset: 42,
filter: null,
openCreateModal: true,
});
});
test('_handleProjectListFilterOffsetRoute', () => {
test('_handleRepoListFilterOffsetRoute', () => {
const data = {params: {filter: 'foo', offset: 42}};
assertDataToParams(data, '_handleProjectListFilterOffsetRoute', {
assertDataToParams(data, '_handleRepoListFilterOffsetRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
offset: 42,
filter: 'foo',
});
});
test('_handleProjectListFilterRoute', () => {
test('_handleRepoListFilterRoute', () => {
const data = {params: {}};
assertDataToParams(data, '_handleProjectListFilterRoute', {
assertDataToParams(data, '_handleRepoListFilterRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
filter: null,
});
data.params.filter = 'foo';
assertDataToParams(data, '_handleProjectListFilterRoute', {
assertDataToParams(data, '_handleRepoListFilterRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-list',
adminView: 'gr-repo-list',
filter: 'foo',
});
});

View File

@ -14,19 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../admin/gr-project-command/gr-project-command.html">
<link rel="import" href="../../admin/gr-repo-command/gr-repo-command.html">
<dom-module id="gr-plugin-project-command">
<dom-module id="gr-plugin-repo-command">
<template>
<gr-project-command title="[[title]]">
</gr-project-command>
<gr-repo-command title="[[title]]">
</gr-repo-command>
</template>
<script>
Polymer({
is: 'gr-plugin-project-command',
is: 'gr-plugin-repo-command',
properties: {
title: String,
projectName: String,
repoName: String,
config: Object,
},
});

View File

@ -16,8 +16,8 @@ limitations under the License.
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
<link rel="import" href="gr-plugin-project-command.html">
<link rel="import" href="gr-plugin-repo-command.html">
<dom-module id="gr-project-api">
<script src="gr-project-api.js"></script>
<dom-module id="gr-repo-api">
<script src="gr-repo-api.js"></script>
</dom-module>

View File

@ -15,37 +15,37 @@
'use strict';
// Prevent redefinition.
if (window.GrProjectApi) { return; }
if (window.GrRepoApi) { return; }
function GrProjectApi(plugin) {
function GrRepoApi(plugin) {
this._hook = null;
this.plugin = plugin;
}
GrProjectApi.prototype._createHook = function(title) {
this._hook = this.plugin.hook('project-command').onAttached(element => {
GrRepoApi.prototype._createHook = function(title) {
this._hook = this.plugin.hook('repo-command').onAttached(element => {
const pluginCommand =
document.createElement('gr-plugin-project-command');
document.createElement('gr-plugin-repo-command');
pluginCommand.title = title;
element.appendChild(pluginCommand);
});
};
GrProjectApi.prototype.createCommand = function(title, callback) {
GrRepoApi.prototype.createCommand = function(title, callback) {
if (this._hook) {
console.warn('Already set up.');
return this._hook;
}
this._createHook(title);
this._hook.onAttached(element => {
if (callback(element.projectName, element.config) === false) {
if (callback(element.repoName, element.config) === false) {
element.hidden = true;
}
});
return this;
};
GrProjectApi.prototype.onTap = function(callback) {
GrRepoApi.prototype.onTap = function(callback) {
if (!this._hook) {
console.warn('Call createCommand first.');
return this;
@ -56,5 +56,5 @@
return this;
};
window.GrProjectApi = GrProjectApi;
window.GrRepoApi = GrRepoApi;
})(window);

View File

@ -16,27 +16,27 @@ limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project-api</title>
<title>gr-repo-api</title>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.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-endpoint-decorator/gr-endpoint-decorator.html">
<link rel="import" href="gr-project-api.html">
<link rel="import" href="gr-repo-api.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-endpoint-decorator name="project-command">
<gr-endpoint-decorator name="repo-command">
</gr-endpoint-decorator>
</template>
</test-fixture>
<script>
suite('gr-project-api tests', () => {
suite('gr-repo-api tests', () => {
let sandbox;
let projectApi;
let repoApi;
setup(() => {
sandbox = sinon.sandbox.create();
@ -44,30 +44,30 @@ limitations under the License.
Gerrit.install(p => { plugin = p; }, '0.1',
'http://test.com/plugins/testplugin/static/test.js');
sandbox.stub(Gerrit, '_arePluginsLoaded').returns(true);
projectApi = plugin.project();
repoApi = plugin.project();
});
teardown(() => {
projectApi = null;
repoApi = null;
sandbox.restore();
});
test('exists', () => {
assert.isOk(projectApi);
assert.isOk(repoApi);
});
test('works', done => {
const attachedStub = sandbox.stub();
const tapStub = sandbox.stub();
projectApi
repoApi
.createCommand('foo', attachedStub)
.onTap(tapStub);
const element = fixture('basic');
flush(() => {
assert.isTrue(attachedStub.called);
const pluginCommand = element.$$('gr-plugin-project-command');
const pluginCommand = element.$$('gr-plugin-repo-command');
assert.isOk(pluginCommand);
const command = pluginCommand.$$('gr-project-command');
const command = pluginCommand.$$('gr-repo-command');
assert.isOk(command);
assert.equal(command.title, 'foo');
assert.isFalse(tapStub.called);

View File

@ -21,7 +21,7 @@ limitations under the License.
<link rel="import" href="../../plugins/gr-dom-hooks/gr-dom-hooks.html">
<link rel="import" href="../../plugins/gr-event-helper/gr-event-helper.html">
<link rel="import" href="../../plugins/gr-popup-interface/gr-popup-interface.html">
<link rel="import" href="../../plugins/gr-project-api/gr-project-api.html">
<link rel="import" href="../../plugins/gr-repo-api/gr-repo-api.html">
<link rel="import" href="../../plugins/gr-theme-api/gr-theme-api.html">
<link rel="import" href="../gr-rest-api-interface/gr-rest-api-interface.html">

View File

@ -207,7 +207,7 @@
};
Plugin.prototype.project = function() {
return new GrProjectApi(this);
return new GrRepoApi(this);
};
/**

View File

@ -234,32 +234,40 @@
return this._fetchSharedCacheURL('/config/server/info');
},
getProject(project) {
getRepo(repo) {
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this._fetchSharedCacheURL(
'/projects/' + encodeURIComponent(project));
'/projects/' + encodeURIComponent(repo));
},
getProjectConfig(project) {
getProjectConfig(repo) {
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this._fetchSharedCacheURL(
'/projects/' + encodeURIComponent(project) + '/config');
'/projects/' + encodeURIComponent(repo) + '/config');
},
getProjectAccess(project) {
getRepoAccess(repo) {
// TODO: Rename rest api from project to repo
// supports it.
return this._fetchSharedCacheURL(
'/access/?project=' + encodeURIComponent(project));
'/access/?project=' + encodeURIComponent(repo));
},
saveProjectConfig(project, config, opt_errFn, opt_ctx) {
const encodeName = encodeURIComponent(project);
saveRepoConfig(repo, config, opt_errFn, opt_ctx) {
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
const encodeName = encodeURIComponent(repo);
return this.send('PUT', `/projects/${encodeName}/config`, config,
opt_errFn, opt_ctx);
},
runProjectGC(project, opt_errFn, opt_ctx) {
if (!project) {
return '';
}
const encodeName = encodeURIComponent(project);
runRepoGC(repo, opt_errFn, opt_ctx) {
if (!repo) { return ''; }
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
const encodeName = encodeURIComponent(repo);
return this.send('POST', `/projects/${encodeName}/gc`, '',
opt_errFn, opt_ctx);
},
@ -269,8 +277,10 @@
* @param {function(?Response, string=)=} opt_errFn
* @param {?=} opt_ctx
*/
createProject(config, opt_errFn, opt_ctx) {
createRepo(config, opt_errFn, opt_ctx) {
if (!config.name) { return ''; }
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
const encodeName = encodeURIComponent(config.name);
return this.send('PUT', `/projects/${encodeName}`, config, opt_errFn,
opt_ctx);
@ -294,16 +304,16 @@
},
/**
* @param {string} project
* @param {string} repo
* @param {string} ref
* @param {function(?Response, string=)=} opt_errFn
* @param {?=} opt_ctx
*/
deleteProjectBranches(project, ref, opt_errFn, opt_ctx) {
if (!project || !ref) {
return '';
}
const encodeName = encodeURIComponent(project);
deleteRepoBranches(repo, ref, opt_errFn, opt_ctx) {
if (!repo || !ref) { return ''; }
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
const encodeName = encodeURIComponent(repo);
const encodeRef = encodeURIComponent(ref);
return this.send('DELETE',
`/projects/${encodeName}/branches/${encodeRef}`, '',
@ -311,16 +321,16 @@
},
/**
* @param {string} project
* @param {string} repo
* @param {string} ref
* @param {function(?Response, string=)=} opt_errFn
* @param {?=} opt_ctx
*/
deleteProjectTags(project, ref, opt_errFn, opt_ctx) {
if (!project || !ref) {
return '';
}
const encodeName = encodeURIComponent(project);
deleteRepoTags(repo, ref, opt_errFn, opt_ctx) {
if (!repo || !ref) { return ''; }
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
const encodeName = encodeURIComponent(repo);
const encodeRef = encodeURIComponent(ref);
return this.send('DELETE',
`/projects/${encodeName}/tags/${encodeRef}`, '',
@ -334,8 +344,10 @@
* @param {function(?Response, string=)=} opt_errFn
* @param {?=} opt_ctx
*/
createProjectBranch(name, branch, revision, opt_errFn, opt_ctx) {
createRepoBranch(name, branch, revision, opt_errFn, opt_ctx) {
if (!name || !branch || !revision) { return ''; }
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
const encodeName = encodeURIComponent(name);
const encodeBranch = encodeURIComponent(branch);
return this.send('PUT',
@ -350,8 +362,10 @@
* @param {function(?Response, string=)=} opt_errFn
* @param {?=} opt_ctx
*/
createProjectTag(name, tag, revision, opt_errFn, opt_ctx) {
createRepoTag(name, tag, revision, opt_errFn, opt_ctx) {
if (!name || !tag || !revision) { return ''; }
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
const encodeName = encodeURIComponent(name);
const encodeTag = encodeURIComponent(tag);
return this.send('PUT', `/projects/${encodeName}/tags/${encodeTag}`,
@ -1060,54 +1074,62 @@
/**
* @param {string} filter
* @param {number} projectsPerPage
* @param {number} reposPerPage
* @param {number=} opt_offset
* @return {!Promise<?Object>}
*/
getProjects(filter, projectsPerPage, opt_offset) {
getRepos(filter, reposPerPage, opt_offset) {
const offset = opt_offset || 0;
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this._fetchSharedCacheURL(
`/projects/?d&n=${projectsPerPage + 1}&S=${offset}` +
`/projects/?d&n=${reposPerPage + 1}&S=${offset}` +
this._computeFilter(filter)
);
},
setProjectHead(project, ref) {
setRepoHead(repo, ref) {
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this.send(
'PUT', `/projects/${encodeURIComponent(project)}/HEAD`, {ref});
'PUT', `/projects/${encodeURIComponent(repo)}/HEAD`, {ref});
},
/**
* @param {string} filter
* @param {string} project
* @param {number} projectsBranchesPerPage
* @param {string} repo
* @param {number} reposBranchesPerPage
* @param {number=} opt_offset
* @return {!Promise<?Object>}
*/
getProjectBranches(filter, project, projectsBranchesPerPage, opt_offset) {
getRepoBranches(filter, repo, reposBranchesPerPage, opt_offset) {
const offset = opt_offset || 0;
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this.fetchJSON(
`/projects/${encodeURIComponent(project)}/branches` +
`?n=${projectsBranchesPerPage + 1}&S=${offset}` +
`/projects/${encodeURIComponent(repo)}/branches` +
`?n=${reposBranchesPerPage + 1}&S=${offset}` +
this._computeFilter(filter)
);
},
/**
* @param {string} filter
* @param {string} project
* @param {number} projectsTagsPerPage
* @param {string} repo
* @param {number} reposTagsPerPage
* @param {number=} opt_offset
* @return {!Promise<?Object>}
*/
getProjectTags(filter, project, projectsTagsPerPage, opt_offset) {
getRepoTags(filter, repo, reposTagsPerPage, opt_offset) {
const offset = opt_offset || 0;
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this.fetchJSON(
`/projects/${encodeURIComponent(project)}/tags` +
`?n=${projectsTagsPerPage + 1}&S=${offset}` +
`/projects/${encodeURIComponent(repo)}/tags` +
`?n=${reposTagsPerPage + 1}&S=${offset}` +
this._computeFilter(filter)
);
},
@ -1127,15 +1149,19 @@
);
},
getProjectAccessRights(projectName) {
getRepoAccessRights(repoName) {
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this._fetchSharedCacheURL(
`/projects/${encodeURIComponent(projectName)}/access`);
`/projects/${encodeURIComponent(repoName)}/access`);
},
setProjectAccessRights(projectName, projectInfo) {
setRepoAccessRights(repoName, repoInfo) {
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this.send(
'POST', `/projects/${encodeURIComponent(projectName)}/access`,
projectInfo);
'POST', `/projects/${encodeURIComponent(repoName)}/access`,
repoInfo);
},
setProjectAccessRightsForReview(projectName, projectInfo) {

View File

@ -799,9 +799,9 @@ limitations under the License.
{reason: 'removal reason'}));
});
test('createProject encodes name', () => {
test('createRepo encodes name', () => {
const sendStub = sandbox.stub(element, 'send');
element.createProject({name: 'x/y'});
element.createRepo({name: 'x/y'});
assert.equal(sendStub.lastCall.args[1], '/projects/x%2Fy');
});
@ -814,31 +814,31 @@ limitations under the License.
});
});
test('getProjects', () => {
test('getRepos', () => {
sandbox.stub(element, '_fetchSharedCacheURL');
element.getProjects('test', 25);
element.getRepos('test', 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=0&m=test'));
element.getProjects(null, 25);
element.getRepos(null, 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=0'));
element.getProjects('test', 25, 25);
element.getRepos('test', 25, 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=25&m=test'));
});
test('getProjects filter', () => {
test('getRepos filter', () => {
sandbox.stub(element, '_fetchSharedCacheURL');
element.getProjects('test/test/test', 25);
element.getRepos('test/test/test', 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=0&m=test%2Ftest%2Ftest'));
});
test('getProjects filter regex', () => {
test('getRepos filter regex', () => {
sandbox.stub(element, '_fetchSharedCacheURL');
element.getProjects('^test.*', 25);
element.getRepos('^test.*', 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=0&r=%5Etest.*'));
});

View File

@ -1,10 +1,10 @@
<dom-module id="sample-project-command">
<dom-module id="sample-repo-command">
<script>
Gerrit.install(plugin => {
// High-level API
plugin.project()
.createCommand('Bork', (projectName, projectConfig) => {
if (projectName !== 'All-Projects') {
.createCommand('Bork', (repoName, projectConfig) => {
if (repoName !== 'All-Projects') {
return false;
}
}).onTap(() => {
@ -13,26 +13,26 @@
// Low-level API
plugin.registerCustomComponent(
'project-command', 'project-command-low');
'repo-command', 'repo-command-low');
});
</script>
</dom-module>
<!-- Low-level custom component for project command. -->
<dom-module id="project-command-low">
<!-- Low-level custom component for repo command. -->
<dom-module id="repo-command-low">
<template>
<gr-project-command
<gr-repo-command
title="Low-level bork"
on-command-tap="_handleCommandTap">
</gr-project-command>
</gr-repo-command>
</template>
<script>
Polymer({
is: 'project-command-low',
is: 'repo-command-low',
attached() {
console.log(this.projectName);
console.log(this.repoName);
console.log(this.config);
this.hidden = this.projectName !== 'All-Projects';
this.hidden = this.repoName !== 'All-Projects';
},
_handleCommandTap() {
alert('(softly) bork, bork.');

View File

@ -38,18 +38,18 @@ limitations under the License.
'admin/gr-create-change-dialog/gr-create-change-dialog_test.html',
'admin/gr-create-group-dialog/gr-create-group-dialog_test.html',
'admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html',
'admin/gr-create-project-dialog/gr-create-project-dialog_test.html',
'admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html',
'admin/gr-group-audit-log/gr-group-audit-log_test.html',
'admin/gr-group-members/gr-group-members_test.html',
'admin/gr-group/gr-group_test.html',
'admin/gr-permission/gr-permission_test.html',
'admin/gr-plugin-list/gr-plugin-list_test.html',
'admin/gr-project-access/gr-project-access_test.html',
'admin/gr-project-command/gr-project-command_test.html',
'admin/gr-project-commands/gr-project-commands_test.html',
'admin/gr-project-detail-list/gr-project-detail-list_test.html',
'admin/gr-project-list/gr-project-list_test.html',
'admin/gr-project/gr-project_test.html',
'admin/gr-repo-access/gr-repo-access_test.html',
'admin/gr-repo-command/gr-repo-command_test.html',
'admin/gr-repo-commands/gr-repo-commands_test.html',
'admin/gr-repo-detail-list/gr-repo-detail-list_test.html',
'admin/gr-repo-list/gr-repo-list_test.html',
'admin/gr-repo/gr-repo_test.html',
'admin/gr-rule-editor/gr-rule-editor_test.html',
'change-list/gr-change-list-item/gr-change-list-item_test.html',
'change-list/gr-change-list-view/gr-change-list-view_test.html',
@ -112,10 +112,10 @@ limitations under the License.
'plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html',
'plugins/gr-event-helper/gr-event-helper_test.html',
'plugins/gr-external-style/gr-external-style_test.html',
'plugins/gr-project-api/gr-project-api_test.html',
'plugins/gr-plugin-host/gr-plugin-host_test.html',
'plugins/gr-popup-interface/gr-plugin-popup_test.html',
'plugins/gr-popup-interface/gr-popup-interface_test.html',
'plugins/gr-repo-api/gr-repo-api_test.html',
'settings/gr-account-info/gr-account-info_test.html',
'settings/gr-change-table-editor/gr-change-table-editor_test.html',
'settings/gr-email-editor/gr-email-editor_test.html',