Procházet zdrojové kódy

feat: add workflow description

Ahmad Kholid před 3 roky
rodič
revize
f95b902d7f

+ 1 - 0
package.json

@@ -26,6 +26,7 @@
     "@webcomponents/custom-elements": "^1.5.0",
     "@webcomponents/custom-elements": "^1.5.0",
     "dayjs": "^1.10.7",
     "dayjs": "^1.10.7",
     "drawflow": "^0.0.51",
     "drawflow": "^0.0.51",
+    "idb": "^7.0.0",
     "mousetrap": "^1.6.5",
     "mousetrap": "^1.6.5",
     "nanoid": "3.1.28",
     "nanoid": "3.1.28",
     "object-path-immutable": "^4.1.2",
     "object-path-immutable": "^4.1.2",

+ 6 - 1
src/components/newtab/shared/SharedCard.vue

@@ -44,12 +44,17 @@
       <p class="line-clamp font-semibold leading-tight">
       <p class="line-clamp font-semibold leading-tight">
         {{ data.name }}
         {{ data.name }}
       </p>
       </p>
+      <p
+        v-show="data.description"
+        class="text-gray-600 dark:text-gray-200 line-clamp leading-tight mb-1"
+      >
+        {{ data.description }}
+      </p>
       <p class="text-gray-600 dark:text-gray-200">{{ formatDate() }}</p>
       <p class="text-gray-600 dark:text-gray-200">{{ formatDate() }}</p>
     </div>
     </div>
   </ui-card>
   </ui-card>
 </template>
 </template>
 <script setup>
 <script setup>
