Browse Source

Merge branch 'dev' of github.com:AutomaApp/automa into dev

M Gilang Januar 3 years ago
parent
commit
e008313ac2

+ 10 - 10
package.json

@@ -1,6 +1,6 @@
 {
   "name": "automa",
-  "version": "1.14.2",
+  "version": "1.14.5",
   "description": "An extension for automating your browser by connecting blocks",
   "license": "MIT",
   "repository": {
@@ -36,12 +36,12 @@
     "@codemirror/language": "^6.0.0",
     "@codemirror/theme-one-dark": "^6.0.0",
     "@medv/finder": "^2.1.0",
-    "@tiptap/extension-character-count": "^2.0.0-beta.24",
-    "@tiptap/extension-image": "^2.0.0-beta.25",
-    "@tiptap/extension-link": "^2.0.0-beta.41",
-    "@tiptap/extension-placeholder": "^2.0.0-beta.51",
-    "@tiptap/starter-kit": "^2.0.0-beta.189",
-    "@tiptap/vue-3": "^2.0.0-beta.90",
+    "@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",
+    "@tiptap/extension-placeholder": "^2.0.0-beta.53",
+    "@tiptap/starter-kit": "^2.0.0-beta.190",
+    "@tiptap/vue-3": "^2.0.0-beta.96",
     "@viselect/vanilla": "^3.0.0-beta.13",
     "@vueuse/rxjs": "^8.7.4",
     "@vuex-orm/core": "^0.36.4",
@@ -87,10 +87,10 @@
     "bumpp": "^7.1.1",
     "clean-webpack-plugin": "4.0.0",
     "copy-webpack-plugin": "^11.0.0",
-    "core-js": "3",
+    "core-js": "^3.23.3",
     "cross-env": "^7.0.3",
     "css-loader": "^6.7.1",
-    "eslint": "7.32.0",
+    "eslint": "^8.19.0",
     "eslint-config-airbnb-base": "^15.0.0",
     "eslint-config-prettier": "^8.3.0",
     "eslint-friendly-formatter": "^4.0.1",
@@ -117,4 +117,4 @@
     "webpack-cli": "^4.10.0",
     "webpack-dev-server": "^4.9.2"
   }
-}
+}

+ 25 - 0
src/background/workflowEngine/blocksHandler/handlerIncreaseVariable.js

@@ -0,0 +1,25 @@
+import { objectHasKey } from '@/utils/helper';
+
+export async function increaseVariable({ id, data }) {
+  const refVariables = this.engine.referenceData.variables;
+
+  if (!objectHasKey(refVariables, data.variableName)) {
+    throw new Error(`Cant find "${data.variableName}" variable`);
+  }
+
+  const currentVar = +refVariables[data.variableName];
+  if (Number.isNaN(currentVar)) {
+    throw new Error(
+      `The "${data.variableName}" variable value is not a number`
+    );
+  }
+
+  refVariables[data.variableName] += data.increaseBy;
+
+  return {
+    data: refVariables[data.variableName],
+    nextBlockId: this.getBlockConnections(id),
+  };
+}
+
+export default increaseVariable;

+ 29 - 0
src/background/workflowEngine/blocksHandler/handlerRegexVariable.js

@@ -0,0 +1,29 @@
+import { objectHasKey } from '@/utils/helper';
+
+export async function regexVariable({ id, data }) {
+  const refVariables = this.engine.referenceData.variables;
+
+  if (!objectHasKey(refVariables, data.variableName)) {
+    throw new Error(`Cant find "${data.variableName}" variable`);
+  }
+
+  const currentVar = refVariables[data.variableName];
+  if (typeof currentVar !== 'string') {
+    throw new Error(
+      `The value of the "${data.variableName}" variable is not a string/text`
+    );
+  }
+
+  const regex = new RegExp(data.expression, data.flag.join(''));
+  const matches = currentVar.match(regex);
+  const newValue = matches && !data.flag.includes('g') ? matches[0] : matches;
+
+  refVariables[data.variableName] = newValue;
+
+  return {
+    data: newValue,
+    nextBlockId: this.getBlockConnections(id),
+  };
+}
+
+export default regexVariable;

+ 27 - 0
src/background/workflowEngine/blocksHandler/handlerSliceVariable.js

