blob: 164d2265ec92eb19eef3d4db94b4e25537f721ef [file] [log] [blame]
import {recursiveParentElement} from '../../../common/commonUtils.js';
import * as pb from '../../../workflows/proto/main_pb.js';
import AttributeRunner from './actionRunners/attribute.js';
import ReadStateRunner from './actionRunners/readState.js';
import CRRunner from './actionRunners/replyWithCR.js';
import Thread from './models/thread.js';
export default class WorkflowRunner {
constructor(workflow, updateCallback) {
this.workflow = workflow;
this._threads = [];
this._currentThreadIndex = 0;
this._currentActionIndex = 0;
// Can be 'waiting', 'running', 'error', 'finished'
this._status = 'waiting';
this._updateCallback = updateCallback;
// Initialize action runners:
this._AttributeRunner = new AttributeRunner();
this._CRRunner = new CRRunner();
this._ReadStateRunner = new ReadStateRunner();
}
start() {
this._getSelectedThreads();
this.status = 'running';
this._runNextAction();
}
_getSelectedThreads() {
let threads = [];
const checkboxes = document.querySelectorAll(
'.thread-group material-checkbox[aria-checked="true"]');
for (const checkbox of checkboxes) {
const url = recursiveParentElement(checkbox, 'EC-THREAD-SUMMARY')
.querySelector('a.header-content')
.href;
const thread = Thread.fromUrl(url);
if (!thread) {
console.error('Couldn\'t parse URL ' + url);
continue;
}
threads.push(thread);
}
this.threads = threads;
}
_showError(err) {
console.warn(
`An error ocurred while executing action ${this.currentActionIndex}.`,
err);
this.status = 'error';
}
_runAction() {
switch (this._currentAction?.getActionCase?.()) {
case pb.workflows.Action.ActionCase.ATTRIBUTE_ACTION:
return this._AttributeRunner.execute(
this._currentAction?.getAttributeAction?.(), this._currentThread);
case pb.workflows.Action.ActionCase.REPLY_WITH_CR_ACTION:
return this._CRRunner.execute(
this._currentAction?.getReplyWithCrAction?.(), this._currentThread);
case pb.workflows.Action.ActionCase.MARK_AS_READ_ACTION:
return this._ReadStateRunner.execute(true, this._currentThread);
case pb.workflows.Action.ActionCase.MARK_AS_UNREAD_ACTION:
return this._ReadStateRunner.execute(false, this._currentThread);
default:
return Promise.reject(new Error('This action isn\'t supported yet.'));
}
}
_runNextAction() {
if (this.status !== 'running')
return console.error(
'Trying to run next action with status ' + this.status + '.');
this._runAction()
.then(() => {
if (this._nextActionIfAvailable())
this._runNextAction();
else
this._finish();
})
.catch(err => this._showError(err));
}
_nextActionIfAvailable() {
if (this.currentActionIndex === this._actions.length - 1) {
if (this.currentThreadIndex === this.numThreads - 1) return false;
this.currentThreadIndex++;
this.currentActionIndex = 0;
return true;
}
this.currentActionIndex++;
return true;
}
_finish() {
this.status = 'finished';
}
get numThreads() {
return this.threads.length ?? 0;
}
get _actions() {
return this.workflow?.getActionsList?.();
}
get _currentAction() {
return this._actions?.[this.currentActionIndex];
}
get _currentThread() {
return this._threads?.[this.currentThreadIndex];
}
// Setters/getters for properties, which will update the UI when changed.
get threads() {
return this._threads;
}
set threads(value) {
this._threads = value;
this._updateCallback();
}
get currentThreadIndex() {
return this._currentThreadIndex;
}
set currentThreadIndex(value) {
this._currentThreadIndex = value;
this._updateCallback();
}
get currentActionIndex() {
return this._currentActionIndex;
}
set currentActionIndex(value) {
this._currentActionIndex = value;
this._updateCallback();
}
get status() {
return this._status;
}
set status(value) {
this._status = value;
this._updateCallback();
}
}