瀏覽代碼

feat: support JS expression in mustache tag

Ahmad Kholid 2 年之前
父節點
當前提交
70b4b78812
共有 83 個文件被更改,包括 775 次插入709 次删除
  1. 1 0
      package.json
  2. 1 1
      src/background/BackgroundUtils.js
  3. 1 1
      src/components/newtab/shared/SharedLogsTable.vue
  4. 1 1
      src/components/newtab/shared/SharedWorkflowState.vue
  5. 1 1
      src/components/newtab/workflow/WorkflowRunning.vue
  6. 1 1
      src/components/newtab/workflow/editor/EditorLocalActions.vue
  7. 1 1
      src/components/newtab/workflows/WorkflowsHosted.vue
  8. 1 1
      src/components/newtab/workflows/WorkflowsLocal.vue
  9. 1 1
      src/components/newtab/workflows/WorkflowsShared.vue
  10. 1 1
      src/components/newtab/workflows/WorkflowsUserTeam.vue
  11. 1 1
      src/components/popup/home/HomeTeamWorkflows.vue
  12. 1 1
      src/newtab/App.vue
  13. 1 1
      src/newtab/pages/logs/Running.vue
  14. 1 1
      src/newtab/pages/workflows/Host.vue
  15. 2 2
      src/newtab/pages/workflows/[id].vue
  16. 27 22
      src/newtab/workflowEngine/WorkflowEngine.js
  17. 0 0
      src/newtab/workflowEngine/WorkflowLogger.js
  18. 0 0
      src/newtab/workflowEngine/WorkflowState.js
  19. 6 6
      src/newtab/workflowEngine/WorkflowWorker.js
  20. 0 0
      src/newtab/workflowEngine/blocksHandler.js
  21. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerActiveTab.js
  22. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerBlockPackage.js
  23. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerBlocksGroup.js
  24. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerBrowserEvent.js
  25. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerClipboard.js
  26. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerCloseTab.js
  27. 7 9
      src/newtab/workflowEngine/blocksHandler/handlerConditions.js
  28. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerCookie.js
  29. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerCreateElement.js
  30. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerDataMapping.js
  31. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerDelay.js
  32. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerDeleteData.js
  33. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerElementExists.js
  34. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerExecuteWorkflow.js
  35. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerExportData.js
  36. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerForwardPage.js
  37. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerGoBack.js
  38. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerGoogleSheets.js
  39. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerHandleDialog.js
  40. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerHandleDownload.js
  41. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerHoverElement.js
  42. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerIncreaseVariable.js
  43. 3 3
      src/newtab/workflowEngine/blocksHandler/handlerInsertData.js
  44. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerInteractionBlock.js
  45. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerJavascriptCode.js
  46. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerLogData.js
  47. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerLoopBreakpoint.js
  48. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerLoopData.js
  49. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerLoopElements.js
  50. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerNewTab.js
  51. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerNewWindow.js
  52. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerNotification.js
  53. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerParameterPrompt.js
  54. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerProxy.js
  55. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerRegexVariable.js
  56. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerReloadTab.js
  57. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerRepeatTask.js
  58. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerSaveAssets.js
  59. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerSliceVariable.js
  60. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerSortData.js
  61. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerSwitchTab.js
  62. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerSwitchTo.js
  63. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerTabUrl.js
  64. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerTakeScreenshot.js
  65. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerTrigger.js
  66. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerWaitConnections.js
  67. 4 4
      src/newtab/workflowEngine/blocksHandler/handlerWebhook.js
  68. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerWhileLoop.js
  69. 0 0
      src/newtab/workflowEngine/blocksHandler/handlerWorkflowState.js
  70. 1 1
      src/newtab/workflowEngine/helper.js
  71. 0 0
      src/newtab/workflowEngine/index.js
  72. 0 0
      src/newtab/workflowEngine/injectContentScript.js
  73. 40 0
      src/newtab/workflowEngine/templating/index.js
  74. 3 128
      src/newtab/workflowEngine/templating/mustacheReplacer.js
  75. 15 0
      src/newtab/workflowEngine/templating/renderString.js
  76. 142 0
      src/newtab/workflowEngine/templating/templatingFunctions.js
  77. 15 144
      src/sandbox/index.js
  78. 19 0
      src/sandbox/utils/handleBlockExpression.js
  79. 43 0
      src/sandbox/utils/handleConditionCode.js
  80. 98 0
      src/sandbox/utils/handleJavascriptBlock.js
  81. 0 43
      src/utils/referenceData/index.js
  82. 4 4
      src/utils/testConditions.js
  83. 332 330
      yarn.lock

+ 1 - 0
package.json

@@ -36,6 +36,7 @@
     "@codemirror/language": "^6.2.1",
     "@codemirror/theme-one-dark": "^6.0.0",
     "@medv/finder": "^2.1.0",
+    "@n8n_io/riot-tmpl": "^1.0.1",
     "@tiptap/extension-character-count": "^2.0.0-beta.31",
     "@tiptap/extension-image": "^2.0.0-beta.30",
     "@tiptap/extension-link": "^2.0.0-beta.43",

+ 1 - 1
src/background/BackgroundUtils.js

@@ -1,5 +1,5 @@
 import browser from 'webextension-polyfill';
