blob: 832400bbe089131a88179920648b8f7262b6f785 [file] [log] [blame]
Dave Borowitz8cdc76b2018-03-26 10:04:27 -04001/**
2 * @license
3 * Copyright (C) 2016 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Andrew Bonventre78792e82016-03-04 17:48:22 -050017(function() {
18 'use strict';
19
Logan Hanksc34e0b62017-10-03 01:40:54 -070020 const PROJECT_PLACEHOLDER_PATTERN = /\$\{project\}/g;
Kasper Nilsson8be6f1a2017-05-30 12:49:01 -070021
Andrew Bonventre78792e82016-03-04 17:48:22 -050022 Polymer({
23 is: 'gr-dashboard-view',
24
25 /**
26 * Fired when the title of the page should change.
27 *
28 * @event title-change
29 */
30
31 properties: {
Paladox noneebc64ef2018-04-06 13:57:21 +000032 account: {
Andrew Bonventre78792e82016-03-04 17:48:22 -050033 type: Object,
Wyatt Allen24caf0a2018-03-02 16:16:54 -080034 value: null,
Andrew Bonventre78792e82016-03-04 17:48:22 -050035 },
Kasper Nilsson8e6a64d2018-04-04 15:33:19 -070036 preferences: Object,
Becky Siegel8d92d532017-08-11 16:32:47 -070037 /** @type {{ selectedChangeIndex: number }} */
Andrew Bonventre78792e82016-03-04 17:48:22 -050038 viewState: Object,
Wyatt Allen809fef22017-10-03 10:41:32 +010039
Logan Hanks894eebd2018-11-13 11:54:30 -080040 /** @type {{ project: string, user: string }} */
Becky Siegel2c944762017-01-11 14:18:56 -080041 params: {
42 type: Object,
Becky Siegel2c944762017-01-11 14:18:56 -080043 },
Andrew Bonventre78792e82016-03-04 17:48:22 -050044
Kasper Nilsson57c1a282018-10-04 13:38:36 -070045 createChangeTap: {
46 type: Function,
47 value() {
48 return this._createChangeTap.bind(this);
49 },
50 },
51
Andrew Bonventre78792e82016-03-04 17:48:22 -050052 _results: Array,
Andrew Bonventre78792e82016-03-04 17:48:22 -050053
54 /**
55 * For showing a "loading..." string during ajax requests.
56 */
57 _loading: {
58 type: Boolean,
59 value: true,
60 },
Kasper Nilsson0dac13a2018-09-20 15:36:08 -070061
62 _showDraftsBanner: {
63 type: Boolean,
64 value: false,
65 },
Logan Hanks911b9b32018-09-20 08:29:32 -070066
67 _showNewUserHelp: {
68 type: Boolean,
69 value: false,
70 },
Andrew Bonventre78792e82016-03-04 17:48:22 -050071 },
72
Logan Hanks9ccf9d02017-08-11 14:17:36 -070073 observers: [
Logan Hanksaa501d02017-09-30 04:07:34 -070074 '_paramsChanged(params.*)',
Logan Hanks9ccf9d02017-08-11 14:17:36 -070075 ],
76
Kasper Nilsson8be6f1a2017-05-30 12:49:01 -070077 behaviors: [
Paladox none44b3a7c2019-08-06 14:36:29 +000078 Gerrit.FireBehavior,
Kasper Nilsson8be6f1a2017-05-30 12:49:01 -070079 Gerrit.RESTClientBehavior,
80 ],
81
82 get options() {
83 return this.listChangesOptionsToHex(
84 this.ListChangesOption.LABELS,
85 this.ListChangesOption.DETAILED_ACCOUNTS,
86 this.ListChangesOption.REVIEWED
87 );
88 },
89
Kasper Nilsson8e6a64d2018-04-04 15:33:19 -070090 attached() {
91 this._loadPreferences();
92 },
93
94 _loadPreferences() {
95 return this.$.restAPI.getLoggedIn().then(loggedIn => {
96 if (loggedIn) {
97 this.$.restAPI.getPreferences().then(preferences => {
98 this.preferences = preferences;
99 });
100 } else {
101 this.preferences = {};
102 }
103 });
104 },
105
Logan Hanksc34e0b62017-10-03 01:40:54 -0700106 _getProjectDashboard(project, dashboard) {
107 const errFn = response => {
108 this.fire('page-error', {response});
109 };
110 return this.$.restAPI.getDashboard(
111 project, dashboard, errFn).then(response => {
112 if (!response) {
113 return;
114 }
115 return {
116 title: response.title,
117 sections: response.sections.map(section => {
118 const suffix = response.foreach ? ' ' + response.foreach : '';
119 return {
120 name: section.name,
Paladox noneabbd26d2019-09-25 15:41:36 +0000121 query: (section.query + suffix).replace(
122 PROJECT_PLACEHOLDER_PATTERN, project),
Logan Hanksc34e0b62017-10-03 01:40:54 -0700123 };
124 }),
125 };
126 });
127 },
128
Logan Hankse6458a22017-08-11 14:41:57 -0700129 _computeTitle(user) {
Logan Hanksc34e0b62017-10-03 01:40:54 -0700130 if (!user || user === 'self') {
Logan Hankse6458a22017-08-11 14:41:57 -0700131 return 'My Reviews';
132 }
133 return 'Dashboard for ' + user;
Becky Siegel2c944762017-01-11 14:18:56 -0800134 },
Andrew Bonventre0c76ebb2016-05-03 22:24:25 -0400135
Logan Hanksc34e0b62017-10-03 01:40:54 -0700136 _isViewActive(params) {
137 return params.view === Gerrit.Nav.View.DASHBOARD;
138 },
139
Logan Hanksaa501d02017-09-30 04:07:34 -0700140 _paramsChanged(paramsChangeRecord) {
141 const params = paramsChangeRecord.base;
142
Logan Hanksc34e0b62017-10-03 01:40:54 -0700143 if (!this._isViewActive(params)) {
144 return Promise.resolve();
Logan Hanksaa501d02017-09-30 04:07:34 -0700145 }
146
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700147 return this._reload();
148 },
Logan Hanksaa501d02017-09-30 04:07:34 -0700149
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700150 /**
151 * Reloads the element.
152 *
153 * @return {Promise<!Object>}
154 */
155 _reload() {
Andrew Bonventre0c76ebb2016-05-03 22:24:25 -0400156 this._loading = true;
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700157 const {project, dashboard, title, user, sections} = this.params;
158 const dashboardPromise = project ?
159 this._getProjectDashboard(project, dashboard) :
Kasper Nilsson6750cf92018-09-17 13:43:12 -0700160 Promise.resolve(Gerrit.Nav.getUserDashboard(
161 user,
162 sections,
163 title || this._computeTitle(user)));
Logan Hanksc34e0b62017-10-03 01:40:54 -0700164
Logan Hanks911b9b32018-09-20 08:29:32 -0700165 const checkForNewUser = !project && user === 'self';
166 return dashboardPromise
Tao Zhou02ac6392019-10-01 13:39:17 +0200167 .then(res => {
168 if (res && res.title) {
169 this.fire('title-change', {title: res.title});
170 }
171 return this._fetchDashboardChanges(res, checkForNewUser);
172 })
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700173 .then(() => {
Kasper Nilsson0dac13a2018-09-20 15:36:08 -0700174 this._maybeShowDraftsBanner();
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700175 this.$.reporting.dashboardDisplayed();
176 }).catch(err => {
Tao Zhou02ac6392019-10-01 13:39:17 +0200177 this.fire('title-change', {
178 title: title || this._computeTitle(user),
179 });
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700180 console.warn(err);
Wyatt Allen4ec56152018-08-28 11:47:13 -0700181 }).then(() => { this._loading = false; });
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700182 },
183
184 /**
185 * Fetches the changes for each dashboard section and sets this._results
186 * with the response.
187 *
188 * @param {!Object} res
Logan Hanks911b9b32018-09-20 08:29:32 -0700189 * @param {boolean} checkForNewUser
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700190 * @return {Promise}
191 */
Logan Hanks911b9b32018-09-20 08:29:32 -0700192 _fetchDashboardChanges(res, checkForNewUser) {
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700193 if (!res) { return Promise.resolve(); }
Logan Hanks911b9b32018-09-20 08:29:32 -0700194
195 const queries = res.sections
196 .map(section => section.suffixForDashboard ?
197 section.query + ' ' + section.suffixForDashboard :
198 section.query);
199
200 if (checkForNewUser) {
Milutin Kristofic5f31b762019-10-07 15:17:31 +0000201 queries.push('owner:self limit:1');
Logan Hanks911b9b32018-09-20 08:29:32 -0700202 }
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700203
204 return this.$.restAPI.getChanges(null, queries, null, this.options)
205 .then(changes => {
Logan Hanks911b9b32018-09-20 08:29:32 -0700206 if (checkForNewUser) {
207 // Last set of results is not meant for dashboard display.
208 const lastResultSet = changes.pop();
209 this._showNewUserHelp = lastResultSet.length == 0;
210 }
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700211 this._results = changes.map((results, i) => ({
Milutin Kristofic497380f2019-10-09 16:19:54 +0200212 name: this._computeSectionName(res.sections[i].name, results),
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700213 query: res.sections[i].query,
214 results,
Logan Hanks1d3dc2a2018-09-19 13:18:59 -0700215 isOutgoing: res.sections[i].isOutgoing,
Logan Hanks911b9b32018-09-20 08:29:32 -0700216 })).filter((section, i) => i < res.sections.length && (
217 !res.sections[i].hideIfEmpty ||
218 section.results.length));
Kasper Nilssonf5136ec2018-08-17 14:11:09 -0700219 });
Andrew Bonventre78792e82016-03-04 17:48:22 -0500220 },
Logan Hanks2eaf8552017-07-17 10:15:39 -0700221
Milutin Kristofic497380f2019-10-09 16:19:54 +0200222 _computeSectionName(name, changes) {
223 if (!changes || !changes.length || changes.length == 0) {
224 return name;
225 }
226 const more = changes[changes.length - 1]._more_changes;
227 const numChanges = changes.length;
228 const andMore = more ? ' and more' : '';
229 const changeLabel = `change${numChanges > 1 ? 's' : ''}`;
230 return `${name} (${numChanges} ${changeLabel}${andMore})`;
231 },
232
Logan Hanks894eebd2018-11-13 11:54:30 -0800233 _computeUserHeaderClass(params) {
234 if (!params || !!params.project || !params.user
235 || params.user === 'self') {
236 return 'hide';
237 }
238 return '';
Wyatt Allen809fef22017-10-03 10:41:32 +0100239 },
Kasper Nilsson08ab3aa2018-07-12 11:15:41 -0700240
241 _handleToggleStar(e) {
242 this.$.restAPI.saveChangeStarred(e.detail.change._number,
243 e.detail.starred);
244 },
Sean Egan3278d7b2018-07-06 11:02:31 -0400245
246 _handleToggleReviewed(e) {
247 this.$.restAPI.saveChangeReviewed(e.detail.change._number,
248 e.detail.reviewed);
249 },
Kasper Nilsson0dac13a2018-09-20 15:36:08 -0700250
251 /**
252 * Banner is shown if a user is on their own dashboard and they have draft
253 * comments on closed changes.
254 */
255 _maybeShowDraftsBanner() {
256 this._showDraftsBanner = false;
257 if (!(this.params.user === 'self')) { return; }
258
259 const draftSection = this._results
260 .find(section => section.query === 'has:draft');
261 if (!draftSection || !draftSection.results.length) { return; }
262
263 const closedChanges = draftSection.results
Paladox none7dca1282019-07-09 22:45:44 +0000264 .filter(change => !this.changeIsOpen(change));
Kasper Nilsson0dac13a2018-09-20 15:36:08 -0700265 if (!closedChanges.length) { return; }
266
267 this._showDraftsBanner = true;
268 },
269
270 _computeBannerClass(show) {
271 return show ? '' : 'hide';
272 },
273
274 _handleOpenDeleteDialog() {
275 this.$.confirmDeleteOverlay.open();
276 },
277
278 _handleConfirmDelete() {
279 this.$.confirmDeleteDialog.disabled = true;
280 return this.$.restAPI.deleteDraftComments('-is:open').then(() => {
281 this._closeConfirmDeleteOverlay();
282 this._reload();
283 });
284 },
285
286 _closeConfirmDeleteOverlay() {
287 this.$.confirmDeleteOverlay.close();
288 },
Kasper Nilsson4fa21ad2018-09-26 10:25:27 -0700289
290 _computeDraftsLink() {
291 return Gerrit.Nav.getUrlForSearchQuery('has:draft -is:open');
292 },
Logan Hanks1d3dc2a2018-09-19 13:18:59 -0700293
Kasper Nilsson57c1a282018-10-04 13:38:36 -0700294 _createChangeTap(e) {
Logan Hanks1d3dc2a2018-09-19 13:18:59 -0700295 this.$.destinationDialog.open();
296 },
297
298 _handleDestinationConfirm(e) {
299 this.$.commandsDialog.branch = e.detail.branch;
300 this.$.commandsDialog.open();
301 },
Andrew Bonventre78792e82016-03-04 17:48:22 -0500302 });
303})();