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