-import { computed } from 'vue';
 import dayjs from '@/lib/dayjs';
 import dayjs from '@/lib/dayjs';
 
 
 const props = defineProps({
 const props = defineProps({

+ 0 - 5
src/components/newtab/workflow/WorkflowActions.vue

@@ -142,10 +142,5 @@ const moreActions = [
     name: t('common.delete'),
     name: t('common.delete'),
     icon: 'riDeleteBin7Line',
     icon: 'riDeleteBin7Line',
   },
   },
-  {
-    id: 'setIcon',
-    name: 'Set icon',
-    icon: 'riImageLine',
-  },
 ];
 ];
 </script>
 </script>

+ 9 - 4
src/components/newtab/workflow/WorkflowDetailsCard.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <div class="px-4 flex items-center mb-2 mt-1">
+  <div class="px-4 flex items-start mb-2 mt-1">
     <ui-popover class="mr-2 h-8">
     <ui-popover class="mr-2 h-8">
       <template #trigger>
       <template #trigger>
         <span
         <span
@@ -42,9 +42,14 @@
         />
         />
       </div>
       </div>
     </ui-popover>
     </ui-popover>
-    <p class="font-semibold text-overflow inline-block text-lg flex-1 mr-4">
-      {{ workflow.name }}
-    </p>
+    <div class="flex-1 overflow-hidden">
+      <p class="font-semibold mt-1 text-overflow text-lg leading-tight">
+        {{ workflow.name }}
+      </p>
+      <p class="line-clamp leading-tight">
+        {{ workflow.description }}
+      </p>
+    </div>
   </div>
   </div>
   <ui-input
   <ui-input
     v-model="query"
     v-model="query"

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

@@ -30,7 +30,8 @@
     "disable": "Disable",
     "disable": "Disable",
     "disabled": "Disabled",
     "disabled": "Disabled",
     "enable": "Enable",
     "enable": "Enable",
-    "fallback": "Fallback"
+    "fallback": "Fallback",
+    "update": "Update"
   },
   },
   "message": {
   "message": {
     "noBlock": "No block",
     "noBlock": "No block",

+ 1 - 1
src/models/workflow.js

@@ -15,10 +15,10 @@ class Workflow extends Model {
       id: this.uid(() => nanoid()),
       id: this.uid(() => nanoid()),
       name: this.string(''),
       name: this.string(''),
       icon: this.string('riGlobalLine'),
       icon: this.string('riGlobalLine'),
-      isIconFromURL: this.boolean(false),
       data: this.attr(null),
       data: this.attr(null),
       drawflow: this.string(''),
       drawflow: this.string(''),
       dataColumns: this.attr([]),
       dataColumns: this.attr([]),
+      description: this.string(''),
       globalData: this.string('[{ "key": "value" }]'),
       globalData: this.string('[{ "key": "value" }]'),
       lastRunAt: this.number(),
       lastRunAt: this.number(),
       createdAt: this.number(),
       createdAt: this.number(),

+ 79 - 52
src/newtab/pages/Workflows.vue

@@ -45,7 +45,7 @@
         </ui-button>
         </ui-button>
       </div>
       </div>
     </div>
     </div>
-    <div v-else class="grid gap-4 grid-cols-5 2xl:grid-cols-6">
+    <div v-else class="grid gap-4 grid-cols-4 2xl:grid-cols-5">
       <shared-card
       <shared-card
         v-for="workflow in workflows"
         v-for="workflow in workflows"
         :key="workflow.id"
         :key="workflow.id"
@@ -91,9 +91,11 @@
                   "
                   "
                 >
                 >
                   <v-remixicon name="riToggleLine" class="mr-2 -ml-1" />
                   <v-remixicon name="riToggleLine" class="mr-2 -ml-1" />
-                  <span class="capitalize">{{
-                    t(`common.${workflow.isDisabled ? 'enable' : 'disable'}`)
-                  }}</span>
+                  <span class="capitalize">
+                    {{
+                      t(`common.${workflow.isDisabled ? 'enable' : 'disable'}`)
+                    }}
+                  </span>
                 </ui-list-item>
                 </ui-list-item>
                 <ui-list-item
                 <ui-list-item
                   v-for="item in menu"
                   v-for="item in menu"
@@ -111,6 +113,37 @@
         </template>
         </template>
       </shared-card>
       </shared-card>
     </div>
     </div>
+    <ui-modal v-model="workflowModal.show" title="Workflow">
+      <ui-input
+        v-model="workflowModal.name"
+        :placeholder="t('common.name')"
+        autofocus
+        class="w-full mb-4"
+        @keyup.enter="handleWorkflowModal"
+      />
+      <ui-textarea
+        v-model="workflowModal.description"
+        :placeholder="t('common.description')"
+        height="165px"
+        class="w-full dark:text-gray-200 text-right"
+        max="300"
+      />
+      <p class="mb-6 text-right text-gray-600 dark:text-gray-200">
+        {{ workflowModal.description.length }}/300
+      </p>
+      <div class="space-x-2 flex">
+        <ui-button class="w-full" @click="workflowModal.show = false">
+          {{ t('common.cancel') }}
+        </ui-button>
+        <ui-button variant="accent" class="w-full" @click="handleWorkflowModal">
+          {{
+            workflowModal.type === 'update'
+              ? t('common.update')
+              : t('common.add')
+          }}
+        </ui-button>
+      </div>
+    </ui-modal>
   </div>
   </div>
 </template>
 </template>
 <script setup>
 <script setup>
@@ -121,7 +154,6 @@ import { sendMessage } from '@/utils/message';
 import { exportWorkflow, importWorkflow } from '@/utils/workflow-data';
 import { exportWorkflow, importWorkflow } from '@/utils/workflow-data';
 import SharedCard from '@/components/newtab/shared/SharedCard.vue';
 import SharedCard from '@/components/newtab/shared/SharedCard.vue';
 import Workflow from '@/models/workflow';
 import Workflow from '@/models/workflow';
-import { isWhiteSpace } from '@/utils/helper';
 
 
 const dialog = useDialog();
 const dialog = useDialog();
 const { t } = useI18n();
 const { t } = useI18n();
@@ -139,6 +171,11 @@ const state = shallowReactive({
   sortBy: savedSorts.sortBy || 'createdAt',
   sortBy: savedSorts.sortBy || 'createdAt',
   sortOrder: savedSorts.sortOrder || 'desc',
   sortOrder: savedSorts.sortOrder || 'desc',
 });
 });
+const workflowModal = shallowReactive({
+  type: 'update',
+  name: '',
+  description: '',
+});
 
 
 const workflows = computed(() =>
 const workflows = computed(() =>
   Workflow.query()
   Workflow.query()
@@ -159,18 +196,11 @@ function updateWorkflow(id, data) {
   });
   });
 }
 }
 function newWorkflow() {
 function newWorkflow() {
-  dialog.prompt({
-    title: t('workflow.new'),
-    placeholder: t('common.name'),
-    okText: t('workflow.add'),
-    onConfirm: (name) => {
-      Workflow.insert({
-        data: {
-          name: name || 'Unnamed',
-          createdAt: Date.now(),
-        },
-      });
-    },
+  Object.assign(workflowModal, {
+    name: '',
+    show: true,
+    type: 'add',
+    description: '',
   });
   });
 }
 }
 function deleteWorkflow({ name, id }) {
 function deleteWorkflow({ name, id }) {
@@ -183,52 +213,49 @@ function deleteWorkflow({ name, id }) {
     },
     },
   });
   });
 }
 }
