Workflows manager: add user-friendly CR selector
This CL lets users select CRs for the "Reply with CR" action in a
user-friendly manner.
A "Select CR" button next to the CR field has been added, which opens a
popup with an adapted version of the Community Console CR list with
buttons next to each CR which lets the user select one of them.
Fixed: twpowertools:148
Change-Id: I9799d671e7440b66435b30c540adc3f050c9f4e2
diff --git a/src/contentScripts/communityConsole/workflows/components/TwptCRImportButton.js b/src/contentScripts/communityConsole/workflows/components/TwptCRImportButton.js
new file mode 100644
index 0000000..935926f
--- /dev/null
+++ b/src/contentScripts/communityConsole/workflows/components/TwptCRImportButton.js
@@ -0,0 +1,40 @@
+import '@material/web/button/outlined-button.js';
+
+import {html, LitElement} from 'lit';
+
+import {SHARED_MD3_STYLES} from '../../../../common/styles/md3.js';
+
+export default class TwptCRImportButton extends LitElement {
+ static properties = {
+ cannedResponseId: {type: String},
+ selected: {type: Boolean},
+ };
+
+ static styles = [
+ SHARED_MD3_STYLES,
+ ];
+
+ render() {
+ const icon = this.selected ? 'done' : 'post_add';
+ const label = this.selected ? 'Selected' : 'Select';
+
+ return html`
+ <md-outlined-button
+ icon=${icon}
+ label=${label}
+ ?disabled=${this.selected}
+ @click=${this._importCR}>
+ </md-outlined-button>
+ `;
+ }
+
+ _importCR() {
+ window.opener?.postMessage?.(
+ {
+ action: 'importCannedResponse',
+ cannedResponseId: this.cannedResponseId,
+ },
+ '*');
+ }
+}
+window.customElements.define('twpt-cr-import-button', TwptCRImportButton);
diff --git a/src/contentScripts/communityConsole/workflows/components/index.js b/src/contentScripts/communityConsole/workflows/components/index.js
index 05cf839..f7651f0 100644
--- a/src/contentScripts/communityConsole/workflows/components/index.js
+++ b/src/contentScripts/communityConsole/workflows/components/index.js
@@ -1,4 +1,5 @@
import './TwptConfirmDialog.js';
+import './TwptCRImportButton.js';
import './TwptWorkflowDialog.js';
import './TwptWorkflowsMenu.js';
@@ -53,7 +54,8 @@
}
_startWorkflow() {
- this.workflowDialogRef.value.workflow = this._selectedWorkflow.cloneMessage();
+ this.workflowDialogRef.value.workflow =
+ this._selectedWorkflow.cloneMessage();
this.workflowDialogRef.value.start();
}
diff --git a/src/contentScripts/communityConsole/workflows/import.js b/src/contentScripts/communityConsole/workflows/import.js
new file mode 100644
index 0000000..8172b62
--- /dev/null
+++ b/src/contentScripts/communityConsole/workflows/import.js
@@ -0,0 +1,108 @@
+import {waitFor} from 'poll-until-promise';
+
+import {recursiveParentElement} from '../../../common/commonUtils.js';
+import {injectStylesheet} from '../../../common/contentScriptsUtils.js';
+import {isOptionEnabled} from '../../../common/optionsUtils.js';
+
+const kListCannedResponsesResponse = 'TWPT_ListCannedResponsesResponse';
+
+const kImportParam = 'TWPTImportToWorkflow';
+const kSelectedIdParam = 'TWPTSelectedId';
+
+// Class which is used to inject a "select" button in the CRs list when loading
+// the canned response list for this purpose from the workflows manager.
+export default class WorkflowsImport {
+ constructor() {
+ // Only set this class up if the Community Console was opened with the
+ // purpose of importing CRs to the workflow manager.
+ const searchParams = new URLSearchParams(document.location.search);
+ if (!searchParams.has(kImportParam)) return;
+
+ this.selectedId = searchParams.get(kSelectedIdParam);
+
+ this.lastCRsList = {
+ body: {},
+ id: -1,
+ duplicateNames: new Set(),
+ };
+
+ this.setUpHandler();
+ this.addCustomStyles();
+ }
+
+ setUpHandler() {
+ window.addEventListener(kListCannedResponsesResponse, e => {
+ if (e.detail.id < this.lastCRsList.id) return;
+
+ // Look if there are duplicate names
+ const crs = e.detail.body?.['1'] ?? [];
+ const names = crs.map(cr => cr?.['7']).slice().sort();
+ let duplicateNames = new Set();
+ for (let i = 1; i < names.length; i++)
+ if (names[i - 1] == names[i]) duplicateNames.add(names[i]);
+
+ this.lastCRsList = {
+ body: e.detail.body,
+ id: e.detail.id,
+ duplicateNames,
+ };
+ });
+ }
+
+ addCustomStyles() {
+ injectStylesheet(chrome.runtime.getURL('css/workflow_import.css'));
+ }
+
+ addButton(tags) {
+ const cr = recursiveParentElement(tags, 'EC-CANNED-RESPONSE-ROW');
+ if (!cr) return;
+
+ const name = cr.querySelector('.text .name').textContent;
+ if (!name) return;
+
+ const toolbar = cr.querySelector('.action .toolbar');
+ if (!toolbar) return console.error(`Can't find toolbar.`);
+
+ // If it has already been injected, exit.
+ if (toolbar.querySelector('twpt-cr-import-button')) return;
+
+ waitFor(() => {
+ if (this.lastCRsList.id != -1) return Promise.resolve(this.lastCRsList);
+ return Promise.reject(new Error('Didn\'t receive canned responses list'));
+ }, {
+ interval: 500,
+ timeout: 15 * 1000,
+ }).then(crs => {
+ // If another CR has the same name, there's no easy way to distinguish
+ // them, so don't inject the button.
+ if (crs.duplicateNames.has(name)) {
+ console.info(
+ 'CR "' + name +
+ '" is duplicate, so skipping the injection of the button.');
+ return;
+ }
+
+ for (const cr of (crs.body?.[1] ?? [])) {
+ if (cr[7] == name) {
+ const id = cr?.[1]?.[1];
+ if (!id) {
+ console.error('Can\'t find ID for canned response', cr);
+ break;
+ }
+
+ const button = document.createElement('twpt-cr-import-button');
+ button.setAttribute('cannedResponseId', id);
+ if (this.selectedId == id) button.setAttribute('selected', '');
+ toolbar.prepend(button);
+ break;
+ }
+ }
+ });
+ }
+
+ addButtonIfEnabled(tags) {
+ isOptionEnabled('workflows').then(isEnabled => {
+ if (isEnabled) this.addButton(tags);
+ });
+ }
+}