-import { waitTabLoaded } from '@/newtab/utils/workflowEngine/helper';
+import { waitTabLoaded } from '@/newtab/workflowEngine/helper';
 
 class BackgroundUtils {
   static async openDashboard(url, updateTab = true) {

+ 1 - 1
src/components/newtab/shared/SharedLogsTable.vue

@@ -114,7 +114,7 @@
 import { reactive } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { countDuration } from '@/utils/helper';
-import { workflowState } from '@/newtab/utils/workflowEngine';
+import { workflowState } from '@/newtab/workflowEngine';
 import dayjs from '@/lib/dayjs';
 
 defineProps({

+ 1 - 1
src/components/newtab/shared/SharedWorkflowState.vue

@@ -59,7 +59,7 @@
 import browser from 'webextension-polyfill';
 import { useI18n } from 'vue-i18n';
 import { getBlocks } from '@/utils/getSharedData';
-import { workflowState } from '@/newtab/utils/workflowEngine';
+import { workflowState } from '@/newtab/workflowEngine';
 import dayjs from '@/lib/dayjs';
 
 const props = defineProps({

+ 1 - 1
src/components/newtab/workflow/WorkflowRunning.vue

@@ -43,7 +43,7 @@
 import browser from 'webextension-polyfill';
 import { useI18n } from 'vue-i18n';
 import { getBlocks } from '@/utils/getSharedData';
-import { workflowState } from '@/newtab/utils/workflowEngine';
+import { workflowState } from '@/newtab/workflowEngine';
 import dayjs from '@/lib/dayjs';
 
 defineProps({

+ 1 - 1
src/components/newtab/workflow/editor/EditorLocalActions.vue

@@ -327,7 +327,7 @@ import { tagColors } from '@/utils/shared';
 import { parseJSON, findTriggerBlock } from '@/utils/helper';
 import { exportWorkflow, convertWorkflow } from '@/utils/workflowData';
 import { registerWorkflowTrigger } from '@/utils/workflowTrigger';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import getTriggerText from '@/utils/triggerText';
 import convertWorkflowData from '@/utils/convertWorkflowData';
 import WorkflowShareTeam from '@/components/newtab/workflow/WorkflowShareTeam.vue';

+ 1 - 1
src/components/newtab/workflows/WorkflowsHosted.vue

@@ -15,7 +15,7 @@ import { useI18n } from 'vue-i18n';
 import { useDialog } from '@/composable/dialog';
 import { arraySorter } from '@/utils/helper';
 import { useHostedWorkflowStore } from '@/stores/hostedWorkflow';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import SharedCard from '@/components/newtab/shared/SharedCard.vue';
 
 const props = defineProps({

+ 1 - 1
src/components/newtab/workflows/WorkflowsLocal.vue

@@ -112,7 +112,7 @@ import { useDialog } from '@/composable/dialog';
 import { useWorkflowStore } from '@/stores/workflow';
 import { exportWorkflow } from '@/utils/workflowData';
 import { useSharedWorkflowStore } from '@/stores/sharedWorkflow';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import WorkflowsLocalCard from './WorkflowsLocalCard.vue';
 
 const props = defineProps({

+ 1 - 1
src/components/newtab/workflows/WorkflowsShared.vue

@@ -12,7 +12,7 @@
 import { computed } from 'vue';
 import { useSharedWorkflowStore } from '@/stores/sharedWorkflow';
 import { arraySorter } from '@/utils/helper';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import SharedCard from '@/components/newtab/shared/SharedCard.vue';
 
 const props = defineProps({

+ 1 - 1
src/components/newtab/workflows/WorkflowsUserTeam.vue

@@ -61,7 +61,7 @@ import { useTeamWorkflowStore } from '@/stores/teamWorkflow';
 import { arraySorter } from '@/utils/helper';
 import { useDialog } from '@/composable/dialog';
 import { tagColors } from '@/utils/shared';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import SharedCard from '@/components/newtab/shared/SharedCard.vue';
 
 const props = defineProps({

+ 1 - 1
src/components/popup/home/HomeTeamWorkflows.vue

@@ -35,7 +35,7 @@ import { useUserStore } from '@/stores/user';
 import { sendMessage } from '@/utils/message';
 import { useTeamWorkflowStore } from '@/stores/teamWorkflow';
 import { tagColors } from '@/utils/shared';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import dayjs from '@/lib/dayjs';
 
 const props = defineProps({

+ 1 - 1
src/newtab/App.vue

@@ -77,7 +77,7 @@ import AppSidebar from '@/components/newtab/app/AppSidebar.vue';
 import dataMigration from '@/utils/dataMigration';
 import iconFirefox from '@/assets/svg/logoFirefox.svg';
 import iconChrome from '@/assets/svg/logo.svg';
-import { executeWorkflow } from './utils/workflowEngine';
+import { executeWorkflow } from './workflowEngine';
 
 let icon;
 if (window.location.protocol === 'moz-extension:') {

+ 1 - 1
src/newtab/pages/logs/Running.vue

@@ -80,7 +80,7 @@ import { useRoute, useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
 import { countDuration } from '@/utils/helper';
 import { useWorkflowStore } from '@/stores/workflow';
-import { workflowState } from '@/newtab/utils/workflowEngine';
+import { workflowState } from '@/newtab/workflowEngine';
 import dbLogs from '@/db/logs';
 import dayjs from '@/lib/dayjs';
 import LogsHistory from '@/components/newtab/logs/LogsHistory.vue';

+ 1 - 1
src/newtab/pages/workflows/Host.vue

@@ -120,7 +120,7 @@ import { useGroupTooltip } from '@/composable/groupTooltip';
 import { findTriggerBlock } from '@/utils/helper';
 import convertWorkflowData from '@/utils/convertWorkflowData';
 import { useWorkflowStore } from '@/stores/workflow';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import { useHostedWorkflowStore } from '@/stores/hostedWorkflow';
 import getTriggerText from '@/utils/triggerText';
 import EditorLogs from '@/components/newtab/workflow/editor/EditorLogs.vue';

+ 2 - 2
src/newtab/pages/workflows/[id].vue

@@ -317,12 +317,12 @@ import { getWorkflowPermissions } from '@/utils/workflowData';
 import { fetchApi } from '@/utils/api';
 import { getBlocks } from '@/utils/getSharedData';
 import { excludeGroupBlocks } from '@/utils/shared';
-import { functions } from '@/utils/referenceData/mustacheReplacer';
 import { useGroupTooltip } from '@/composable/groupTooltip';
 import { useCommandManager } from '@/composable/commandManager';
 import { debounce, parseJSON, throttle } from '@/utils/helper';
-import { executeWorkflow } from '@/newtab/utils/workflowEngine';
+import { executeWorkflow } from '@/newtab/workflowEngine';
 import { registerWorkflowTrigger } from '@/utils/workflowTrigger';
+import functions from '@/newtab/workflowEngine/templating/templatingFunctions';
 import browser from 'webextension-polyfill';
 import dbStorage from '@/db/storage';
 import DroppedNode from '@/utils/editor/DroppedNode';

+ 27 - 22
src/newtab/utils/workflowEngine/WorkflowEngine.js → src/newtab/workflowEngine/WorkflowEngine.js

@@ -312,7 +312,7 @@ class WorkflowEngine {
 
   async executeQueue() {
     const { workflowQueue } = await browser.storage.local.get('workflowQueue');
-    const queueIndex = (workflowQueue || []).indexOf(this.workflow.id);
+    const queueIndex = (workflowQueue || []).indexOf(this.workflow?.id);
 
     if (!workflowQueue || queueIndex === -1) return;
 
@@ -342,6 +342,29 @@ class WorkflowEngine {
   }
 
   async destroy(status, message, blockDetail) {
+    const cleanUp = () => {
+      this.id = null;
+      this.states = null;
+      this.logger = null;
+      this.saveLog = null;
+      this.workflow = null;
+      this.blocksHandler = null;
+      this.parentWorkflow = null;
+
+      this.isDestroyed = true;
+      this.referenceData = null;
+      this.eventListeners = null;
+      this.packagesCache = null;
+      this.extractedGroup = null;
+      this.connectionsMap = null;
+      this.waitConnections = null;
+      this.blocks = null;
+      this.history = null;
+      this.columnsId = null;
+      this.historyCtxData = null;
+      this.preloadScripts = null;
+    };
+
     try {
       if (this.isDestroyed) return;
       if (this.isUsingProxy) browser.proxy.settings.clear({});
@@ -461,29 +484,11 @@ class WorkflowEngine {
           },
         });
       }
+
+      cleanUp();
     } catch (error) {
       console.error(error);
-    } finally {
-      this.id = null;
-      this.states = null;
-      this.logger = null;
-      this.saveLog = null;
-      this.workflow = null;
-      this.blocksHandler = null;
-      this.parentWorkflow = null;
-
-      this.isDestroyed = true;
-      this.referenceData = null;
-      this.eventListeners = null;
-      this.packagesCache = null;
-      this.extractedGroup = null;
-      this.connectionsMap = null;
-      this.waitConnections = null;
-      this.blocks = null;
-      this.history = null;
-      this.columnsId = null;
-      this.historyCtxData = null;
-      this.preloadScripts = null;
+      cleanUp();
     }
   }
 

+ 0 - 0
src/newtab/utils/workflowEngine/WorkflowLogger.js → src/newtab/workflowEngine/WorkflowLogger.js


+ 0 - 0
src/newtab/utils/workflowEngine/WorkflowState.js → src/newtab/workflowEngine/WorkflowState.js


+ 6 - 6
src/newtab/utils/workflowEngine/WorkflowWorker.js → src/newtab/workflowEngine/WorkflowWorker.js

@@ -6,8 +6,8 @@ import {
   parseJSON,
   isObject,
 } from '@/utils/helper';
-import referenceData from '@/utils/referenceData';
-import mustacheReplacer from '@/utils/referenceData/mustacheReplacer';
+import templating from './templating';
+import renderString from './templating/renderString';
 import { convertData, waitTabLoaded } from './helper';
 import injectContentScript from './injectContentScript';
 
@@ -167,7 +167,7 @@ class WorkflowWorker {
       activeTabUrl: this.activeTab.url,
     };
 
-    const replacedBlock = referenceData({
+    const replacedBlock = await templating({
       block,
       data: refData,
       refKeys:
@@ -242,8 +242,8 @@ class WorkflowWorker {
         }
 
         if (blockOnError.insertData) {
-          blockOnError.dataToInsert.forEach((item) => {
-            let value = mustacheReplacer(item.value, refData)?.value;
+          for (const item of blockOnError.dataToInsert) {
+            let value = await renderString(item.value, refData)?.value;
             value = parseJSON(value, value);
 
             if (item.type === 'variable') {
@@ -251,7 +251,7 @@ class WorkflowWorker {
             } else {
               this.addDataToColumn(item.name, value);
             }
-          });
+          }
         }
 
         const nextBlocks = this.getBlockConnections(

+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler.js → src/newtab/workflowEngine/blocksHandler.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerActiveTab.js → src/newtab/workflowEngine/blocksHandler/handlerActiveTab.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerBlockPackage.js → src/newtab/workflowEngine/blocksHandler/handlerBlockPackage.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerBlocksGroup.js → src/newtab/workflowEngine/blocksHandler/handlerBlocksGroup.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerBrowserEvent.js → src/newtab/workflowEngine/blocksHandler/handlerBrowserEvent.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerClipboard.js → src/newtab/workflowEngine/blocksHandler/handlerClipboard.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerCloseTab.js → src/newtab/workflowEngine/blocksHandler/handlerCloseTab.js


+ 7 - 9
src/newtab/utils/workflowEngine/blocksHandler/handlerConditions.js → src/newtab/workflowEngine/blocksHandler/handlerConditions.js

@@ -1,8 +1,8 @@
 import { customAlphabet } from 'nanoid/non-secure';
 import browser from 'webextension-polyfill';
 import compareBlockValue from '@/utils/compareBlockValue';
-import mustacheReplacer from '@/utils/referenceData/mustacheReplacer';
 import testConditions from '@/utils/testConditions';
+import renderString from '../templating/renderString';
 import { automaRefDataStr, messageSandbox } from '../helper';
 
 const nanoid = customAlphabet('1234567890abcdef', 5);
@@ -147,14 +147,12 @@ async function conditions({ data, id }, { prevBlockData, refData }) {
       outputId = data.conditions[conditionsResult.index].id;
     }
   } else {
-    data.conditions.forEach(({ type, value, compareValue, id: itemId }) => {
-      if (isConditionMet) return;
+    for (const { type, value, compareValue, id: itemId } of data.conditions) {
+      if (isConditionMet) break;
 
-      const firstValue = mustacheReplacer(
-        compareValue ?? prevData,
-        refData
-      ).value;
-      const secondValue = mustacheReplacer(value, refData).value;
+      const firstValue = await renderString(compareValue ?? prevData, refData)
+        .value;
+      const secondValue = await renderString(value, refData).value;
 
       Object.assign(replacedValue, firstValue.list, secondValue.list);
 
@@ -169,7 +167,7 @@ async function conditions({ data, id }, { prevBlockData, refData }) {
         resultData = value;
         isConditionMet = true;
       }
-    });
+    }
   }
 
   return {

+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerCookie.js → src/newtab/workflowEngine/blocksHandler/handlerCookie.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerCreateElement.js → src/newtab/workflowEngine/blocksHandler/handlerCreateElement.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerDataMapping.js → src/newtab/workflowEngine/blocksHandler/handlerDataMapping.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerDelay.js → src/newtab/workflowEngine/blocksHandler/handlerDelay.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerDeleteData.js → src/newtab/workflowEngine/blocksHandler/handlerDeleteData.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerElementExists.js → src/newtab/workflowEngine/blocksHandler/handlerElementExists.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerExecuteWorkflow.js → src/newtab/workflowEngine/blocksHandler/handlerExecuteWorkflow.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerExportData.js → src/newtab/workflowEngine/blocksHandler/handlerExportData.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerForwardPage.js → src/newtab/workflowEngine/blocksHandler/handlerForwardPage.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerGoBack.js → src/newtab/workflowEngine/blocksHandler/handlerGoBack.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerGoogleSheets.js → src/newtab/workflowEngine/blocksHandler/handlerGoogleSheets.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerHandleDialog.js → src/newtab/workflowEngine/blocksHandler/handlerHandleDialog.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerHandleDownload.js → src/newtab/workflowEngine/blocksHandler/handlerHandleDownload.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerHoverElement.js → src/newtab/workflowEngine/blocksHandler/handlerHoverElement.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerIncreaseVariable.js → src/newtab/workflowEngine/blocksHandler/handlerIncreaseVariable.js


+ 3 - 3
src/newtab/utils/workflowEngine/blocksHandler/handlerInsertData.js → src/newtab/workflowEngine/blocksHandler/handlerInsertData.js

@@ -1,7 +1,7 @@
 import Papa from 'papaparse';
 import { parseJSON } from '@/utils/helper';
 import getFile from '@/utils/getFile';
-import mustacheReplacer from '@/utils/referenceData/mustacheReplacer';
+import renderString from '../templating/renderString';
 
 async function insertData({ id, data }, { refData }) {
   const replacedValueList = {};
@@ -10,7 +10,7 @@ async function insertData({ id, data }, { refData }) {
     let value = '';
 
     if (item.isFile) {
-      const replacedPath = mustacheReplacer(item.filePath || '', refData);
+      const replacedPath = await renderString(item.filePath || '', refData);
       const path = replacedPath.value;
       const isJSON = path.endsWith('.json');
       const isCSV = path.endsWith('.csv');
@@ -35,7 +35,7 @@ async function insertData({ id, data }, { refData }) {
       value = result;
       Object.assign(replacedValueList, replacedPath.list);
     } else {
-      const replacedValue = mustacheReplacer(item.value, refData);
+      const replacedValue = await renderString(item.value, refData);
       value = parseJSON(replacedValue.value, replacedValue.value);
       Object.assign(replacedValueList, replacedValue.list);
     }

+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerInteractionBlock.js → src/newtab/workflowEngine/blocksHandler/handlerInteractionBlock.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerJavascriptCode.js → src/newtab/workflowEngine/blocksHandler/handlerJavascriptCode.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerLogData.js → src/newtab/workflowEngine/blocksHandler/handlerLogData.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerLoopBreakpoint.js → src/newtab/workflowEngine/blocksHandler/handlerLoopBreakpoint.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerLoopData.js → src/newtab/workflowEngine/blocksHandler/handlerLoopData.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerLoopElements.js → src/newtab/workflowEngine/blocksHandler/handlerLoopElements.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerNewTab.js → src/newtab/workflowEngine/blocksHandler/handlerNewTab.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerNewWindow.js → src/newtab/workflowEngine/blocksHandler/handlerNewWindow.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerNotification.js → src/newtab/workflowEngine/blocksHandler/handlerNotification.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerParameterPrompt.js → src/newtab/workflowEngine/blocksHandler/handlerParameterPrompt.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerProxy.js → src/newtab/workflowEngine/blocksHandler/handlerProxy.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerRegexVariable.js → src/newtab/workflowEngine/blocksHandler/handlerRegexVariable.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerReloadTab.js → src/newtab/workflowEngine/blocksHandler/handlerReloadTab.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerRepeatTask.js → src/newtab/workflowEngine/blocksHandler/handlerRepeatTask.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerSaveAssets.js → src/newtab/workflowEngine/blocksHandler/handlerSaveAssets.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerSliceVariable.js → src/newtab/workflowEngine/blocksHandler/handlerSliceVariable.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerSortData.js → src/newtab/workflowEngine/blocksHandler/handlerSortData.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerSwitchTab.js → src/newtab/workflowEngine/blocksHandler/handlerSwitchTab.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerSwitchTo.js → src/newtab/workflowEngine/blocksHandler/handlerSwitchTo.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerTabUrl.js → src/newtab/workflowEngine/blocksHandler/handlerTabUrl.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerTakeScreenshot.js → src/newtab/workflowEngine/blocksHandler/handlerTakeScreenshot.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerTrigger.js → src/newtab/workflowEngine/blocksHandler/handlerTrigger.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerWaitConnections.js → src/newtab/workflowEngine/blocksHandler/handlerWaitConnections.js


+ 4 - 4
src/newtab/utils/workflowEngine/blocksHandler/handlerWebhook.js → src/newtab/workflowEngine/blocksHandler/handlerWebhook.js

@@ -1,7 +1,7 @@
 import objectPath from 'object-path';
 import { isWhitespace } from '@/utils/helper';
 import { executeWebhook } from '@/utils/webhookUtil';
-import mustacheReplacer from '@/utils/referenceData/mustacheReplacer';
+import renderString from '../templating/renderString';
 
 export async function webhook({ data, id }, { refData }) {
   const nextBlockId = this.getBlockConnections(id);
@@ -17,11 +17,11 @@ export async function webhook({ data, id }, { refData }) {
     }
 
     const newHeaders = [];
-    data.headers.forEach(({ value, name }) => {
-      const newValue = mustacheReplacer(value, refData).value;
+    for (const { value, name } of data.headers) {
+      const newValue = await renderString(value, refData).value;
 
       newHeaders.push({ name, value: newValue });
-    });
+    }
 
     const response = await executeWebhook({ ...data, headers: newHeaders });
 

+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerWhileLoop.js → src/newtab/workflowEngine/blocksHandler/handlerWhileLoop.js


+ 0 - 0
src/newtab/utils/workflowEngine/blocksHandler/handlerWorkflowState.js → src/newtab/workflowEngine/blocksHandler/handlerWorkflowState.js


+ 1 - 1
src/newtab/utils/workflowEngine/helper.js → src/newtab/workflowEngine/helper.js

@@ -7,7 +7,7 @@ export function messageSandbox(type, data = {}) {
   return new Promise((resolve) => {
     const messageId = nanoid();
 
-    const iframeEl = document.querySelector('#sandbox');
+    const iframeEl = document.getElementById('sandbox');
     iframeEl.contentWindow.postMessage({ id: messageId, type, ...data }, '*');
 
     const messageListener = ({ data: messageData }) => {

+ 0 - 0
src/newtab/utils/workflowEngine/index.js → src/newtab/workflowEngine/index.js


+ 0 - 0
src/newtab/utils/workflowEngine/injectContentScript.js → src/newtab/workflowEngine/injectContentScript.js


+ 40 - 0
src/newtab/workflowEngine/templating/index.js

@@ -0,0 +1,40 @@
+import objectPath from 'object-path';
+import cloneDeep from 'lodash.clonedeep';
+import renderString from './renderString';
+
+export default async function ({ block, refKeys, data }) {
+  if (!refKeys || refKeys.length === 0) return block;
+
+  const copyBlock = cloneDeep(block);
+  const addReplacedValue = (value) => {
+    if (!copyBlock.replacedValue) copyBlock.replacedValue = {};
+    copyBlock.replacedValue = { ...copyBlock.replacedValue, ...value };
+  };
+
+  for (const blockDataKey of refKeys) {
+    const currentData = objectPath.get(copyBlock.data, blockDataKey);
+    /* eslint-disable-next-line */
+    if (!currentData) continue;
+
+    if (Array.isArray(currentData)) {
+      for (let index = 0; index < currentData.length; index += 1) {
+        const value = currentData[index];
+        const renderedValue = await renderString(value, data);
+
+        addReplacedValue(renderedValue.list);
+        objectPath.set(
+          copyBlock.data,
+          `${blockDataKey}.${index}`,
+          renderedValue.value
+        );
+      }
+    } else if (typeof currentData === 'string') {
+      const renderedValue = await renderString(currentData, data);
+
+      addReplacedValue(renderedValue.list);
+      objectPath.set(copyBlock.data, blockDataKey, renderedValue.value);
+    }
+  }
+
+  return copyBlock;
+}

+ 3 - 128
src/utils/referenceData/mustacheReplacer.js → src/newtab/workflowEngine/templating/mustacheReplacer.js

@@ -1,138 +1,13 @@
 import objectPath from 'object-path';
-import jsonpath from 'jsonpath';
-import dayjs from '@/lib/dayjs';
 import credentialUtil from '@/utils/credentialUtil';
-import { parseJSON, isObject } from '@/utils/helper';
+import { parseJSON } from '@/utils/helper';
+import templatingFunctions from './templatingFunctions';
 
 const refKeys = {
   table: 'table',
   dataColumn: 'table',
   dataColumns: 'table',
 };
-const isAllNums = (...args) => args.every((arg) => !Number.isNaN(+arg));
-
-/* eslint-disable prefer-destructuring, no-useless-escape */
-export const functions = {
-  date(...args) {
-    let date = new Date();
-    let dateFormat = 'DD-MM-YYYY';
-
-    if (args.length === 1) {
-      dateFormat = args[0];
-    } else if (args.length >= 2) {
-      date = new Date(args[0]);
-      dateFormat = args[1];
-    }
-
-    /* eslint-disable-next-line */
-    const isValidDate = date instanceof Date && !isNaN(date);
-    const dayjsDate = dayjs(isValidDate ? date : Date.now());
-
-    let result = dayjsDate.format(dateFormat);
-
-    if (dateFormat === 'relative') result = dayjsDate.fromNow();
-    else if (dateFormat === 'timestamp') result = dayjsDate.valueOf();
-
-    return result;
-  },
-  randint(min = 0, max = 100) {
-    return Math.round(Math.random() * (+max - +min) + +min);
-  },
-  getLength(str) {
-    const value = parseJSON(str, str);
-
-    return value.length ?? value;
-  },
-  slice(value, start, end) {
-    if (!value || !value.slice) return value;
-
-    const startIndex = Number.isNaN(+start) ? 0 : +start;
-    const endIndex = Number.isNaN(+end) ? value.length : +end;
-
-    return value.slice(startIndex, endIndex);
-  },
-  multiply(value, multiplyBy) {
-    if (!isAllNums(value, multiplyBy)) return value;
-
-    return +value * +multiplyBy;
-  },
-  increment(value, incrementBy) {
-    if (!isAllNums(value, incrementBy)) return value;
-
-    return +value + +incrementBy;
-  },
-  divide(value, divideBy) {
-    if (!isAllNums(value, divideBy)) return value;
-
-    return +value / +divideBy;
-  },
-  subtract(value, subtractBy) {
-    if (!isAllNums(value, subtractBy)) return value;
-
-    return +value - +subtractBy;
-  },
-  randData(str) {
-    if (Array.isArray(str)) {
-      const index = Math.floor(Math.random() * str.length);
-      return str[index];
-    }
-
-    const getRand = (data) => data[Math.floor(Math.random() * data.length)];
-    const lowercase = 'abcdefghijklmnopqrstuvwxyz';
-    const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
-    const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-    const symbols = `!@#$%^&*()-_+={}[]|\;:'"<>,./?"`;
-    const mapSamples = {
-      l: () => getRand(lowercase),
-      u: () => getRand(uppercase),
-      d: () => getRand(digits),
-      s: () => getRand(symbols),
-      f() {
-        return this.l() + this.u();
-      },
-      n() {
-        return this.l() + this.d();
-      },
-      m() {
-        return this.u() + this.d();
-      },
-      i() {
-        return this.l() + this.u() + this.d();
-      },
-      a() {
-        return getRand(lowercase + uppercase + digits.join('') + symbols);
-      },
-    };
-
-    return `${str}`.replace(
-      /\?[a-zA-Z]/g,
-      (char) => mapSamples[char.at(-1)]?.() ?? char
-    );
-  },
-  filter(data, exps) {
-    if (!isObject(data) && !Array.isArray(data)) return data;
-
-    return jsonpath.query(data, exps);
-  },
-  replace(value, search, replace) {
-    if (!value) return value;
-
-    return value.replace(search, replace);
-  },
-  toLowerCase(value) {
-    if (!value) return value;
-
-    return value.toLowerCase();
-  },
-  toUpperCase(value) {
-    if (!value) return value;
-
-    return value.toUpperCase();
-  },
-  modulo(value, divisor) {
-    return +value % +divisor;
-  },
-};
 
 export function extractStrFunction(str) {
   const extractedStr = /^\$\s*(\w+)\s*\((.*)\)/.exec(
@@ -252,7 +127,7 @@ function replacer(str, { regex, tagLen, modifyPath, data }) {
 export default function (str, refData) {
   if (!str || typeof str !== 'string') return '';
 
-  const data = { ...refData, functions };
+  const data = { ...refData, functions: templatingFunctions };
   const replacedList = {};
 
   const replacedStr = replacer(`${str}`, {

+ 15 - 0
src/newtab/workflowEngine/templating/renderString.js

@@ -0,0 +1,15 @@
+import { messageSandbox } from '../helper';
+import mustacheReplacer from './mustacheReplacer';
+
+export default async function (str, data) {
+  if (!str || typeof str !== 'string') return '';
+
+  let renderedValue = {};
+  if (str.startsWith('!#')) {
+    renderedValue = await messageSandbox('blockExpression', { str, data });
+  } else {
+    renderedValue = mustacheReplacer(str, data);
+  }
+
+  return renderedValue;
+}

+ 142 - 0
src/newtab/workflowEngine/templating/templatingFunctions.js

@@ -0,0 +1,142 @@
+/* eslint-disable prefer-destructuring, no-useless-escape */
+import jsonpath from 'jsonpath';
+import dayjs from 'dayjs';
+import relativeTime from 'dayjs/plugin/relativeTime';
+
+dayjs.extend(relativeTime);
+
+const isAllNums = (...args) => args.every((arg) => !Number.isNaN(+arg));
+const isObject = (obj) =>
+  typeof obj === 'object' && obj !== null && !Array.isArray(obj);
+
+function parseJSON(data, def) {
+  try {
+    const result = JSON.parse(data);
+
+    return result;
+  } catch (error) {
+    return def;
+  }
+}
+
+export default {
+  date(...args) {
+    let date = new Date();
+    let dateFormat = 'DD-MM-YYYY';
+
+    if (args.length === 1) {
+      dateFormat = args[0];
+    } else if (args.length >= 2) {
+      date = new Date(args[0]);
+      dateFormat = args[1];
+    }
+
+    /* eslint-disable-next-line */
+    const isValidDate = date instanceof Date && !isNaN(date);
+    const dayjsDate = dayjs(isValidDate ? date : Date.now());
+
+    let result = dayjsDate.format(dateFormat);
+
+    if (dateFormat === 'relative') result = dayjsDate.fromNow();
+    else if (dateFormat === 'timestamp') result = dayjsDate.valueOf();
+
+    return result;
+  },
+  randint(min = 0, max = 100) {
+    return Math.round(Math.random() * (+max - +min) + +min);
+  },
+  getLength(str) {
+    const value = parseJSON(str, str);
+
+    return value.length ?? value;
+  },
+  slice(value, start, end) {
+    if (!value || !value.slice) return value;
+
+    const startIndex = Number.isNaN(+start) ? 0 : +start;
+    const endIndex = Number.isNaN(+end) ? value.length : +end;
+
+    return value.slice(startIndex, endIndex);
+  },
+  multiply(value, multiplyBy) {
+    if (!isAllNums(value, multiplyBy)) return value;
+
+    return +value * +multiplyBy;
+  },
+  increment(value, incrementBy) {
+    if (!isAllNums(value, incrementBy)) return value;
+
+    return +value + +incrementBy;
+  },
+  divide(value, divideBy) {
+    if (!isAllNums(value, divideBy)) return value;
+
+    return +value / +divideBy;
+  },
+  subtract(value, subtractBy) {
+    if (!isAllNums(value, subtractBy)) return value;
+
+    return +value - +subtractBy;
+  },
+  randData(str) {
+    if (Array.isArray(str)) {
+      const index = Math.floor(Math.random() * str.length);
+      return str[index];
+    }
+
+    const getRand = (data) => data[Math.floor(Math.random() * data.length)];
+    const lowercase = 'abcdefghijklmnopqrstuvwxyz';
+    const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+    const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    const symbols = `!@#$%^&*()-_+={}[]|\;:'"<>,./?"`;
+    const mapSamples = {
+      l: () => getRand(lowercase),
+      u: () => getRand(uppercase),
+      d: () => getRand(digits),
+      s: () => getRand(symbols),
+      f() {
+        return this.l() + this.u();
+      },
+      n() {
+        return this.l() + this.d();
+      },
+      m() {
+        return this.u() + this.d();
+      },
+      i() {
+        return this.l() + this.u() + this.d();
+      },
+      a() {
+        return getRand(lowercase + uppercase + digits.join('') + symbols);
+      },
+    };
+
+    return `${str}`.replace(
+      /\?[a-zA-Z]/g,
+      (char) => mapSamples[char.at(-1)]?.() ?? char
+    );
+  },
+  filter(data, exps) {
+    if (!isObject(data) && !Array.isArray(data)) return data;
+
+    return jsonpath.query(data, exps);
+  },
+  replace(value, search, replace) {
+    if (!value) return value;
+
+    return value.replace(search, replace);
+  },
+  toLowerCase(value) {
+    if (!value) return value;
+
+    return value.toLowerCase();
+  },
+  toUpperCase(value) {
+    if (!value) return value;
+
+    return value.toUpperCase();
+  },
+  modulo(value, divisor) {
+    return +value % +divisor;
+  },
+};

+ 15 - 144
src/sandbox/index.js

@@ -1,158 +1,29 @@
 import objectPath from 'object-path';
+import handleConditionCode from './utils/handleConditionCode';
+import handleJavascriptBlock from './utils/handleJavascriptBlock';
+import handleBlockExpression from './utils/handleBlockExpression';
 
 window.$getNestedProperties = objectPath.get;
 
-function handleJavascriptBlock(data) {
-  let timeout;
-  const scriptId = `script${data.id}`;
-  const propertyName = `automa${data.id}`;
+const eventHandlers = {
+  conditionCode: handleConditionCode,
+  blockExpression: handleBlockExpression,
+  javascriptBlock: handleJavascriptBlock,
+};
 
-  const isScriptExists = document.querySelector(`#${scriptId}`);
-  if (isScriptExists) {
+window.addEventListener('message', ({ data }) => {
+  if (!data.id || !data.type || !eventHandlers[data.type]) return;
+
+  function sendResponse(payload) {
     window.top.postMessage(
       {
         id: data.id,
         type: 'sandbox',
-        result: {
-          columns: {},
-          variables: {},
-        },
+        result: payload,
       },
       '*'
     );
-
-    return;
-  }
-
-  const preloadScripts = data.preloadScripts.map((item) => {
-    const scriptEl = document.createElement('script');
-    scriptEl.textContent = item.script;
-
-    document.body.appendChild(scriptEl);
-
-    return scriptEl;
-  });
-
-  if (!data.blockData.code.includes('automaNextBlock')) {
-    data.blockData.code += `\n automaNextBlock()`;
-  }
-
-  const script = document.createElement('script');
-  script.id = scriptId;
-  script.textContent = `
-    (() => {
-      function automaRefData(keyword, path = '') {
-        return window.$getNestedProperties(${propertyName}.refData, keyword + '.' + path);
-      }
-      function automaSetVariable(name, value) {
-        ${propertyName}.refData.variables[name] = value;
-      }
-      function automaNextBlock(data = {}, insert = true) {
-        ${propertyName}.nextBlock({ data, insert });
-      }
-      function automaResetTimeout() {
-        ${propertyName}.resetTimeout();
-      }
-
-      try {
-        ${data.blockData.code}
-      } catch (error) {
-        console.error(error);
-        automaNextBlock({ $error: true, message: error.message });
-      }
-    })();
-  `;
-
-  function cleanUp() {
-    script.remove();
-    preloadScripts.forEach((preloadScript) => {
-      preloadScript.remove();
-    });
-
-    delete window[propertyName];
   }
 
-  window[propertyName] = {
-    refData: data.refData,
-    nextBlock: (result) => {
-      cleanUp();
-      window.top.postMessage(
-        {
-          id: data.id,
-          type: 'sandbox',
-          result: {
-            variables: data?.refData?.variables,
-            columns: {
-              data: result?.data,
-              insert: result?.insert,
-            },
-          },
-        },
-        '*'
-      );
-    },
-    resetTimeout: () => {
-      clearTimeout(timeout);
-      timeout = setTimeout(cleanUp, data.blockData.timeout);
-    },
-  };
-
-  timeout = setTimeout(cleanUp, data.blockData.timeout);
-  document.body.appendChild(script);
-}
-function handleConditionCode(data) {
-  const propertyName = `automa${data.id}`;
-
-  const script = document.createElement('script');
-  script.textContent = `
-    (async () => {
-      function automaRefData(keyword, path = '') {
-        return window.$getNestedProperties(${propertyName}.refData, keyword + '.' + path);
-      }
-
-      try {
-        ${data.data.code}
-      } catch (error) {
-        return {
-          $isError: true,
-          message: error.message,
-        }
-      }
-    })()
-      .then((result) => {
-        ${propertyName}.done(result);
-      });
-  `;
-
-  window[propertyName] = {
-    refData: data.refData,
-    done: (result) => {
-      script.remove();
-      delete window[propertyName];
-
-      window.top.postMessage(
-        {
-          result,
-          id: data.id,
-          type: 'sandbox',
-        },
-        '*'
-      );
-    },
-  };
-
-  document.body.appendChild(script);
-}
-
-const eventHandlers = {
-  conditionCode: handleConditionCode,
-  javascriptBlock: handleJavascriptBlock,
-};
-
-function onMessage({ data }) {
-  if (!data.id || !data.type || !eventHandlers[data.type]) return;
-
-  eventHandlers[data.type](data);
-}
-
-window.addEventListener('message', onMessage);
+  eventHandlers[data.type](data, sendResponse);
+});

+ 19 - 0
src/sandbox/utils/handleBlockExpression.js

@@ -0,0 +1,19 @@
+import * as tmpl from '@n8n_io/riot-tmpl';
+import functions from '@/newtab/workflowEngine/templating/templatingFunctions';
+
+tmpl.brackets.set('{{ }}');
+
+const templatingFunctions = Object.keys(functions).reduce((acc, funcName) => {
+  acc[`$${funcName}`] = functions[funcName];
+
+  return acc;
+}, {});
+
+export default function ({ str, data }, sendResponse) {
+  const value = tmpl.tmpl(str, { ...data, ...templatingFunctions });
+
+  sendResponse({
+    list: {},
+    value: value.slice(2),
+  });
+}

+ 43 - 0
src/sandbox/utils/handleConditionCode.js

@@ -0,0 +1,43 @@
+export default function (data) {
+  const propertyName = `automa${data.id}`;
+
+  const script = document.createElement('script');
+  script.textContent = `
+    (async () => {
+      function automaRefData(keyword, path = '') {
+        return window.$getNestedProperties(${propertyName}.refData, keyword + '.' + path);
+      }
+
+      try {
+        ${data.data.code}
+      } catch (error) {
+        return {
+          $isError: true,
+          message: error.message,
+        }
+      }
+    })()
+      .then((result) => {
+        ${propertyName}.done(result);
+      });
+  `;
+
+  window[propertyName] = {
+    refData: data.refData,
+    done: (result) => {
+      script.remove();
+      delete window[propertyName];
+
+      window.top.postMessage(
+        {
+          result,
+          id: data.id,
+          type: 'sandbox',
+        },
+        '*'
+      );
+    },
+  };
+
+  document.body.appendChild(script);
+}

+ 98 - 0
src/sandbox/utils/handleJavascriptBlock.js

@@ -0,0 +1,98 @@
+export default function (data) {
+  let timeout;
+  const scriptId = `script${data.id}`;
+  const propertyName = `automa${data.id}`;
+
+  const isScriptExists = document.querySelector(`#${scriptId}`);
+  if (isScriptExists) {
+    window.top.postMessage(
+      {
+        id: data.id,
+        type: 'sandbox',
+        result: {
+          columns: {},
+          variables: {},
+        },
+      },
+      '*'
+    );
+
+    return;
+  }
+
+  const preloadScripts = data.preloadScripts.map((item) => {
+    const scriptEl = document.createElement('script');
+    scriptEl.textContent = item.script;
+
+    document.body.appendChild(scriptEl);
+
+    return scriptEl;
+  });
+
+  if (!data.blockData.code.includes('automaNextBlock')) {
+    data.blockData.code += `\n automaNextBlock()`;
+  }
+
+  const script = document.createElement('script');
+  script.id = scriptId;
+  script.textContent = `
+    (() => {
+      function automaRefData(keyword, path = '') {
+        return window.$getNestedProperties(${propertyName}.refData, keyword + '.' + path);
+      }
+      function automaSetVariable(name, value) {
+        ${propertyName}.refData.variables[name] = value;
+      }
+      function automaNextBlock(data = {}, insert = true) {
+        ${propertyName}.nextBlock({ data, insert });
+      }
+      function automaResetTimeout() {
+        ${propertyName}.resetTimeout();
+      }
+
+      try {
+        ${data.blockData.code}
+      } catch (error) {
+        console.error(error);
+        automaNextBlock({ $error: true, message: error.message });
+      }
+    })();
+  `;
+
+  function cleanUp() {
+    script.remove();
+    preloadScripts.forEach((preloadScript) => {
+      preloadScript.remove();
+    });
+
+    delete window[propertyName];
+  }
+
+  window[propertyName] = {
+    refData: data.refData,
+    nextBlock: (result) => {
+      cleanUp();
+      window.top.postMessage(
+        {
+          id: data.id,
+          type: 'sandbox',
+          result: {
+            variables: data?.refData?.variables,
+            columns: {
+              data: result?.data,
+              insert: result?.insert,
+            },
+          },
+        },
+        '*'
+      );
+    },
+    resetTimeout: () => {
+      clearTimeout(timeout);
+      timeout = setTimeout(cleanUp, data.blockData.timeout);
+    },
+  };
+
+  timeout = setTimeout(cleanUp, data.blockData.timeout);
+  document.body.appendChild(script);
+}

+ 0 - 43
src/utils/referenceData/index.js

@@ -1,43 +0,0 @@
-import objectPath from 'object-path';
-import cloneDeep from 'lodash.clonedeep';
-import mustacheReplacer from './mustacheReplacer';
-
-export default function ({ block, refKeys, data }) {
-  if (!refKeys || refKeys.length === 0) return block;
-
-  const copyBlock = cloneDeep(block);
-  const addReplacedValue = (value) => {
-    if (!copyBlock.replacedValue) copyBlock.replacedValue = {};
-
-    copyBlock.replacedValue = { ...copyBlock.replacedValue, ...value };
-  };
-
-  refKeys.forEach((blockDataKey) => {
-    const options = {
-      stringify: block.label === 'webhook' && blockDataKey === 'body',
-    };
-    const currentData = objectPath.get(copyBlock.data, blockDataKey);
-
-    if (!currentData) return;
-
-    if (Array.isArray(currentData)) {
-      currentData.forEach((str, index) => {
-        const replacedStr = mustacheReplacer(str, data, options);
-
-        addReplacedValue(replacedStr.list);
-        objectPath.set(
-          copyBlock.data,
-          `${blockDataKey}.${index}`,
-          replacedStr.value
-        );
-      });
-    } else if (typeof currentData === 'string') {
-      const replacedStr = mustacheReplacer(currentData, data, options);
-
-      addReplacedValue(replacedStr.list);
-      objectPath.set(copyBlock.data, blockDataKey, replacedStr.value);
-    }
-  });
-
-  return copyBlock;
-}

+ 4 - 4
src/utils/testConditions.js

@@ -1,6 +1,6 @@
 import cloneDeep from 'lodash.clonedeep';
 import objectPath from 'object-path';
-import mustacheReplacer from './referenceData/mustacheReplacer';
+import renderString from '@/newtab/workflowEngine/templating/renderString';
 import { conditionBuilder } from './shared';
 
 const isBoolStr = (str) => {
@@ -48,15 +48,15 @@ export default async function (conditionsArr, workflowData) {
 
     const copyData = cloneDeep(data);
 
-    Object.keys(data).forEach((key) => {
-      const { value, list } = mustacheReplacer(
+    for (const key of Object.keys(data)) {
+      const { value, list } = await renderString(
         copyData[key],
         workflowData.refData
       );
 
       copyData[key] = value ?? '';
       Object.assign(result.replacedValue, list);
-    });
+    }
 
     if (type === 'value') return copyData.value;
 

文件差異過大導致無法顯示
+ 332 - 330
yarn.lock


部分文件因文件數量過多而無法顯示