blob: d96e566e74f376a66286bb35fa8544b1fbbaaa49 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// TODO(juliacordero): Handle pRPC errors with a FE page
6
7import {LitElement, html, css} from 'lit-element';
8import {store, connectStore} from 'reducers/base.js';
9import {shouldWaitForDefaultQuery} from 'shared/helpers.js';
10import * as issueV0 from 'reducers/issueV0.js';
11import * as projectV0 from 'reducers/projectV0.js';
12import * as sitewide from 'reducers/sitewide.js';
13import 'elements/framework/links/mr-issue-link/mr-issue-link.js';
14import './mr-grid-controls.js';
15import './mr-grid.js';
16
17/**
18 * <mr-grid-page>
19 *
20 * Grid page view containing mr-grid and mr-grid-controls.
21 * @extends {LitElement}
22 */
23export class MrGridPage extends connectStore(LitElement) {
24 /** @override */
25 render() {
26 const displayedProgress = this.progress || 0.02;
27 const doneLoading = this.progress === 1;
28 const noMatches = this.totalIssues === 0 && doneLoading;
29 return html`
30 <div id="grid-area">
31 <mr-grid-controls
32 .projectName=${this.projectName}
33 .queryParams=${this._queryParams}
34 .issueCount=${this.issues.length}>
35 </mr-grid-controls>
36 ${noMatches ? html`
37 <div class="empty-search">
38 Your search did not generate any results.
39 </div>` : html`
40 <progress
41 title="${Math.round(displayedProgress * 100)}%"
42 value=${displayedProgress}
43 ?hidden=${doneLoading}
44 ></progress>`}
45 <br>
46 <mr-grid
47 .issues=${this.issues}
48 .xField=${this._queryParams.x}
49 .yField=${this._queryParams.y}
50 .cellMode=${this._queryParams.cells ? this._queryParams.cells : 'tiles'}
51 .queryParams=${this._queryParams}
52 .projectName=${this.projectName}
53 ></mr-grid>
54 </div>
55 `;
56 }
57
58 /** @override */
59 static get properties() {
60 return {
61 projectName: {type: String},
62 _queryParams: {type: Object},
63 userDisplayName: {type: String},
64 issues: {type: Array},
65 fields: {type: Array},
66 progress: {type: Number},
67 totalIssues: {type: Number},
68 _presentationConfigLoaded: {type: Boolean},
69 /**
70 * The current search string the user is querying for.
71 * Project default if not specified.
72 */
73 _currentQuery: {type: String},
74 /**
75 * The current canned query the user is searching for.
76 * Project default if not specified.
77 */
78 _currentCan: {type: String},
79 };
80 };
81
82 /** @override */
83 constructor() {
84 super();
85 this.issues = [];
86 this.progress = 0;
87 /** @type {string} */
88 this.projectName;
89 this._queryParams = {};
90 this._presentationConfigLoaded = false;
91 };
92
93 /** @override */
94 updated(changedProperties) {
95 if (changedProperties.has('userDisplayName')) {
96 store.dispatch(issueV0.fetchStarredIssues());
97 }
98 // TODO(zosha): Abort sets of calls to ListIssues when
99 // queryParams.q is changed.
100 if (this._shouldFetchMatchingIssues(changedProperties)) {
101 this._fetchMatchingIssues();
102 }
103 }
104
105 /**
106 * Computes whether to fetch matching issues based on changedProperties
107 * @param {Map} changedProperties
108 * @return {boolean}
109 */
110 _shouldFetchMatchingIssues(changedProperties) {
111 const wait = shouldWaitForDefaultQuery(this._queryParams);
112 if (wait && !this._presentationConfigLoaded) {
113 return false;
114 } else if (wait && this._presentationConfigLoaded &&
115 changedProperties.has('_presentationConfigLoaded')) {
116 return true;
117 } else if (changedProperties.has('projectName') ||
118 changedProperties.has('_currentQuery') ||
119 changedProperties.has('_currentCan')) {
120 return true;
121 }
122 return false;
123 }
124
125 /** @private */
126 _fetchMatchingIssues() {
127 store.dispatch(issueV0.fetchIssueList(this.projectName, {
128 ...this._queryParams,
129 q: this._currentQuery,
130 can: this._currentCan,
131 maxItems: 500, // 500 items * 12 calls = max of 6,000 issues.
132 maxCalls: 12,
133 }));
134 }
135
136 /** @override */
137 stateChanged(state) {
138 this.projectName = projectV0.viewedProjectName(state);
139 this.issues = (issueV0.issueList(state) || []);
140 this.progress = (issueV0.issueListProgress(state) || 0);
141 this.totalIssues = (issueV0.totalIssues(state) || 0);
142 this._queryParams = sitewide.queryParams(state);
143 this._currentQuery = sitewide.currentQuery(state);
144 this._currentCan = sitewide.currentCan(state);
145 this._presentationConfigLoaded =
146 projectV0.viewedPresentationConfigLoaded(state);
147 }
148
149 /** @override */
150 static get styles() {
151 return css `
152 :host {
153 display: block;
154 box-sizing: border-box;
155 width: 100%;
156 padding: 0.5em 8px;
157 }
158 progress {
159 background-color: var(--chops-white);
160 border: 1px solid var(--chops-gray-500);
161 width: 40%;
162 margin-left: 1%;
163 margin-top: 0.5em;
164 visibility: visible;
165 }
166 ::-webkit-progress-bar {
167 background-color: var(--chops-white);
168 }
169 progress::-webkit-progress-value {
170 transition: width 1s;
171 background-color: var(--chops-blue-700);
172 }
173 .empty-search {
174 text-align: center;
175 padding-top: 2em;
176 }
177 `;
178 }
179};
180customElements.define('mr-grid-page', MrGridPage);