Browse Source

feat: add sort data block

Ahmad Kholid 3 years ago
parent
commit
7c54c84284

BIN
automa.zip


+ 4 - 1
src/background/index.js

@@ -414,8 +414,11 @@ browser.runtime.onInstalled.addListener(async ({ reason }) => {
 });
 });
 browser.runtime.onStartup.addListener(async () => {
 browser.runtime.onStartup.addListener(async () => {
   const { workflows } = await browser.storage.local.get('workflows');
   const { workflows } = await browser.storage.local.get('workflows');
+  const workflowsArr = Array.isArray(workflows)
+    ? workflows
+    : Object.values(workflows);
 
 
-  for (const currWorkflow of workflows) {
+  for (const currWorkflow of workflowsArr) {
     let triggerBlock = currWorkflow.trigger;
     let triggerBlock = currWorkflow.trigger;
 
 
     if (!triggerBlock) {
     if (!triggerBlock) {

+ 69 - 0
src/background/workflowEngine/blocksHandler/handlerSortData.js

@@ -0,0 +1,69 @@
+import { objectHasKey } from '@/utils/helper';
+
+export async function sliceData({ id, data }) {
+  let dataToSort = null;
+
+  if (data.dataSource === 'table') {
+    dataToSort = this.engine.referenceData.table;
+  } else if (data.dataSource === 'variable') {
+    const { variables } = this.engine.referenceData;
+
+    if (!objectHasKey(variables, data.varSourceName)) {
+      throw new Error(`Cant find "${data.varSourceName}" variable`);
+    }
+
+    dataToSort = variables[data.varSourceName];
+  }
+
+  if (!Array.isArray(dataToSort)) {
+    const dataType = dataToSort === null ? 'null' : typeof dataToSort;
+
+    throw new Error(`Can't sort data with "${dataType}" data type`);
+  }
+
+  const getComparisonValue = ({ itemA, itemB, order = 'asc' }) => {
+    let comparison = 0;
+
+    if (itemA > itemB) {
+      comparison = 1;
+    } else if (itemA < itemB) {
+      comparison = -1;
+    }
+
+    return order === 'desc' ? comparison * -1 : comparison;
+  };
+  const sortedArray = dataToSort.sort((a, b) => {
+    let comparison = 0;
+
+    if (data.sortByProperty) {
+      data.itemProperties.forEach(({ name, order }) => {
+        comparison = getComparisonValue({
+          order,
+          itemA: a[name] ?? a,
+          itemB: b[name] ?? b,
+        });
+      });
+    } else {
+      comparison = getComparisonValue({
+        itemA: a,
+        itemB: b,
+      });
+    }
+
+    return comparison;
+  });
+
+  if (data.assignVariable) {
+    this.setVariable(data.variableName, sortedArray);
+  }
+  if (data.saveData) {
+    this.addDataToColumn(data.dataColumn, sortedArray);
+  }
+
+  return {
+    data: sortedArray,
+    nextBlockId: this.getBlockConnections(id),
+  };
+}
+
+export default sliceData;

+ 1 - 0
src/background/workflowEngine/helper.js

@@ -57,6 +57,7 @@ export function waitTabLoaded({ tabId, listenError = false, ms = 10000 }) {
       )
       )
         return;
         return;
 
 
+      clearTimeout(timeout);
       browser.webNavigation.onErrorOccurred.removeListener(onErrorOccurred);
       browser.webNavigation.onErrorOccurred.removeListener(onErrorOccurred);
       reject(new Error(details.error));
       reject(new Error(details.error));
     };
     };

+ 1 - 1
src/components/block/BlockGroup.vue

@@ -22,7 +22,7 @@
         />
         />
       </div>
       </div>
       <input
       <input
-        :model-value="data.name"
+        :value="data.name"
         :placeholder="t('workflow.blocks.blocks-group.groupName')"
         :placeholder="t('workflow.blocks.blocks-group.groupName')"
         type="text"
         type="text"
         class="bg-transparent w-full focus:ring-0"
         class="bg-transparent w-full focus:ring-0"

+ 1 - 1
src/components/newtab/workflow/edit/EditDataMapping.vue

@@ -155,7 +155,7 @@ const workflow = inject('workflow');
 
 
 const state = reactive({
 const state = reactive({
   query: '',
   query: '',
-  showModal: true,
+  showModal: false,
   autocompleteItems: [],
   autocompleteItems: [],
   sources: [...props.data.sources],
   sources: [...props.data.sources],
 });
 });

+ 128 - 0
src/components/newtab/workflow/edit/EditSortData.vue

@@ -0,0 +1,128 @@
+<template>
+  <div>
+    <ui-textarea
+      :model-value="data.description"
+      :placeholder="t('common.description')"
+      class="w-full"
+      @change="updateData({ description: $event })"
+    />
+    <ui-select
+      :label="t('workflow.blocks.data-mapping.dataSource')"
+      :model-value="data.dataSource"
+      class="w-full mt-4"
+      @change="updateData({ dataSource: $event })"
+    >
+      <option v-for="source in dataSources" :key="source.id" :value="source.id">
+        {{ source.name }}
+      </option>
+    </ui-select>
+    <ui-input
+      v-if="data.dataSource === 'variable'"
+      :model-value="data.varSourceName"
+      :placeholder="t('workflow.variables.name')"
+      :title="t('workflow.variables.name')"
+      class="mt-2 w-full"
+      @change="updateData({ varSourceName: $event })"
+    />
+    <label class="flex items-center mt-4">
+      <ui-switch
+        :model-value="data.sortByProperty"
+        @change="updateData({ sortByProperty: $event })"
+      />
+      <span class="ml-2">
+        {{ t('workflow.blocks.sort-data.property') }}
+      </span>
+    </label>
+    <template v-if="data.sortByProperty">
+      <ul
+        v-for="(property, index) in properties"
+        :key="index"
+        class="mt-4 space-y-1 divide-y"
+      >
+        <li class="sort-property">
+          <ui-autocomplete
+            :model-value="property.name"
+            :items="columns"
+            :disabled="data.dataSource !== 'table'"
+            class="w-full"
+          >
+            <ui-input
+              v-model="property.name"
+              autocomplete="off"
+              :placeholder="`Property ${index + 1}`"
+              class="w-full"
+            />
+          </ui-autocomplete>
+          <div class="flex items-center mt-2">
+            <ui-select v-model="property.order" class="flex-1">
+              <option value="asc">Ascending</option>
+              <option value="desc">Descending</option>
+            </ui-select>
+            <ui-button class="ml-2" icon @click="properties.splice(index, 1)">
+              <v-remixicon name="riDeleteBin7Line" />
+            </ui-button>
+          </div>
+        </li>
+      </ul>
+      <ui-button
+        v-if="properties.length < 3"
+        variant="accent"
+        class="mt-4 text-sm"
+        @click="addProperty"
+      >
+        {{ t('workflow.blocks.sort-data.addProperty') }}
+      </ui-button>
+    </template>
+    <div class="mt-6">
+      <insert-workflow-data :data="data" variables @update="updateData" />
+    </div>
+  </div>
+</template>
+<script setup>
+import { inject, ref, watch } from 'vue';
+import { useI18n } from 'vue-i18n';
+import cloneDeep from 'lodash.clonedeep';
+import InsertWorkflowData from './InsertWorkflowData.vue';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+const dataSources = [
+  { id: 'table', name: t('workflow.table.title') },
+  { id: 'variable', name: t('workflow.variables.title') },
+];
+
+const workflow = inject('workflow');
+const columns = workflow.columns.value.map(({ name }) => name);
+
+const properties = ref(cloneDeep(props.data.itemProperties));
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+function addProperty() {
+  properties.value.push({
+    name: '',
+    order: 'asc',
+  });
+}
+
+watch(
+  properties,
+  (value) => {
+    updateData({ itemProperties: value });
+  },
+  { deep: true }
+);
+</script>
+<style>
+.sort-property .ui-popover__trigger {
+  width: 100%;
+}
+</style>

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

@@ -116,6 +116,12 @@
         "addSource": "Add source",
         "addSource": "Add source",
         "addDestination": "Add destination"
         "addDestination": "Add destination"
       },
       },
+      "sort-data": {
+        "name": "Sort data",
+        "description": "Sort the items of data",
+        "property": "Sort by the item's property",
+        "addProperty": "Add property"
+      },
       "increase-variable": {
       "increase-variable": {
         "name": "Increase variable",
         "name": "Increase variable",
         "description": "Increase the value of a variable by specific amount",
         "description": "Increase the value of a variable by specific amount",

+ 24 - 1
src/utils/shared.js

@@ -1122,7 +1122,6 @@ export const tasks = {
     data: {
     data: {
       disableBlock: false,
       disableBlock: false,
       description: '',
       description: '',
-      expression: '',
       dataSource: 'table',
       dataSource: 'table',
       sources: [],
       sources: [],
       varSourceName: '',
       varSourceName: '',
@@ -1132,6 +1131,30 @@ export const tasks = {
       variableName: '',
       variableName: '',
     },
     },
   },
   },
+  'sort-data': {
+    name: 'Sort data',
+    description: 'Sort the items of data',
+    icon: 'riSortAsc',
+    editComponent: 'EditSortData',
+    component: 'BlockBasic',
+    category: 'data',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: true,
+    maxConnection: 1,
+    data: {
+      disableBlock: false,
+      description: '',
+      sortByProperty: false,
+      itemProperties: [],
+      dataSource: 'table',
+      varSourceName: '',
+      dataColumn: '',
+      saveData: false,
+      assignVariable: false,
+      variableName: '',
+    },
+  },
 };
 };
 
 
 export const categories = {
 export const categories = {