blob: 2e90b19c5d019b13347cd1d20d330764fa966acd [file] [log] [blame]
Adrià Vilanova Martínez54964a52022-10-26 23:53:29 +02001import {parseUrl, recursiveParentElement} from '../../../common/commonUtils.js';
2import * as pb from '../../../workflows/proto/main_pb.js';
3
4import CRRunner from './actionRunners/replyWithCR.js';
5
6export default class WorkflowRunner {
7 constructor(workflow, updateCallback) {
8 this.workflow = workflow;
9 this._threads = [];
10 this._currentThreadIndex = 0;
11 this._currentActionIndex = 0;
12 // Can be 'waiting', 'running', 'error', 'finished'
13 this._status = 'waiting';
14 this._updateCallback = updateCallback;
15
16 // Initialize action runners:
17 this._CRRunner = new CRRunner();
18 }
19
20 start() {
21 this._getSelectedThreads();
22 this.status = 'running';
23 this._runNextAction();
24 }
25
26 _getSelectedThreads() {
27 let threads = [];
28 const checkboxes = document.querySelectorAll(
29 '.thread-group material-checkbox[aria-checked="true"]');
30
31 for (const checkbox of checkboxes) {
32 const url = recursiveParentElement(checkbox, 'EC-THREAD-SUMMARY')
33 .querySelector('a.header-content')
34 .href;
35 const thread = parseUrl(url);
36 if (!thread) {
37 console.error('Couldn\'t parse URL ' + url);
38 continue;
39 }
40 threads.push(thread);
41 }
42
43 this.threads = threads;
44 }
45
46 _showError(err) {
47 console.warn(
48 `An error ocurred while executing action ${this.currentActionIndex}.`,
49 err);
50 this.status = 'error';
51 }
52
53 _runAction() {
54 switch (this._currentAction?.getActionCase?.()) {
55 case pb.workflows.Action.ActionCase.REPLY_WITH_CR_ACTION:
56 return this._CRRunner.execute(
57 this._currentAction?.getReplyWithCrAction?.(), this._currentThread);
58
59 default:
60 return Promise.reject(new Error('This action isn\'t supported yet.'));
61 }
62 }
63
64 _runNextAction() {
65 if (this.status !== 'running')
66 return console.error(
67 'Trying to run next action with status ' + this.status + '.');
68
69 this._runAction()
70 .then(() => {
71 if (this._nextActionIfAvailable())
72 this._runNextAction();
73 else
74 this._finish();
75 })
76 .catch(err => this._showError(err));
77 }
78
79 _nextActionIfAvailable() {
80 if (this.currentActionIndex === this._actions.length - 1) {
81 if (this.currentThreadIndex === this.numThreads - 1) return false;
82
83 this.currentThreadIndex++;
84 this.currentActionIndex = 0;
85 return true;
86 }
87
88 this.currentActionIndex++;
89 return true;
90 }
91
92 _finish() {
93 this.status = 'finished';
94 }
95
96 get numThreads() {
97 return this.threads.length ?? 0;
98 }
99
100 get _actions() {
101 return this.workflow?.getActionsList?.();
102 }
103
104 get _currentAction() {
105 return this._actions?.[this.currentActionIndex];
106 }
107
108 get _currentThread() {
109 return this._threads?.[this.currentThreadIndex];
110 }
111
112 // Setters/getters for properties, which will update the UI when changed.
113 get threads() {
114 return this._threads;
115 }
116
117 set threads(value) {
118 this._threads = value;
119 this._updateCallback();
120 }
121
122 get currentThreadIndex() {
123 return this._currentThreadIndex;
124 }
125
126 set currentThreadIndex(value) {
127 this._currentThreadIndex = value;
128 this._updateCallback();
129 }
130
131 get currentActionIndex() {
132 return this._currentActionIndex;
133 }
134
135 set currentActionIndex(value) {
136 this._currentActionIndex = value;
137 this._updateCallback();
138 }
139
140 get status() {
141 return this._status;
142 }
143
144 set status(value) {
145 this._status = value;
146 this._updateCallback();
147 }
148}