PolyGerrit: Show a list of projects on /admin/projects page
When going to /admin/projects/test for example it will take you back to the old ui to view the project configs. Bug: Issue 5966 Change-Id: I7d6fb8f17a235602bba0c535cfe4b43030f515a3
This commit is contained in:
committed by
Becky Siegel
parent
5fe963e635
commit
2719063a1e
@@ -0,0 +1,109 @@
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
|
||||
<link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
|
||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
|
||||
|
||||
<link rel="import" href="../../../styles/gr-form-styles.html">
|
||||
|
||||
<dom-module id="gr-admin-project-list">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
tr.project-table {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
#projectList {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
td {
|
||||
flex-shrink: 0;
|
||||
padding: .3em .5em;
|
||||
}
|
||||
th {
|
||||
background-color: #ddd;
|
||||
border-bottom: 1px solid #eee;
|
||||
font-weight: bold;
|
||||
padding: .3em .5em;
|
||||
text-align: left;
|
||||
}
|
||||
.readOnly,
|
||||
.repositoryBrowser,
|
||||
.description {
|
||||
white-space: nowrap;
|
||||
}
|
||||
a {
|
||||
color: var(--default-text-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
nav {
|
||||
padding: .5em 0;
|
||||
text-align: center;
|
||||
}
|
||||
nav a {
|
||||
display: inline-block;
|
||||
}
|
||||
nav a:first-of-type {
|
||||
margin-right: .5em;
|
||||
}
|
||||
</style>
|
||||
<table id="projectList">
|
||||
<tr class="headerRow">
|
||||
<th class="name topHeader">Project Name</th>
|
||||
<th class="description topHeader">Project Description</th>
|
||||
<th class="repositoryBrowser topHeader">Repository Browser</th>
|
||||
<th class="readOnly topHeader">Read only</th>
|
||||
</tr>
|
||||
<template is="dom-repeat" items="[[_projects]]">
|
||||
<tr class="project-table">
|
||||
<td class="name">
|
||||
<a href$="[[_getUrl(item.id)]]">[[item.name]]</a>
|
||||
</td>
|
||||
<td class="description">[[item.description]]</td>
|
||||
<td class="repositoryBrowser">
|
||||
<template is="dom-repeat"
|
||||
items="[[_computeWeblink(item)]]" as="link">
|
||||
<a href$="[[link.url]]" class="webLink" rel="noopener" target="_blank">
|
||||
([[link.name]])
|
||||
</a>
|
||||
</template>
|
||||
</td>
|
||||
<td class="readOnly">[[_readOnly(item)]]</td>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
<nav>
|
||||
<a id="prevArrow"
|
||||
href$="[[_computeNavLink(_offset, -1, _projectsPerPage)]]"
|
||||
hidden$="[[_hidePrevArrow(_offset)]]" hidden>← Prev</a>
|
||||
<a id="nextArrow"
|
||||
href$="[[_computeNavLink(_offset, 1, _projectsPerPage)]]"
|
||||
hidden$="[[_hideNextArrow(_loading, _projects)]]" hidden>
|
||||
Next →</a>
|
||||
</nav>
|
||||
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||
</template>
|
||||
<script src="gr-admin-project-list.js"></script>
|
||||
</dom-module>
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright (C) 2017 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-admin-project-list',
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
* Offset of currently visible query results.
|
||||
*/
|
||||
_offset: Number,
|
||||
|
||||
_projects: Array,
|
||||
|
||||
_projectsPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
|
||||
listeners: {
|
||||
'next-page': '_handleNextPage',
|
||||
'previous-page': '_handlePreviousPage',
|
||||
},
|
||||
|
||||
_paramsChanged(value) {
|
||||
this._loading = true;
|
||||
|
||||
if (value && value.offset) {
|
||||
this._offset = value.offset;
|
||||
} else {
|
||||
this._offset = 0;
|
||||
}
|
||||
|
||||
return this.$.restAPI.getProjects(this._projectsPerPage, this._offset)
|
||||
.then(projects => {
|
||||
if (!projects) {
|
||||
this._projects = [];
|
||||
return;
|
||||
}
|
||||
this._projects = Object.keys(projects)
|
||||
.map(key => {
|
||||
const project = projects[key];
|
||||
project.name = key;
|
||||
return project;
|
||||
});
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
_readOnly(item) {
|
||||
return item.state === 'READ_ONLY' ? 'Y' : 'N';
|
||||
},
|
||||
|
||||
_getUrl(item) {
|
||||
return this.getBaseUrl() + '/admin/projects/' +
|
||||
this.encodeURL(item, false);
|
||||
},
|
||||
|
||||
_isProjectWebLink(link) {
|
||||
return link.name === 'gitiles' || link.name === 'gitweb';
|
||||
},
|
||||
|
||||
_computeWeblink(project) {
|
||||
if (!project.web_links) {
|
||||
return '';
|
||||
}
|
||||
const webLinks = project.web_links.filter(
|
||||
l => !this._isProjectWebLink(l));
|
||||
return webLinks.length ? webLinks : null;
|
||||
},
|
||||
|
||||
_computeNavLink(offset, direction, projectsPerPage) {
|
||||
// Offset could be a string when passed from the router.
|
||||
offset = +(offset || 0);
|
||||
const newOffset = Math.max(0, offset + (projectsPerPage * direction));
|
||||
let href = this.getBaseUrl() + '/admin/projects';
|
||||
if (newOffset > 0) {
|
||||
href += ',' + newOffset;
|
||||
}
|
||||
return href;
|
||||
},
|
||||
|
||||
_hidePrevArrow(offset) {
|
||||
return offset === 0;
|
||||
},
|
||||
|
||||
_hideNextArrow(loading, projects) {
|
||||
let lastPage = false;
|
||||
if (projects.length < this._projectsPerPage + 1) {
|
||||
lastPage = true;
|
||||
}
|
||||
return loading || lastPage || !projects || !projects.length;
|
||||
},
|
||||
|
||||
_handleNextPage() {
|
||||
if (this.$.nextArrow.hidden) { return; }
|
||||
page.show(this._computeNavLink(
|
||||
this._offset, 1, this._projectsPerPage));
|
||||
},
|
||||
|
||||
_handlePreviousPage() {
|
||||
if (this.$.prevArrow.hidden) { return; }
|
||||
page.show(this._computeNavLink(
|
||||
this._offset, -1, this._projectsPerPage));
|
||||
},
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>gr-admin-project-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="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
|
||||
|
||||
<link rel="import" href="gr-admin-project-list.html">
|
||||
|
||||
<script>void(0);</script>
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-admin-project-list></gr-admin-project-list>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
let counter = 0;
|
||||
const projectGenerator = () => {
|
||||
return {
|
||||
id: `test${++counter}`,
|
||||
state: 'ACTIVE',
|
||||
web_links: [
|
||||
{
|
||||
name: 'diffusion',
|
||||
url: `https://phabricator.example.org/r/project/test${counter}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
suite('gr-admin-project-list tests', () => {
|
||||
let element;
|
||||
let projects;
|
||||
let value;
|
||||
|
||||
suite('list with projects', () => {
|
||||
setup(done => {
|
||||
projects = _.times(30, projectGenerator);
|
||||
|
||||
stub('gr-rest-api-interface', {
|
||||
getProjects(num, offset) {
|
||||
return Promise.resolve(projects);
|
||||
},
|
||||
});
|
||||
|
||||
element = fixture('basic');
|
||||
element._paramsChanged(value).then(() => { flush(done); });
|
||||
});
|
||||
|
||||
test('test for test project in the list', done => {
|
||||
flush(() => {
|
||||
assert.equal(element._projects[1].id, 'test2');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('test next button', done => {
|
||||
flush(() => {
|
||||
let loading;
|
||||
assert.isFalse(element._hideNextArrow(loading, projects));
|
||||
loading = true;
|
||||
assert.isTrue(element._hideNextArrow(loading, projects));
|
||||
loading = false;
|
||||
assert.isFalse(element._hideNextArrow(loading, projects));
|
||||
element._projects = [];
|
||||
assert.isTrue(element._hideNextArrow(loading, element._projects));
|
||||
projects = _.times(4, projectGenerator);
|
||||
assert.isTrue(element._hideNextArrow(loading, projects));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('test for prev button', () => {
|
||||
flush(() => {
|
||||
let offset = 0;
|
||||
assert.isTrue(element._hidePrevArrow(offset));
|
||||
offset = 5;
|
||||
assert.isFalse(element._hidePrevArrow(offset));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('test with less then 25 projects', () => {
|
||||
setup(done => {
|
||||
projects = _.times(25, projectGenerator);
|
||||
|
||||
stub('gr-rest-api-interface', {
|
||||
getProjects(num, offset) {
|
||||
return Promise.resolve(projects);
|
||||
},
|
||||
});
|
||||
|
||||
element = fixture('basic');
|
||||
element._paramsChanged(value).then(() => { flush(done); });
|
||||
});
|
||||
|
||||
test('test next button', done => {
|
||||
flush(() => {
|
||||
let loading;
|
||||
assert.isTrue(element._hideNextArrow(loading, projects));
|
||||
projects = _.times(1, projectGenerator);
|
||||
assert.isTrue(element._hideNextArrow(loading, projects));
|
||||
projects = _.times(26, projectGenerator);
|
||||
assert.isFalse(element._hideNextArrow(loading, projects));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -108,6 +108,20 @@
|
||||
});
|
||||
});
|
||||
|
||||
// Matches /admin/projects[,<offset>][/].
|
||||
page(/^\/admin\/projects(,(\d+))?(\/)?$/, loadUser, data => {
|
||||
restAPI.getLoggedIn().then(loggedIn => {
|
||||
if (loggedIn) {
|
||||
app.params = {
|
||||
view: 'gr-admin-project-list',
|
||||
offset: data.params[1] || 0,
|
||||
};
|
||||
} else {
|
||||
page.redirect('/login/' + encodeURIComponent(data.canonicalPath));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
page('/admin/(.*)', loadUser, data => {
|
||||
restAPI.getLoggedIn().then(loggedIn => {
|
||||
if (loggedIn) {
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
<link rel="import" href="../behaviors/base-url-behavior/base-url-behavior.html">
|
||||
<link rel="import" href="../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
|
||||
<link rel="import" href="../styles/app-theme.html">
|
||||
<link rel="import" href="./admin/gr-admin-project-list/gr-admin-project-list.html">
|
||||
<link rel="import" href="./admin/gr-admin-view/gr-admin-view.html">
|
||||
<link rel="import" href="./change-list/gr-change-list-view/gr-change-list-view.html">
|
||||
<link rel="import" href="./change-list/gr-dashboard-view/gr-dashboard-view.html">
|
||||
@@ -125,6 +126,11 @@ limitations under the License.
|
||||
on-account-detail-update="_handleAccountDetailUpdate">
|
||||
</gr-settings-view>
|
||||
</template>
|
||||
<template is="dom-if" if="[[_showProjectListView]]" restamp="true">
|
||||
<gr-admin-project-list
|
||||
params="[[params]]"
|
||||
id="projectList"></gr-admin-project-list>
|
||||
</template>
|
||||
<template is="dom-if" if="[[_showAdminView]]" restamp="true">
|
||||
<gr-admin-view path="[[_path]]"></gr-admin-view>
|
||||
</template>
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
this.set('_showChangeView', view === 'gr-change-view');
|
||||
this.set('_showDiffView', view === 'gr-diff-view');
|
||||
this.set('_showSettingsView', view === 'gr-settings-view');
|
||||
this.set('_showProjectListView', view === 'gr-admin-project-list');
|
||||
this.set('_showAdminView', view === 'gr-admin-view');
|
||||
this.set('_showCLAView', view === 'gr-cla-view');
|
||||
if (this.params.justRegistered) {
|
||||
|
||||
@@ -559,6 +559,13 @@
|
||||
});
|
||||
},
|
||||
|
||||
getProjects(projectsPerPage, opt_offset) {
|
||||
const offset = opt_offset || 0;
|
||||
return this._fetchSharedCacheURL(
|
||||
`/projects/?d&n=${projectsPerPage}&S=${offset}`
|
||||
);
|
||||
},
|
||||
|
||||
getSuggestedGroups(inputVal, opt_n, opt_errFn, opt_ctx) {
|
||||
const params = {s: inputVal};
|
||||
if (opt_n) { params.n = opt_n; }
|
||||
|
||||
@@ -30,6 +30,7 @@ limitations under the License.
|
||||
// This seemed to be flakey when it was farther down the list. Keep at the
|
||||
// beginning.
|
||||
'gr-app_test.html',
|
||||
'admin/gr-admin-project-list/gr-admin-project-list_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',
|
||||
'change-list/gr-change-list/gr-change-list_test.html',
|
||||
|
||||
Reference in New Issue
Block a user