@@ -0,0 +1,27 @@
+export async function sliceData({ id, data }) {
+  const variable = this.engine.referenceData.variables[data.variableName];
+  const payload = {
+    data: variable,
+    nextBlockId: this.getBlockConnections(id),
+  };
+
+  if (!variable || !variable?.slice) return payload;
+
+  let startIndex = 0;
+  let endIndex = variable.length;
+
+  if (data.startIdxEnabled) {
+    startIndex = data.startIndex;
+  }
+  if (data.endIdxEnabled) {
+    endIndex = data.endIndex;
+  }
+
+  const slicedVariable = variable.slice(startIndex, endIndex);
+  payload.data = slicedVariable;
+  this.engine.referenceData.variables[data.variableName] = slicedVariable;
+
+  return payload;
+}
+
+export default sliceData;

+ 2 - 2
src/components/newtab/workflow/WorkflowDataTable.vue

@@ -35,9 +35,9 @@
   </template>
   <div
     v-else-if="state.connectedTable"
-    class="py-2 px-4 rounded-md bg-green-200 dark:bg-green-300 flex items-center mb-4"
+    class="py-2 px-4 rounded-md bg-green-200 dark:bg-green-300 flex items-center mb-4 text-black"
   >
-    <p class="mr-1 text-black">
+    <p class="mr-1">
       This workflow is connected to the
       <router-link
         :to="`/storage/tables/${state.connectedTable.id}`"

+ 2 - 2
src/components/newtab/workflow/WorkflowEditor.vue