-function renameWorkflow({ id, name }) {
-  dialog.prompt({
-    title: t('workflow.rename'),
-    placeholder: t('common.name'),
-    okText: t('common.rename'),
-    inputValue: name,
-    onConfirm: (newName) => {
-      Workflow.update({
-        where: id,
+function renameWorkflow({ id, name, description }) {
+  Object.assign(workflowModal, {
+    id,
+    name,
+    description,
+    show: true,
+    type: 'update',
+  });
+}
+async function handleWorkflowModal() {
+  try {
+    if (workflowModal.type === 'add') {
+      await Workflow.insert({
         data: {
         data: {
-          name: newName,
+          createdAt: Date.now(),
+          name: workflowModal.name || 'Unnamed',
+          description: workflowModal.description,
         },
         },
       });
       });
-      console.log(Workflow.data);
-    },
-  });
-}
-
-function setIconWorkflow({ id }) {
-  dialog.prompt({
-    title: 'Set icon workflow',
-    placeholder: 'URL of the new icon',
-    okText: 'Set Icon',
-    inputValue: '',
-    onConfirm: (iconUrl) => {
-      let isIconFromURL = true;
-      if (!iconUrl || isWhiteSpace(iconUrl)) {
-        iconUrl = String('riGlobalLine');
-        isIconFromURL = false;
-      }
-
-      Workflow.update({
-        where: id,
+    } else {
+      await Workflow.update({
+        where: workflowModal.id,
         data: {
         data: {
-          icon: String(iconUrl),
-          isIconFromURL,
+          name: workflowModal.name,
+          description: workflowModal.description,
         },
         },
       });
       });
-    },
-  });
+    }
+
+    Object.assign(workflowModal, {
+      name: '',
+      show: false,
+      description: '',
+    });
+  } catch (error) {
+    console.error(error);
+  }
 }
 }
+
 const menuHandlers = {
 const menuHandlers = {
   export: exportWorkflow,
   export: exportWorkflow,
   rename: renameWorkflow,
   rename: renameWorkflow,
   delete: deleteWorkflow,
   delete: deleteWorkflow,
-  setIcon: setIconWorkflow,
 };
 };
 
 
 watch(
 watch(

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

@@ -114,6 +114,32 @@
       @close="state.showModal = false"
       @close="state.showModal = false"
     />
     />
   </ui-modal>
   </ui-modal>
+  <ui-modal v-model="renameModal.show" title="Workflow">
+    <ui-input
+      v-model="renameModal.name"
+      :placeholder="t('common.name')"
+      class="w-full mb-4"
+      @keyup.enter="updateNameAndDesc"
+    />
+    <ui-textarea
+      v-model="renameModal.description"
+      :placeholder="t('common.description')"
+      height="165px"
+      class="w-full dark:text-gray-200 text-right"
+      max="300"
+    />
+    <p class="mb-6 text-right text-gray-600 dark:text-gray-200">
+      {{ renameModal.description.length }}/300
+    </p>
+    <div class="space-x-2 flex">
+      <ui-button class="w-full" @click="renameModal.show = false">
+        {{ t('common.cancel') }}
+      </ui-button>
+      <ui-button variant="accent" class="w-full" @click="updateNameAndDesc">
+        {{ t('common.update') }}
+      </ui-button>
+    </div>
+  </ui-modal>
 </template>
 </template>
 <script setup>
 <script setup>
 /* eslint-disable consistent-return */
 /* eslint-disable consistent-return */
@@ -180,6 +206,11 @@ const state = reactive({
   isEditBlock: false,
   isEditBlock: false,
   isDataChanged: false,
   isDataChanged: false,
 });
 });
