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