@@ -126,11 +126,11 @@ const { t } = useI18n();
 const store = useStore();
 const editor = useVueFlow({
   id: props.id,
-  minZoom: 0.4,
+  minZoom: 0.7,
   edgeUpdaterRadius: 20,
   deleteKeyCode: 'Delete',
   elevateEdgesOnSelect: true,
-  defaultZoom: props.data?.zoom ?? 0.7,
+  defaultZoom: props.data?.zoom ?? 1,
   multiSelectionKeyCode: isMac ? 'Meta' : 'Control',
   defaultPosition: getPosition(props.data?.position),
   ...props.options,

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

@@ -221,7 +221,7 @@ async function publishWorkflow() {
     const workflow = convertWorkflow(state.workflow, ['id', 'category']);
     workflow.name = workflow.name || 'unnamed';
     workflow.content = state.workflow.content || null;
-    workflow.drawflow = parseJSON(workflow.drawflow, {});
+    workflow.drawflow = parseJSON(workflow.drawflow, workflow.drawflow);
     workflow.description = state.workflow.description.slice(0, 300);
 
     delete workflow.extVersion;

+ 25 - 10
src/components/newtab/workflow/edit/BlockSetting/BlockSettingLines.vue

@@ -10,8 +10,15 @@
       </option>
     </ui-select>
     <div v-if="activeEdge" class="mt-4">
-      <div class="flex items-center mt-2">
-        <label class="flex items-center mr-4 mt-5">
+      <ui-input
+        :model-value="activeEdge.label"
+        :label="t('workflow.blocks.base.settings.line.label')"
+        placeholder="A label"
+        class="w-full"
+        @change="updateActiveEdge('label', $event)"
+      />
+      <div class="flex items-center mt-4">
+        <label class="flex items-center mr-4 block">
           <ui-switch
             :model-value="activeEdge.animated"
             @change="updateActiveEdge('animated', $event)"
@@ -20,13 +27,19 @@
             {{ t('workflow.blocks.base.settings.line.animated') }}
           </span>
         </label>
-        <ui-input
-          :model-value="activeEdge.label"
-          :label="t('workflow.blocks.base.settings.line.label')"
-          placeholder="A label"
-          class="flex-1"
-          @change="updateActiveEdge('label', $event)"
-        />
+        <div class="w-32" />
+        <label class="flex items-center">
+          <input
+            :value="activeEdge.style?.stroke ?? null"
+            type="color"
+            name="color"
+            class="h-10 w-10 rounded-lg bg-input p-1"
+            @input="updateActiveEdge('style', { stroke: $event.target.value })"
+          />
+          <span class="ml-2">
+            {{ t('workflow.blocks.base.settings.line.lineColor') }}
+          </span>
+        </label>
       </div>
     </div>
   </div>
@@ -63,7 +76,7 @@ const updateActiveEdge = debounce((name, value) => {
 
 onMounted(() => {
   state.edges = editor.value.getEdges.value.reduce(
-    (acc, { id, source, targetNode, label, animated, labelStyle }) => {
+    (acc, { id, source, targetNode, label, animated, labelStyle, style }) => {
       if (source !== props.blockId) return acc;
 
       let name = t('workflow.blocks.base.settings.line.to', {
@@ -81,6 +94,8 @@ onMounted(() => {
         labelStyle: labelStyle || '',
       };
 
+      if (style) acc[id].style = style;
+
       return acc;
     },
     {}

+ 47 - 0
src/components/newtab/workflow/edit/EditIncreaseVariable.vue

@@ -0,0 +1,47 @@
+<template>
+  <div>
+    <ui-textarea
+      :model-value="data.description"
+      :placeholder="t('common.description')"
+      class="w-full"
+      @change="updateData({ description: $event })"
+    />
+    <ui-input
+      :model-value="data.variableName"
+      :label="t('workflow.variables.name')"
+      :title="t('workflow.variables.name')"
+      class="mt-2 w-full"
+      @change="updateData({ variableName: $event })"
+    />
+    <ui-input
+      :model-value="data.increaseBy"
+      :label="t('workflow.blocks.increase-variable.increase')"
+      placeholder="0"
+      type="number"
+      class="w-full mt-2"
+      @change="updateData({ increaseBy: +$event })"
+    />
+  </div>
+</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+</script>
+<style>
+.log-data .block-variable {
+  margin-top: 4px;
+}
+</style>

+ 97 - 0
src/components/newtab/workflow/edit/EditRegexVariable.vue

@@ -0,0 +1,97 @@
+<template>
+  <div>
+    <ui-textarea
+      :model-value="data.description"
+      :placeholder="t('common.description')"
+      class="w-full"
+      @change="updateData({ description: $event })"
+    />
+    <ui-input
+      :model-value="data.variableName"
+      :label="t('workflow.variables.name')"
+      :title="t('workflow.variables.name')"
+      class="mt-2 w-full"
+      @change="updateData({ variableName: $event })"
+    />
+    <div class="flex items-end mt-2">
+      <div class="flex-1 mr-2">
+        <label
+          class="ml-1 block text-gray-600 dark:text-gray-200 text-sm"
+          for="var-expression"
+        >
+          RegEx
+        </label>
+        <div
+          class="flex items-center bg-input transition-colors px-4 rounded-lg"
+        >
+          <span>/</span>
+          <input
+            id="var-expression"
+            :value="data.expression"
+            placeholder="Expression"
+            class="py-2 w-11/12 bg-transparent focus:ring-0 px-1"
+            @input="updateData({ expression: $event.target.value })"
+          />
+          <span class="text-right">/</span>
+        </div>
+      </div>
+      <ui-popover>
+        <template #trigger>
+          <button class="p-2 rounded-lg bg-input" title="Flags">
+            {{ data.flag.length === 0 ? 'flags' : data.flag.join('') }}
+          </button>
+        </template>
+        <p>Flags</p>
+        <ul class="mt-2 space-y-1">
+          <li v-for="flag in flags" :key="flag.id">
+            <ui-checkbox
+              :model-value="data.flag.includes(flag.id)"
+              @change="updateFlag($event, flag.id)"
+            >
+              {{ flag.name }}
+            </ui-checkbox>
+          </li>
+        </ul>
+      </ui-popover>
+    </div>
+  </div>
+</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+const flags = [
+  { id: 'g', name: 'global' },
+  { id: 'i', name: 'ignore case' },
+  { id: 'm', name: 'multiline' },
+];
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+function updateFlag(include, flag) {
+  const copyFlag = [...props.data.flag];
+
+  if (include) {
+    copyFlag.push(flag);
+  } else {
+    const index = copyFlag.indexOf(flag);
+    copyFlag.splice(index, 1);
+  }
+
+  updateData({ flag: copyFlag });
+}
+</script>
+<style>
+.log-data .block-variable {
+  margin-top: 4px;
+}
+</style>

+ 62 - 0
src/components/newtab/workflow/edit/EditSliceVariable.vue

@@ -0,0 +1,62 @@
+<template>
+  <div>
+    <ui-textarea
+      :model-value="data.description"
+      :placeholder="t('common.description')"
+      class="w-full"
+      @change="updateData({ description: $event })"
+    />
+    <ui-input
+      :model-value="data.variableName"
+      :label="t('workflow.variables.name')"
+      :title="t('workflow.variables.name')"
+      class="mt-2 w-full"
+      @change="updateData({ variableName: $event })"
+    />
+    <ul class="mt-4 space-y-2">
+      <li v-for="param in params" :key="param.id">
+        <ui-checkbox
+          :model-value="data[param.toggleKey]"
+          @change="updateData({ [param.toggleKey]: $event })"
+        >
+          {{ t(`workflow.blocks.slice-variable.${param.text}`) }}
+        </ui-checkbox>
+        <ui-input
+          v-if="data[param.toggleKey]"
+          :model-value="data[param.id]"
+          placeholder="0"
+          type="number"
+          class="w-full mb-2"
+          @change="updateData({ [param.id]: +$event })"
+        />
+      </li>
+    </ul>
+  </div>
+</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+
+const params = [
+  { id: 'startIndex', text: 'start', toggleKey: 'startIdxEnabled' },
+  { id: 'endIndex', text: 'end', toggleKey: 'endIdxEnabled' },
+];
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+</script>
+<style>
+.log-data .block-variable {
+  margin-top: 4px;
+}
+</style>

+ 5 - 0
src/content/services/webService.js

@@ -64,6 +64,11 @@ function initWebListener() {
           table: workflow.table || workflow.dataColumns,
         };
 
+        workflowData.drawflow =
+          typeof workflowData.drawflow === 'string'
+            ? parseJSON(workflowData.drawflow, workflowData.drawflow)
+            : workflowData.drawflow;
+
         if (Array.isArray(workflowsStorage)) {
           workflowsStorage.push(workflowData);
         } else {

+ 2 - 1
src/content/showExecutedBlock.js

@@ -35,7 +35,8 @@ export default function (data, enable) {
     return () => {};
   }
 
-  const block = tasks[data.name];
+  const block = tasks[data.label];
+  if (!block) return () => {};
   let container = document.querySelector('.automa-executed-block');
 
   if (!container) {

+ 6 - 0
src/lib/vRemixicon.js

@@ -27,6 +27,7 @@ import {
   riChat3Line,
   riEarthLine,
   riLock2Line,
+  riSliceLine,
   riHome5Line,
   riShareLine,
   riBook3Line,
@@ -119,6 +120,7 @@ import {
   riArrowGoForwardLine,
   riCheckboxCircleLine,
   riLightbulbFlashLine,
+  riIncreaseDecreaseLine,
 } from 'v-remixicon/icons';
 
 export const icons = {
@@ -149,6 +151,7 @@ export const icons = {
   riChat3Line,
   riEarthLine,
   riLock2Line,
+  riSliceLine,
   riHome5Line,
   riShareLine,
   riBook3Line,
@@ -241,9 +244,12 @@ export const icons = {
   riArrowGoForwardLine,
   riCheckboxCircleLine,
   riLightbulbFlashLine,
+  riIncreaseDecreaseLine,
   mdiEqual: 'M19,10H5V8H19V10M19,16H5V14H19V16Z',
   mdiVariable:
     'M20.41,3C21.8,5.71 22.35,8.84 22,12C21.8,15.16 20.7,18.29 18.83,21L17.3,20C18.91,17.57 19.85,14.8 20,12C20.34,9.2 19.89,6.43 18.7,4L20.41,3M5.17,3L6.7,4C5.09,6.43 4.15,9.2 4,12C3.66,14.8 4.12,17.57 5.3,20L3.61,21C2.21,18.29 1.65,15.17 2,12C2.2,8.84 3.3,5.71 5.17,3M12.08,10.68L14.4,7.45H16.93L13.15,12.45L15.35,17.37H13.09L11.71,14L9.28,17.33H6.76L10.66,12.21L8.53,7.45H10.8L12.08,10.68Z',
+  mdiRegex:
+    'M16,16.92C15.67,16.97 15.34,17 15,17C14.66,17 14.33,16.97 14,16.92V13.41L11.5,15.89C11,15.5 10.5,15 10.11,14.5L12.59,12H9.08C9.03,11.67 9,11.34 9,11C9,10.66 9.03,10.33 9.08,10H12.59L10.11,7.5C10.3,7.25 10.5,7 10.76,6.76V6.76C11,6.5 11.25,6.3 11.5,6.11L14,8.59V5.08C14.33,5.03 14.66,5 15,5C15.34,5 15.67,5.03 16,5.08V8.59L18.5,6.11C19,6.5 19.5,7 19.89,7.5L17.41,10H20.92C20.97,10.33 21,10.66 21,11C21,11.34 20.97,11.67 20.92,12H17.41L19.89,14.5C19.7,14.75 19.5,15 19.24,15.24V15.24C19,15.5 18.75,15.7 18.5,15.89L16,13.41V16.92H16V16.92M5,19A2,2 0 0,1 7,17A2,2 0 0,1 9,19A2,2 0 0,1 7,21A2,2 0 0,1 5,19H5Z',
   mdiDrag:
     'M7,19V17H9V19H7M11,19V17H13V19H11M15,19V17H17V19H15M7,15V13H9V15H7M11,15V13H13V15H11M15,15V13H17V15H15M7,11V9H9V11H7M11,11V9H13V11H11M15,11V9H17V11H15M7,7V5H9V7H7M11,7V5H13V7H11M15,7V5H17V7H15Z',
   webhookIcon:

+ 16 - 0
src/locales/en/blocks.json

@@ -25,6 +25,7 @@
             "animated": "Animated",
             "select": "Select line",
             "to": "Line to {name} block",
+            "lineColor": "Line color"
           }
         },
         "toggle": {
@@ -95,6 +96,21 @@
         "specificFlow": "Only continue a specific flow",
         "selectFlow": "Select flow"
       },
+      "slice-variable": {
+        "name": "Slice variable",
+        "description": "Extracts a section of a variable value",
+        "start": "Start index",
+        "end": "End index"
+      },
+      "regex-variable": {
+        "name": "RegEx variable",
+        "description": "Matching a variable value against a regular expression"
+      },
+      "increase-variable": {
+        "name": "Increase variable",
+        "description": "Increase the value of a variable by specific amount",
+        "increase": "Increase by"
+      },
       "notification": {
         "name": "notification",
         "description": "Display a notification",

+ 1 - 1
src/stores/workflow.js

@@ -20,7 +20,7 @@ const defaultWorkflow = (data = null, options = {}) => {
     connectedTable: null,
     drawflow: {
       edges: [],
-      position: { zoom: 1 },
+      zoom: 1.3,
       nodes: [
         {
           position: {

+ 57 - 0
src/utils/shared.js

@@ -1049,6 +1049,63 @@ export const tasks = {
       variableName: '',
     },
   },
+  'slice-variable': {
+    name: 'Slice variable',
+    description: 'Extracts a section of a variable value',
+    icon: 'riSliceLine',
+    editComponent: 'EditSliceVariable',
+    component: 'BlockBasic',
+    category: 'data',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: true,
+    maxConnection: 1,
+    data: {
+      disableBlock: false,
+      description: '',
+      endIdxEnabled: false,
+      startIdxEnabled: true,
+      endIndex: 0,
+      startIndex: 0,
+      variableName: '',
+    },
+  },
+  'increase-variable': {
+    name: 'Increase variable',
+    description: 'Increase the value of a variable by specific amount',
+    icon: 'riIncreaseDecreaseLine',
+    editComponent: 'EditIncreaseVariable',
+    component: 'BlockBasic',
+    category: 'data',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: true,
+    maxConnection: 1,
+    data: {
+      disableBlock: false,
+      description: '',
+      increaseBy: 1,
+      variableName: '',
+    },
+  },
+  'regex-variable': {
+    name: 'RegEx variable',
+    description: 'Matching a variable value against a regular expression',
+    icon: 'mdiRegex',
+    editComponent: 'EditRegexVariable',
+    component: 'BlockBasic',
+    category: 'data',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: true,
+    maxConnection: 1,
+    data: {
+      disableBlock: false,
+      description: '',
+      expression: '',
+      flag: [],
+    },
+  },
 };
 
 export const categories = {

+ 2 - 0
src/utils/workflowTrigger.js

@@ -13,6 +13,8 @@ export function registerContextMenu(workflowId, data) {
     const isFirefox = BROWSER_TYPE === 'firefox';
     const browserContext = isFirefox ? browser.menus : browser.contextMenus;
 
+    if (!browserContext) return;
+
     browserContext.create(
       {
         id: workflowId,

File diff suppressed because it is too large
+ 521 - 526
yarn.lock


Some files were not shown because too many files changed in this diff