Browse Source

feat: restart workflow option when an error occurs

Ahmad Kholid 3 years ago
parent
commit
5146b37203

+ 9 - 7
src/background/collection-engine/flow-handler.js

@@ -30,13 +30,15 @@ export function workflow(flow) {
       blocksHandler,
       states: this.states,
       logger: this.logger,
-      parentWorkflow: {
-        id: this.id,
-        isCollection: true,
-        name: this.collection.name,
-      },
-      data: {
-        globalData: globalData.trim() === '' ? null : globalData,
+      options: {
+        parentWorkflow: {
+          id: this.id,
+          isCollection: true,
+          name: this.collection.name,
+        },
+        data: {
+          globalData: globalData.trim() === '' ? null : globalData,
+        },
       },
     });
 

+ 2 - 2
src/background/index.js

@@ -64,7 +64,7 @@ const workflow = {
     }
 
     const engine = new WorkflowEngine(workflowData, {
-      ...options,
+      options,
       blocksHandler,
       logger: this.logger,
       states: this.states,
@@ -155,7 +155,7 @@ async function checkVisitWebTriggers(changeInfo, tab) {
   if (triggeredWorkflow) {
     const workflowData = await workflow.get(triggeredWorkflow.id);
 
-    if (workflowData) workflow.execute(workflowData);
+    if (workflowData) workflow.execute(workflowData, { tabId: tab.id });
   }
 }
 async function checkRecordingWorkflow({ status }, { url, id }) {

+ 8 - 6
src/background/workflow-engine/blocks-handler/handler-execute-workflow.js

@@ -52,9 +52,14 @@ async function executeWorkflow({ outputs, data }) {
       throw errorInstance;
     }
     const options = {
-      parentWorkflow: {
-        id: this.id,
-        name: this.workflow.name,
+      options: {
+        data: {
+          globalData: isWhitespace(data.globalData) ? null : data.globalData,
+        },
+        parentWorkflow: {
+          id: this.id,
+          name: this.workflow.name,
+        },
       },
       events: {
         onInit: (engine) => {
@@ -77,9 +82,6 @@ async function executeWorkflow({ outputs, data }) {
       states: this.states,
       logger: this.logger,
       blocksHandler: this.blocksHandler,
-      data: {
-        globalData: isWhitespace(data.globalData) ? null : data.globalData,
-      },
     };
 
     if (workflow.drawflow.includes(this.workflow.id)) {

+ 53 - 10
src/background/workflow-engine/engine.js

@@ -9,7 +9,7 @@ import executeContentScript from './execute-content-script';
 class WorkflowEngine {
   constructor(
     workflow,
-    { states, logger, blocksHandler, tabId, parentWorkflow, data }
+    { states, logger, blocksHandler, parentWorkflow, options }
   ) {
     this.id = nanoid();
     this.states = states;
@@ -23,6 +23,7 @@ class WorkflowEngine {
     this.repeatedTasks = {};
 
     this.windowId = null;
+    this.triggerBlock = null;
     this.currentBlock = null;
     this.childWorkflowId = null;
 
@@ -34,15 +35,20 @@ class WorkflowEngine {
     this.eventListeners = {};
     this.columns = { column: { index: 0, type: 'any' } };
 
-    const globalData = data?.globalData || workflow.globalData;
-    const variables = isObject(data?.variables) ? data.variables : {};
+    const globalData = options?.data?.globalData || workflow.globalData;
+    const variables = isObject(options?.data?.variables)
+      ? options?.data.variables
+      : {};
+
+    options.data = { globalData, variables };
+    this.options = options;
 
     this.activeTab = {
       url: '',
-      id: tabId,
       frameId: 0,
       frames: {},
       groupId: null,
+      id: options?.tabId,
     };
     this.referenceData = {
       variables,
@@ -59,7 +65,38 @@ class WorkflowEngine {
     };
   }
 
-  init(currentBlock) {
+  reset() {
+    this.loopList = {};
+    this.repeatedTasks = {};
+
+    this.windowId = null;
+    this.currentBlock = null;
+    this.childWorkflowId = null;
+
+    this.isDestroyed = false;
+    this.isUsingProxy = false;
+
+    this.history = [];
+    this.columns = { column: { index: 0, type: 'any' } };
+
+    this.activeTab = {
+      url: '',
+      frameId: 0,
+      frames: {},
+      groupId: null,
+      id: this.options?.tabId,
+    };
+    this.referenceData = {
+      table: [],
+      loopData: {},
+      workflow: {},
+      googleSheets: {},
+      variables: this.options.variables,
+      globalData: this.referenceData.globalData,
+    };
+  }
+
+  init() {
     if (this.workflow.isDisabled) return;
 
     if (!this.states) {
@@ -98,7 +135,7 @@ class WorkflowEngine {
     this.blocks = blocks;
     this.startedTimestamp = Date.now();
     this.workflow.table = columns;
-    this.currentBlock = currentBlock || triggerBlock;
+    this.currentBlock = triggerBlock;
 
     this.states.on('stop', this.onWorkflowStopped);
 
@@ -307,13 +344,19 @@ class WorkflowEngine {
         ...(error.data || {}),
       });
 
-      if (
-        this.workflow.settings.onError === 'keep-running' &&
-        error.nextBlockId
-      ) {
+      const { onError } = this.workflow.settings;
+
+      if (onError === 'keep-running' && error.nextBlockId) {
         setTimeout(() => {
           this.executeBlock(this.blocks[error.nextBlockId], error.data || '');
         }, blockDelay);
+      } else if (onError === 'restart-workflow' && !this.parentWorkflow) {
+        this.reset();
+
+        const triggerBlock = Object.values(this.blocks).find(
+          ({ name }) => name === 'trigger'
+        );
+        this.executeBlock(triggerBlock);
       } else {
         this.destroy('error', error.message);
       }

+ 11 - 19
src/components/newtab/workflow/WorkflowSettings.vue

@@ -4,23 +4,11 @@
       <p class="mb-1 capitalize">
         {{ t('workflow.settings.onError.title') }}
       </p>
-      <div class="space-x-4 flex w-full max-w-sm items-center">
-        <div
-          v-for="item in onError"
-          :key="item.id"
-          class="p-3 rounded-lg border transition-colors w-full hoverable"
-          @click="settings.onError = item.id"
-        >
-          <ui-radio
-            :model-value="settings.onError"
-            :value="item.id"
-            class="capitalize"
-            @change="settings.onError = $event"
-          >
-            {{ item.name }}
-          </ui-radio>
-        </div>
-      </div>
+      <ui-select v-model="settings.onError" class="w-full max-w-sm">
+        <option v-for="item in onError" :key="item.id" :value="item.id">
+          {{ t(`workflow.settings.onError.items.${item.name}`) }}
+        </option>
+      </ui-select>
     </div>
     <div>
       <p class="mb-1 capitalize">
@@ -67,11 +55,15 @@ const { t } = useI18n();
 const onError = [
   {
     id: 'keep-running',
-    name: t('workflow.settings.onError.items.keepRunning'),
+    name: 'keepRunning',
   },
   {
     id: 'stop-workflow',
-    name: t('workflow.settings.onError.items.stopWorkflow'),
+    name: 'stopWorkflow',
+  },
+  {
+    id: 'restart-workflow',
+    name: 'restartWorkflow',
   },
 ];
 

+ 2 - 1
src/locales/en/newtab.json

@@ -162,7 +162,8 @@
         "title": "On workflow error",
         "items": {
           "keepRunning": "Keep running",
-          "stopWorkflow": "Stop workflow"
+          "stopWorkflow": "Stop workflow",
+          "restartWorkflow": "Restart workflow"
         }
       },
       "timeout": {

+ 3 - 1
src/manifest.json

@@ -46,7 +46,9 @@
     }
   ],
   "optional_permissions": [
-    "clipboardRead"
+    "clipboardRead",
+    "webRequest",
+    "debugger"
   ],
   "permissions": [
     "tabs",