Project import generated by Copybara.
GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/static/js/tracker/tracker-update-issues-hotlists.js b/static/js/tracker/tracker-update-issues-hotlists.js
new file mode 100644
index 0000000..04a85bf
--- /dev/null
+++ b/static/js/tracker/tracker-update-issues-hotlists.js
@@ -0,0 +1,320 @@
+/* Copyright 2018 The Chromium Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://developers.google.com/open-source/licenses/bsd
+ */
+
+/**
+ * This file contains JS functions that support a dialog for adding and removing
+ * issues from hotlists in Monorail.
+ */
+
+(function() {
+ window.__hotlists_dialog = window.__hotlists_dialog || {};
+
+ // An optional IssueRef.
+ // If set, we will not check for selected issues, and only add/remove issueRef
+ // instead.
+ window.__hotlists_dialog.issueRef = null;
+ // A function to be called with the modified hotlists. If issueRef is set, the
+ // hotlists for which the user is owner and the issue is part of will be
+ // passed as well.
+ window.__hotlists_dialog.onResponse = () => {};
+ // A function to be called if there was an error updating the hotlists.
+ window.__hotlists_dialog.onFailure = () => {};
+
+ /**
+ * A function to show the hotlist dialog.
+ * It is the only function exported by this module.
+ */
+ function ShowUpdateHotlistDialog() {
+ _FetchHotlists().then(_BuildDialog);
+ }
+
+ async function _CreateNewHotlistWithIssues() {
+ let selectedIssueRefs;
+ if (window.__hotlists_dialog.issueRef) {
+ selectedIssueRefs = [window.__hotlists_dialog.issueRef];
+ } else {
+ selectedIssueRefs = _GetSelectedIssueRefs();
+ }
+
+ const name = await _CheckNewHotlistName();
+ if (!name) {
+ return;
+ }
+
+ const message = {
+ name: name,
+ summary: 'Hotlist of bulk added issues',
+ issueRefs: selectedIssueRefs,
+ };
+ try {
+ await window.prpcClient.call(
+ 'monorail.Features', 'CreateHotlist', message);
+ } catch (error) {
+ window.__hotlists_dialog.onFailure(error);
+ return;
+ }
+
+ const newHotlist = [name, window.CS_env.loggedInUserEmail];
+ const newIssueHotlists = [];
+ window.__hotlists_dialog._issueHotlists.forEach(
+ hotlist => newIssueHotlists.push(hotlist.split('_')));
+ newIssueHotlists.push(newHotlist);
+ window.__hotlists_dialog.onResponse([newHotlist], newIssueHotlists);
+ }
+
+ async function _UpdateIssuesInHotlists() {
+ const hotlistRefsAdd = _GetSelectedHotlists(
+ window.__hotlists_dialog._userHotlists);
+ const hotlistRefsRemove = _GetSelectedHotlists(
+ window.__hotlists_dialog._issueHotlists);
+ if (hotlistRefsAdd.length === 0 && hotlistRefsRemove.length === 0) {
+ alert('Please select/un-select some hotlists');
+ return;
+ }
+
+ let selectedIssueRefs;
+ if (window.__hotlists_dialog.issueRef) {
+ selectedIssueRefs = [window.__hotlists_dialog.issueRef];
+ } else {
+ selectedIssueRefs = _GetSelectedIssueRefs();
+ }
+
+ if (hotlistRefsAdd.length > 0) {
+ const message = {
+ hotlistRefs: hotlistRefsAdd,
+ issueRefs: selectedIssueRefs,
+ };
+ try {
+ await window.prpcClient.call(
+ 'monorail.Features', 'AddIssuesToHotlists', message);
+ } catch (error) {
+ window.__hotlists_dialog.onFailure(error);
+ return;
+ }
+ hotlistRefsAdd.forEach(hotlist => {
+ window.__hotlists_dialog._issueHotlists.add(
+ hotlist.name + '_' + hotlist.owner.user_id);
+ });
+ }
+
+ if (hotlistRefsRemove.length > 0) {
+ const message = {
+ hotlistRefs: hotlistRefsRemove,
+ issueRefs: selectedIssueRefs,
+ };
+ try {
+ await window.prpcClient.call(
+ 'monorail.Features', 'RemoveIssuesFromHotlists', message);
+ } catch (error) {
+ window.__hotlists_dialog.onFailure(error);
+ return;
+ }
+ hotlistRefsRemove.forEach(hotlist => {
+ window.__hotlists_dialog._issueHotlists.delete(
+ hotlist.name + '_' + hotlist.owner.user_id);
+ });
+ }
+
+ const modifiedHotlists = hotlistRefsAdd.concat(hotlistRefsRemove).map(
+ hotlist => [hotlist.name, hotlist.owner.user_id]);
+ const newIssueHotlists = [];
+ window.__hotlists_dialog._issueHotlists.forEach(
+ hotlist => newIssueHotlists.push(hotlist.split('_')));
+
+ window.__hotlists_dialog.onResponse(modifiedHotlists, newIssueHotlists);
+ }
+
+ async function _FetchHotlists() {
+ const userHotlistsMessage = {
+ user: {
+ display_name: window.CS_env.loggedInUserEmail,
+ }
+ };
+ const userHotlistsResponse = await window.prpcClient.call(
+ 'monorail.Features', 'ListHotlistsByUser', userHotlistsMessage);
+
+ // Here we have the list of all hotlists owned by the user. We filter out
+ // the hotlists that already contain issueRef in the next paragraph of code.
+ window.__hotlists_dialog._userHotlists = new Set();
+ (userHotlistsResponse.hotlists || []).forEach(hotlist => {
+ window.__hotlists_dialog._userHotlists.add(
+ hotlist.name + '_' + hotlist.ownerRef.userId);
+ });
+
+ // Here we filter out the hotlists that are owned by the user, and that
+ // contain issueRef from _userHotlists and save them into _issueHotlists.
+ window.__hotlists_dialog._issueHotlists = new Set();
+ if (window.__hotlists_dialog.issueRef) {
+ const issueHotlistsMessage = {
+ issue: window.__hotlists_dialog.issueRef,
+ };
+ const issueHotlistsResponse = await window.prpcClient.call(
+ 'monorail.Features', 'ListHotlistsByIssue', issueHotlistsMessage);
+ (issueHotlistsResponse.hotlists || []).forEach(hotlist => {
+ const hotlistRef = hotlist.name + '_' + hotlist.ownerRef.userId;
+ if (window.__hotlists_dialog._userHotlists.has(hotlistRef)) {
+ window.__hotlists_dialog._userHotlists.delete(hotlistRef);
+ window.__hotlists_dialog._issueHotlists.add(hotlistRef);
+ }
+ });
+ }
+ }
+
+ function _BuildDialog() {
+ const table = $('js-hotlists-table');
+
+ while (table.firstChild) {
+ table.removeChild(table.firstChild);
+ }
+
+ if (window.__hotlists_dialog._issueHotlists.size > 0) {
+ _UpdateRows(
+ table, 'Remove issues from:',
+ window.__hotlists_dialog._issueHotlists);
+ }
+ _UpdateRows(table, 'Add issues to:',
+ window.__hotlists_dialog._userHotlists);
+ _BuildCreateNewHotlist(table);
+
+ $('update-issues-hotlists').style.display = 'block';
+ $('save-issues-hotlists').addEventListener(
+ 'click', _UpdateIssuesInHotlists);
+ $('cancel-update-hotlists').addEventListener('click', function() {
+ $('update-issues-hotlists').style.display = 'none';
+ });
+
+ }
+
+ function _BuildCreateNewHotlist(table) {
+ const inputTr = document.createElement('tr');
+ inputTr.classList.add('hotlist_rows');
+
+ const inputCell = document.createElement('td');
+ const input = document.createElement('input');
+ input.setAttribute('id', 'text_new_hotlist_name');
+ input.setAttribute('placeholder', 'New hotlist name');
+ // Hotlist changes are automatic and should be ignored by
+ // TKR_currentFormValues() and TKR_isDirty()
+ input.setAttribute('ignore-dirty', true);
+ input.addEventListener('input', _CheckNewHotlistName);
+ inputCell.appendChild(input);
+ inputTr.appendChild(inputCell);
+
+ const buttonCell = document.createElement('td');
+ const button = document.createElement('button');
+ button.setAttribute('id', 'create-new-hotlist');
+ button.addEventListener('click', _CreateNewHotlistWithIssues);
+ button.textContent = 'Create New Hotlist';
+ button.disabled = true;
+ buttonCell.appendChild(button);
+ inputTr.appendChild(buttonCell);
+
+ table.appendChild(inputTr);
+
+ const feedbackTr = document.createElement('tr');
+ feedbackTr.classList.add('hotlist_rows');
+
+ const feedbackCell = document.createElement('td');
+ feedbackCell.setAttribute('colspan', '2');
+ const feedback = document.createElement('span');
+ feedback.classList.add('fielderror');
+ feedback.setAttribute('id', 'hotlistnamefeedback');
+ feedbackCell.appendChild(feedback);
+ feedbackTr.appendChild(feedbackCell);
+
+ table.appendChild(feedbackTr);
+ }
+
+ function _UpdateRows(table, title, hotlists) {
+ const tr = document.createElement('tr');
+ tr.classList.add('hotlist_rows');
+ const addCell = document.createElement('td');
+ const add = document.createElement('b');
+ add.textContent = title;
+ addCell.appendChild(add);
+ tr.appendChild(addCell);
+ table.appendChild(tr);
+
+ hotlists.forEach(hotlist => {
+ const hotlistParts = hotlist.split('_');
+ const name = hotlistParts[0];
+
+ const tr = document.createElement('tr');
+ tr.classList.add('hotlist_rows');
+
+ const cbCell = document.createElement('td');
+ const cb = document.createElement('input');
+ cb.classList.add('checkRangeSelect');
+ cb.setAttribute('id', 'cb_hotlist_' + hotlist);
+ cb.setAttribute('type', 'checkbox');
+ // Hotlist changes are automatic and should be ignored by
+ // TKR_currentFormValues() and TKR_isDirty()
+ cb.setAttribute('ignore-dirty', true);
+ cbCell.appendChild(cb);
+
+ const nameCell = document.createElement('td');
+ const label = document.createElement('label');
+ label.htmlFor = cb.id;
+ label.textContent = name;
+ nameCell.appendChild(label);
+
+ tr.appendChild(cbCell);
+ tr.appendChild(nameCell);
+ table.appendChild(tr);
+ });
+ }
+
+ async function _CheckNewHotlistName() {
+ const name = $('text_new_hotlist_name').value;
+ const checkNameResponse = await window.prpcClient.call(
+ 'monorail.Features', 'CheckHotlistName', {name});
+
+ if (checkNameResponse.error) {
+ $('hotlistnamefeedback').textContent = checkNameResponse.error;
+ $('create-new-hotlist').disabled = true;
+ return null;
+ }
+
+ $('hotlistnamefeedback').textContent = '';
+ $('create-new-hotlist').disabled = false;
+ return name;
+ }
+
+ /**
+ * Call GetSelectedIssuesRefs from tracker-editing.js and convert to an Array
+ * of IssueRef PBs.
+ */
+ function _GetSelectedIssueRefs() {
+ return GetSelectedIssuesRefs().map(issueRef => ({
+ project_name: issueRef['project_name'],
+ local_id: issueRef['id'],
+ }));
+ }
+
+ /**
+ * Get HotlistRef PBs for the hotlists that the user wants to add/remove the
+ * selected issues to.
+ */
+ function _GetSelectedHotlists(hotlists) {
+ const selectedHotlistRefs = [];
+ hotlists.forEach(hotlist => {
+ const checkbox = $('cb_hotlist_' + hotlist);
+ const hotlistParts = hotlist.split('_');
+ if (checkbox && checkbox.checked) {
+ selectedHotlistRefs.push({
+ name: hotlistParts[0],
+ owner: {
+ user_id: hotlistParts[1],
+ }
+ });
+ }
+ });
+ return selectedHotlistRefs;
+ }
+
+ Object.assign(window.__hotlists_dialog, {ShowUpdateHotlistDialog});
+})();