瀏覽代碼

feat: sort workflows by most used

Ahmad Kholid 2 年之前
父節點
當前提交
93abb45c4b

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

@@ -60,7 +60,8 @@
   "sort": {
     "sortBy": "Sort by",
     "name": "Name",
-    "createdAt": "Created date"
+    "createdAt": "Created date",
+    "mostUsed": "Most used"
   },
   "logStatus": {
     "stopped": "stopped",

+ 23 - 11
src/manifest.chrome.json

@@ -1,12 +1,13 @@
 {
-  "manifest_version": 2,
+  "manifest_version": 3,
   "name": "Automa",
-  "browser_action": {
+  "action": {
     "default_popup": "popup.html",
     "default_icon": "icon-128.png"
   },
   "background": {
-    "scripts": ["background.bundle.js"]
+    "service_worker": "background.bundle.js",
+    "type": "module"
   },
   "icons": {
     "128": "icon-128.png"
@@ -51,18 +52,29 @@
     "alarms",
     "storage",
     "debugger",
-    "<all_urls>",
+    "scripting",
     "webNavigation",
     "unlimitedStorage"
   ],
+  "host_permissions": [
+    "<all_urls>"
+  ],
   "web_accessible_resources": [
-    "/elementSelector.css",
-    "/Inter-roman-latin.var.woff2",
-    "/icon-128.png",
-    "/locales/*",
-    "elementSelector.bundle.js"
+    {
+      "resources": [
+        "/elementSelector.css",
+        "/Inter-roman-latin.var.woff2",
+        "/icon-128.png",
+        "/locales/*",
+        "elementSelector.bundle.js"
+      ],
+      "matches": ["<all_urls>"]
+    }
   ],
   "sandbox": {
-    "pages": ["/sandbox.html", "uiSandbox.html"]
+    "pages": ["/sandbox.html"]
+  },
+  "content_security_policy": {
+    "sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"
   }
-}
+}

+ 4 - 4
src/newtab/pages/Workflows.vue

@@ -1,18 +1,18 @@
 <template>
   <div class="flex flex-col">
-    <div class="flex items-center border-b h-12">
+    <div class="flex items-center border-b h-10">
       <draggable
         v-model="state.tabs"
         item-key="id"
-        class="scroll overflow-auto text-gray-600 h-full dark:text-gray-300 scroll-xs flex items-center"
+        class="scroll overflow-auto text-gray-600 h-full dark:text-gray-300 scroll-xs flex items-center text-sm"
       >
         <template #item="{ element: tab, index }">
           <button
             :value="tab.id"
             :class="[
               state.activeTab === tab.id
-                ? 'border-accent'
-                : 'border-transparent',
+                ? 'border-accent dark:border-accent'
+                : 'border-transparent dark:border-transparent',
               {
                 'bg-box-transparent text-black dark:text-gray-100':
                   state.activeTab === tab.id,

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

@@ -155,7 +155,7 @@
             />
           </ui-tab-panel>
         </template>
-        <ui-tab-panel cache value="editor" class="w-full">
+        <ui-tab-panel cache value="editor" class="w-full" @keydown="onKeydown">
           <workflow-editor
             v-if="state.workflowConverted"
             :id="route.params.id"
@@ -1570,6 +1570,18 @@ function checkWorkflowUpdate() {
       console.error(error);
     });
 }
+/* eslint-disable consistent-return */
+function onBeforeLeave() {
+  updateHostedWorkflow();
+
+  const dataNotChanged = !state.dataChanged || !haveEditAccess.value;
+  const isExternalPkg = isPackage && workflow.value.isExternal;
+  if (dataNotChanged || isExternalPkg) return;
+
+  const confirm = window.confirm(t('message.notSaved'));
+
+  if (!confirm) return false;
+}
 
 useHead({
   title: () =>
@@ -1605,18 +1617,7 @@ watch(
   }
 );
 
-/* eslint-disable consistent-return */
-onBeforeRouteLeave(() => {
-  updateHostedWorkflow();
-
-  const dataNotChanged = !state.dataChanged || !haveEditAccess.value;
-  const isExternalPkg = isPackage && workflow.value.isExternal;
-  if (dataNotChanged || isExternalPkg) return;
-
-  const confirm = window.confirm(t('message.notSaved'));
-
-  if (!confirm) return false;
-});
+onBeforeRouteLeave(onBeforeLeave);
 onMounted(() => {
   if (!workflow.value) {
     router.replace(isPackage ? '/packages' : '/');
@@ -1649,17 +1650,14 @@ onMounted(() => {
   }
 
   initAutocomplete();
-
-  window.addEventListener('keydown', onKeydown);
 });
 onBeforeUnmount(() => {
   const editorContainer = document.querySelector(
     '.vue-flow__viewport.vue-flow__container'
   );
-  if (editorContainer)
+  if (editorContainer) {
     editorContainer.removeEventListener('click', onClickEditor);
-
-  window.removeEventListener('keydown', onKeydown);
+  }
 
   if (isPackage && workflow.value.isExternal) return;
   updateHostedWorkflow();

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

@@ -386,7 +386,7 @@ const workflowStore = useWorkflowStore();
 const teamWorkflowStore = useTeamWorkflowStore();
 const hostedWorkflowStore = useHostedWorkflowStore();
 
-const sorts = ['name', 'createdAt'];
+const sorts = ['name', 'createdAt', 'mostUsed'];
 const { teamId, active } = router.currentRoute.value.query;
 const savedSorts = JSON.parse(localStorage.getItem('workflow-sorts') || '{}');
 const validTeamId = userStore.user?.teams?.some(

+ 12 - 2
src/utils/helper.js

@@ -281,12 +281,22 @@ export async function clearCache(workflow) {
 }
 
 export function arraySorter({ data, key, order = 'asc' }) {
+  let runCounts = {};
   const copyData = data.slice();
 
+  if (key === 'mostUsed') {
+    runCounts = parseJSON(localStorage.getItem('runCounts'), {}) || {};
+  }
+
   return copyData.sort((a, b) => {
     let comparison = 0;
-    const itemA = a[key] || a;
-    const itemB = b[key] || b;
+    let itemA = a[key] || a;
+    let itemB = b[key] || b;
+
+    if (key === 'mostUsed') {
+      itemA = runCounts[a.id] || 0;
+      itemB = runCounts[b.id] || 0;
+    }
 
     if (itemA > itemB) {
       comparison = 1;

+ 7 - 0
src/workflowEngine/index.js

@@ -36,6 +36,13 @@ export function stopWorkflowExec(executionId) {
 }
 
 export function startWorkflowExec(workflowData, options, isPopup = true) {
+  if (localStorage) {
+    const runCounts = parseJSON(localStorage.getItem('runCounts'), {}) || {};
+    runCounts[workflowData.id] = (runCounts[workflowData.id] || 0) + 1;
+
+    localStorage.setItem('runCounts', JSON.stringify(runCounts));
+  }
+
   if (workflowData.isProtected) {
     const flow = parseJSON(workflowData.drawflow, null);