+const renameModal = reactive({
+  show: false,
+  name: '',
+  description: '',
+});
 
 
 const workflowState = computed(() =>
 const workflowState = computed(() =>
   store.getters.getWorkflowState(workflowId)
   store.getters.getWorkflowState(workflowId)
@@ -226,6 +257,18 @@ function updateWorkflow(data) {
     data,
     data,
   });
   });
 }
 }
+function updateNameAndDesc() {
+  updateWorkflow({
+    name: renameModal.name,
+    description: renameModal.description.slice(0, 300),
+  }).then(() => {
+    Object.assign(renameModal, {
+      show: false,
+      name: '',
+      description: '',
+    });
+  });
+}
 function saveWorkflow() {
 function saveWorkflow() {
   const data = editor.value.export();
   const data = editor.value.export();
 
 
@@ -277,19 +320,10 @@ function deleteWorkflow() {
   });
   });
 }
 }
 function renameWorkflow() {
 function renameWorkflow() {
-  dialog.prompt({
-    title: t('workflow.rename'),
-    placeholder: t('common.name'),
-    okText: t('common.rename'),
-    inputValue: workflow.value.name,
-    onConfirm: (newName) => {
-      Workflow.update({
-        where: route.params.id,
-        data: {
-          name: newName,
-        },
-      });
-    },
+  Object.assign(renameModal, {
+    show: true,
+    name: workflow.value.name,
+    description: workflow.value.description,
   });
   });
 }
 }
 
 

+ 1 - 5
src/utils/helper.js

@@ -1,7 +1,3 @@
-export function isWhitespace(str) {
-  return !/\S/g.test(str);
-}
-
 export function parseJSON(data, def) {
 export function parseJSON(data, def) {
   try {
   try {
     const result = JSON.parse(data);
     const result = JSON.parse(data);
@@ -77,7 +73,7 @@ export function objectHasKey(obj, key) {
   return Object.prototype.hasOwnProperty.call(obj, key);
   return Object.prototype.hasOwnProperty.call(obj, key);
 }
 }
 
 
-export function isWhiteSpace(str) {
+export function isWhitespace(str) {
   return !/\S/.test(str);
   return !/\S/.test(str);
 }
 }
 
 

+ 1 - 0
src/utils/workflow-data.js

@@ -27,6 +27,7 @@ export function exportWorkflow(workflow) {
     'name',
     'name',
     'settings',
     'settings',
     'globalData',
     'globalData',
+    'description',
   ];
   ];
   const content = {};
   const content = {};
 
 

+ 5 - 0
yarn.lock

@@ -3736,6 +3736,11 @@ icss-utils@^5.0.0, icss-utils@^5.1.0:
   resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
   resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
   integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
   integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
 
 
+idb@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/idb/-/idb-7.0.0.tgz#f349b418c128f625961147a7d6b0e4b526fd34ed"
+  integrity sha512-jSx0WOY9Nj+QzP6wX5e7g64jqh8ExtDs/IAuOrOEZCD/h6+0HqyrKsDMfdJc0hqhSvh0LsrwqrkDn+EtjjzSRA==
+
 ieee754@^1.1.13:
 ieee754@^1.1.13:
   version "1.2.1"
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"