Implement workflow execution UI and logic
This CL adds a provisional workflow execution UI (which will need to be
thoroughly improved in the future), and most importantly the logic for
running workflows and actions inside workflows.
Bug: twpowertools:74
Change-Id: I94944a623a2411bef9d2b5244fea707e69a49790
diff --git a/src/contentScripts/communityConsole/workflows/components/TwptWorkflowDialog.js b/src/contentScripts/communityConsole/workflows/components/TwptWorkflowDialog.js
new file mode 100644
index 0000000..9b9525f
--- /dev/null
+++ b/src/contentScripts/communityConsole/workflows/components/TwptWorkflowDialog.js
@@ -0,0 +1,76 @@
+import '@material/mwc-dialog/mwc-dialog.js';
+import '@material/web/button/text-button.js';
+
+import './TwptWorkflowProgress.js';
+
+import {css, html, LitElement} from 'lit';
+import {createRef, ref} from 'lit/directives/ref.js';
+
+import WorkflowRunner from '../runner.js';
+
+export default class TwptWorkflowDialog extends LitElement {
+ static properties = {
+ open: {type: Boolean},
+ workflow: {type: Object},
+ _runner: {type: Object, state: true},
+ };
+
+ static styles = css`
+ :host {
+ --mdc-dialog-content-ink-color: var(--mdc-theme-on-surface, #000);
+ --mdc-dialog-z-index: 200;
+ }
+
+ .workflow-name {
+ font-weight: 500;
+ }
+ `;
+
+ progressRef = createRef();
+
+ constructor() {
+ super();
+ this.open = false;
+ }
+
+ render() {
+ return html`
+ <mwc-dialog
+ ?open=${this.open}
+ @opening=${this._openingDialog}
+ @closing=${this._closingDialog}
+ heading=${'Running ' + this.workflow?.getName?.() + '...'}>
+ <twpt-workflow-progress ${ref(this.progressRef)}
+ .workflow=${this.workflow}
+ currentThread=${this._runner?.currentThreadIndex}
+ numThreads=${this._runner?.numThreads}
+ currentAction=${this._runner?.currentActionIndex}
+ status=${this._runner?.status}>
+ </twpt-workflow-progress>
+
+ <md-text-button
+ ?disabled=${this._runner?.status !== 'finished'}
+ slot="primaryAction"
+ dialogAction="cancel"
+ label="Close">
+ </md-text-button>
+ </mwc-dialog>
+ `;
+ }
+
+ start() {
+ this._runner =
+ new WorkflowRunner(this.workflow, () => this.requestUpdate());
+ this._runner.start();
+ this.open = true;
+ }
+
+ _openingDialog() {
+ this.open = true;
+ }
+
+ _closingDialog() {
+ this.open = false;
+ }
+}
+window.customElements.define('twpt-workflow-dialog', TwptWorkflowDialog);
diff --git a/src/contentScripts/communityConsole/workflows/components/TwptWorkflowProgress.js b/src/contentScripts/communityConsole/workflows/components/TwptWorkflowProgress.js
new file mode 100644
index 0000000..52245e0
--- /dev/null
+++ b/src/contentScripts/communityConsole/workflows/components/TwptWorkflowProgress.js
@@ -0,0 +1,70 @@
+import '@material/mwc-dialog/mwc-dialog.js';
+import '@material/web/button/filled-button.js';
+import '@material/web/button/text-button.js';
+
+import '../../../../workflows/manager/components/ActionEditor.js';
+
+import {css, html, LitElement} from 'lit';
+import {map} from 'lit/directives/map.js';
+
+export default class TwptWorkflowProgress extends LitElement {
+ static properties = {
+ workflow: {type: Object},
+ currentThread: {type: Number},
+ numThreads: {type: Number},
+ currentAction: {type: Number},
+ status: {type: String},
+ };
+
+ static styles = css`
+ .progressbar-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+ `;
+
+ renderThreadProgress() {
+ // @TODO: Improve this UI when the actions section is complete
+ return html`
+ <div class="progressbar-container">
+ <progress value=${this.currentThread + 1} max=${
+ this.numThreads}></progress>
+ <span>Thread ${this.currentThread + 1}/${this.numThreads}</span>
+ </div>
+ <p style="color: gray;">(Debug information) Status: ${this.status}</p>
+ `;
+ }
+
+ renderActions() {
+ const actions = this.workflow?.getActionsList?.() ?? [];
+ return map(actions, (action, i) => {
+ let status;
+ if (i > this.currentAction)
+ status = 'idle';
+ else if (i == this.currentAction && this.status == 'running')
+ status = 'running';
+ else if (i == this.currentAction && this.status == 'error')
+ status = 'error';
+ else
+ status = 'done';
+
+ return html`
+ <wf-action-editor
+ .action=${action}
+ readOnly
+ step=${i + 1}
+ status=${status}>
+ </wf-action-editor>
+ `;
+ });
+ }
+
+ render() {
+ return [
+ this.renderThreadProgress(),
+ this.renderActions(),
+ ];
+ }
+}
+window.customElements.define('twpt-workflow-progress', TwptWorkflowProgress);
diff --git a/src/contentScripts/communityConsole/workflows/components/index.js b/src/contentScripts/communityConsole/workflows/components/index.js
index 3041e41..1822edc 100644
--- a/src/contentScripts/communityConsole/workflows/components/index.js
+++ b/src/contentScripts/communityConsole/workflows/components/index.js
@@ -1,5 +1,6 @@
-import './TwptWorkflowsMenu.js';
import './TwptConfirmDialog.js';
+import './TwptWorkflowDialog.js';
+import './TwptWorkflowsMenu.js';
import {css, html, LitElement} from 'lit';
import {createRef, ref} from 'lit/directives/ref.js';
@@ -52,14 +53,13 @@
}
_startWorkflow() {
- // @TODO
- console.log(`Start workflow ${this._selectedWorkflowUuid}!`);
+ this.workflowDialogRef.value.workflow = this._selectedWorkflow.cloneMessage();
+ this.workflowDialogRef.value.start();
}
get _selectedWorkflow() {
for (const w of this._workflows) {
- if (w.uuid == this._selectedWorkflowUuid)
- return w.proto;
+ if (w.uuid == this._selectedWorkflowUuid) return w.proto;
}
return null;