Ahmad Kholid 3 years ago
parent
commit
88526be675

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "automa",
-  "version": "1.11.0",
+  "version": "1.11.1",
   "description": "An extension for automating your browser by connecting blocks",
   "license": "MIT",
   "repository": {

+ 2 - 4
src/background/index.js

@@ -151,7 +151,7 @@ async function checkVisitWebTriggers(tabId, tabUrl) {
     state.tabIds.includes(tabId)
   );
   const visitWebTriggers = await storage.get('visitWebTriggers');
-  const triggeredWorkflow = visitWebTriggers.find(({ url, isRegex, id }) => {
+  const triggeredWorkflow = visitWebTriggers?.find(({ url, isRegex, id }) => {
     if (url.trim() === '') return false;
 
     const matchUrl = tabUrl.match(isRegex ? new RegExp(url, 'g') : url);
@@ -421,8 +421,6 @@ message.on('collection:execute', (collection) => {
 message.on('workflow:execute', (workflowData) => {
   workflow.execute(workflowData, workflowData?.options || {});
 });
-message.on('workflow:stop', async (id) => {
-  await workflow.states.stop(id);
-});
+message.on('workflow:stop', (id) => workflow.states.stop(id));
 
 browser.runtime.onMessage.addListener(message.listener());

+ 0 - 4
src/background/workflowEngine/blocksHandler/handlerActiveTab.js

@@ -1,6 +1,5 @@
 import browser from 'webextension-polyfill';
 import { getBlockConnection } from '../helper';
-import executeContentScript from '../executeContentScript';
 
 async function activeTab(block) {
   const nextBlockId = getBlockConnection(block);
@@ -29,11 +28,8 @@ async function activeTab(block) {
       throw error;
     }
 
-    const frames = await executeContentScript(tab.id);
-
     this.activeTab = {
       ...this.activeTab,
-      frames,
       frameId: 0,
       id: tab.id,
       url: tab.url,

+ 1 - 3
src/background/workflowEngine/blocksHandler/handlerSwitchTo.js

@@ -1,6 +1,5 @@
 import { objectHasKey } from '@/utils/helper';
-import { getBlockConnection } from '../helper';
-import executeContentScript, { getFrames } from '../executeContentScript';
+import { getBlockConnection, getFrames } from '../helper';
 
 async function switchTo(block) {
   const nextBlockId = getBlockConnection(block);
@@ -35,7 +34,6 @@ async function switchTo(block) {
     if (objectHasKey(frames, url)) {
       this.activeTab.frameId = frames[url];
 
-      await executeContentScript(this.activeTab.id, this.activeTab.frameId);
       await new Promise((resolve) => setTimeout(resolve, 1000));
 
       return {

+ 4 - 2
src/background/workflowEngine/blocksHandler/handlerTakeScreenshot.js

@@ -87,8 +87,10 @@ async function takeScreenshot({ data, outputs, name }) {
         ? this._sendMessageToTab({
             name,
             options,
-            type: data.type,
-            selector: data.selector,
+            data: {
+              type: data.type,
+              selector: data.selector,
+            },
             tabId: this.activeTab.id,
           })
         : captureTab());

+ 8 - 15
src/background/workflowEngine/blocksHandler/handlerTrigger.js

@@ -1,21 +1,14 @@
 import { getBlockConnection } from '../helper';
-import executeContentScript from '../executeContentScript';
 
 async function trigger(block) {
-  const nextBlockId = getBlockConnection(block);
-
-  try {
-    if (block.data.type === 'visit-web' && this.activeTab.id) {
-      await executeContentScript(this.activeTab.id);
-    }
-
-    return { nextBlockId, data: '' };
-  } catch (error) {
-    const errorInstance = new Error(error);
-    errorInstance.nextBlockId = nextBlockId;
-
-    throw errorInstance;
-  }
+  return new Promise((resolve) => {
+    const nextBlockId = getBlockConnection(block);
+
+    resolve({
+      data: '',
+      nextBlockId,
+    });
+  });
 }
 
 export default trigger;

+ 0 - 51
src/background/workflowEngine/executeContentScript.js

@@ -1,51 +0,0 @@
-import browser from 'webextension-polyfill';
-
-export async function getFrames(tabId) {
-  try {
-    const frames = await browser.webNavigation.getAllFrames({ tabId });
-    const framesObj = frames.reduce((acc, { frameId, url }) => {
-      const key = url === 'about:blank' ? '' : url;
-
-      acc[key] = frameId;
-
-      return acc;
-    }, {});
-
-    return framesObj;
-  } catch (error) {
-    console.error(error);
-    return {};
-  }
-}
-
-async function contentScriptExist(tabId, frameId = 0) {
-  try {
-    await browser.tabs.sendMessage(
-      tabId,
-      { type: 'content-script-exists' },
-      { frameId }
-    );
-
-    return true;
-  } catch (error) {
-    return false;
-  }
-}
-
-export default async function (tabId, frameId = 0) {
-  try {
-    const currentFrameId = typeof frameId !== 'number' ? 0 : frameId;
-    const isScriptExists = await contentScriptExist(tabId, currentFrameId);
-
-    if (!isScriptExists) {
-      await browser.tabs.executeScript(tabId, {
-        allFrames: true,
-        runAt: 'document_end',
-        file: './contentScript.bundle.js',
-      });
-    }
-  } catch (error) {
-    console.error(error);
-    throw error;
-  }
-}

+ 20 - 7
src/background/workflowEngine/helper.js

@@ -1,5 +1,23 @@
 import browser from 'webextension-polyfill';
 
+export async function getFrames(tabId) {
+  try {
+    const frames = await browser.webNavigation.getAllFrames({ tabId });
+    const framesObj = frames.reduce((acc, { frameId, url }) => {
+      const key = url === 'about:blank' ? '' : url;
+
+      acc[key] = frameId;
+
+      return acc;
+    }, {});
+
+    return framesObj;
+  } catch (error) {
+    console.error(error);
+    return {};
+  }
+}
+
 export function sendDebugCommand(tabId, method, params = {}) {
   return new Promise((resolve) => {
     chrome.debugger.sendCommand({ tabId }, method, params, resolve);
@@ -19,20 +37,17 @@ export function attachDebugger(tabId, prevTab) {
 
 export function waitTabLoaded(tabId, ms = 10000) {
   return new Promise((resolve, reject) => {
-    const timeout = null;
-    let isResolved = false;
+    let timeout = null;
     const onErrorOccurred = (details) => {
       if (details.tabId !== tabId || details.error.includes('ERR_ABORTED'))
         return;
 
-      isResolved = true;
       browser.webNavigation.onErrorOccurred.removeListener(onErrorOccurred);
       reject(new Error(details.error));
     };
 
     if (ms > 0) {
-      setTimeout(() => {
-        isResolved = true;
+      timeout = setTimeout(() => {
         browser.webNavigation.onErrorOccurred.removeListener(onErrorOccurred);
         reject(new Error('Timeout'));
       }, ms);
@@ -41,8 +56,6 @@ export function waitTabLoaded(tabId, ms = 10000) {
     browser.webNavigation.onErrorOccurred.addListener(onErrorOccurred);
 
     const activeTabStatus = () => {
-      if (isResolved) return;
-
       browser.tabs.get(tabId).then((tab) => {
         if (!tab) {
           reject(new Error('no-tab'));

+ 1 - 5
src/background/workflowEngine/worker.js

@@ -5,7 +5,6 @@ import { toCamelCase, sleep, objectHasKey, isObject } from '@/utils/helper';
 import { tasks } from '@/utils/shared';
 import referenceData from '@/utils/referenceData';
 import { convertData, waitTabLoaded, getBlockConnection } from './helper';
-import executeContentScript from './executeContentScript';
 
 class Worker {
   constructor(engine) {
@@ -315,10 +314,6 @@ class Worker {
         this.activeTab.id,
         this.settings?.tabLoadTimeout ?? 30000
       );
-      await executeContentScript(
-        this.activeTab.id,
-        this.activeTab.frameId || 0
-      );
 
       const { executedBlockOnWeb, debugMode } = this.settings;
       const messagePayload = {
@@ -338,6 +333,7 @@ class Worker {
 
       return data;
     } catch (error) {
+      console.error(error);
       if (error.message?.startsWith('Could not establish connection')) {
         error.message = 'Could not establish connection to the active tab';
       } else if (error.message?.startsWith('No tab')) {

+ 12 - 3
src/components/newtab/workflow/WorkflowBuilder.vue

@@ -207,7 +207,9 @@ export default {
         active: isOutputEl(target),
       });
 
-      const nodeContent = target.closest('.drawflow_content_node');
+      const nodeContent = target.closest(
+        '.drawflow-node:not(.blocks-group) .drawflow_content_node'
+      );
       toggleHoverClass({
         classes: 'ring-4',
         target: nodeContent,
@@ -220,20 +222,27 @@ export default {
 
       if (!block) return;
 
+      const highlightedEls = document.querySelectorAll(
+        '.drawflow_content_node.ring-4'
+      );
+      highlightedEls.forEach((el) => {
+        el.classList.remove('ring-4');
+      });
+
       const isTriggerExists =
         block.id === 'trigger' &&
         editor.value.getNodesFromName('trigger').length !== 0;
       if (isTriggerExists) return;
 
       if (target.closest('.drawflow_content_node')) {
-        prevSelectedEl.nodeContent?.classList.remove('ring-4');
-
         const targetNodeId = target
           .closest('.drawflow-node')
           .id.replace(/node-/, '');
         const targetNode = editor.value.getNodeFromId(targetNodeId);
         editor.value.removeNodeId(`node-${targetNodeId}`);
 
+        if (targetNode.name === 'blocks-group') return;
+
         let targetBlock = block;
         if (block.fromBlockBasic) {
           targetBlock = { ...tasks[block.id], id: block.id };

+ 2 - 6
src/content/blocksHandler/handlerJavascriptCode.js

@@ -56,8 +56,8 @@ function javascriptCode(block) {
     const promisePreloadScripts =
       block.data?.preloadScripts?.map(async (item) => {
         try {
-          const { protocol, pathname } = new URL(item.src);
-          const isValidUrl = /https?/.test(protocol) && /\.js$/.test(pathname);
+          const { protocol } = new URL(item.src);
+          const isValidUrl = /https?/.test(protocol);
 
           if (!isValidUrl) return null;
 
@@ -107,12 +107,8 @@ function javascriptCode(block) {
 
       if (!block.data.everyNewTab) {
         let timeout;
-        let isResolved = false;
 
         const cleanUp = (detail = {}) => {
-          if (isResolved) return;
-          isResolved = true;
-
           script.remove();
           preloadScripts.forEach((item) => {
             if (item.removeAfterExec) item.script.remove();

+ 1 - 1
src/content/blocksHandler/handlerTakeScreenshot.js

@@ -90,7 +90,7 @@ async function captureElementScreenshot({ selector, tabId, options }) {
   return canvasToBase64(canvas, options);
 }
 
-export default async function ({ tabId, options, type, selector }) {
+export default async function ({ tabId, options, data: { type, selector } }) {
   if (type === 'element') {
     const imageUrl = await captureElementScreenshot({
       tabId,

+ 4 - 1
src/content/index.js

@@ -3,6 +3,7 @@ import { toCamelCase } from '@/utils/helper';
 import blocksHandler from './blocksHandler';
 import showExecutedBlock from './showExecutedBlock';
 import handleTestCondition from './handleTestCondition';
+import shortcutListener from './services/shortcutListener';
 
 const isMainFrame = window.self === window.top;
 
@@ -36,7 +37,7 @@ function messageToFrame(frameElement, blockData) {
 async function executeBlock(data) {
   const removeExecutedBlock = showExecutedBlock(data, data.executedBlockOnWeb);
 
-  if (data.data.selector?.includes('|>') && isMainFrame) {
+  if (data.data?.selector?.includes('|>') && isMainFrame) {
     const [frameSelector, selector] = data.data.selector.split(/\|>(.+)/);
     const frameElement = document.querySelector(frameSelector);
     const frameError = (message) => {
@@ -131,6 +132,8 @@ function messageListener({ data, source }) {
   window.isAutomaInjected = true;
   window.addEventListener('message', messageListener);
 
+  if (isMainFrame) shortcutListener();
+
   browser.runtime.onMessage.addListener((data) => {
     return new Promise((resolve, reject) => {
       if (data.isBlock) {

+ 2 - 2
src/content/services/shortcutListener.js

@@ -56,7 +56,7 @@ function workflowShortcutsListener(findWorkflow, shortcutsObj) {
   });
 }
 
-(async () => {
+export default async function () {
   try {
     const { shortcuts, workflows, workflowHosts } =
       await browser.storage.local.get([
@@ -83,4 +83,4 @@ function workflowShortcutsListener(findWorkflow, shortcutsObj) {
   } catch (error) {
     console.error(error);
   }
-})();
+}

+ 1 - 4
src/content/utils.js

@@ -99,13 +99,11 @@ function automaRefData(keyword, path = '') {
 function messageTopFrame(windowCtx) {
   return new Promise((resolve) => {
     let timeout = null;
-    let isResolved = false;
 
     const messageListener = ({ data }) => {
-      if (data.type !== 'automa:the-frame-rect' || isResolved) return;
+      if (data.type !== 'automa:the-frame-rect') return;
 
       clearTimeout(timeout);
-      isResolved = true;
       windowCtx.removeEventListener('message', messageListener);
       resolve(data.frameRect);
     };
@@ -113,7 +111,6 @@ function messageTopFrame(windowCtx) {
     timeout = setTimeout(() => {
       if (isResolved) return;
 
-      isResolved = true;
       windowCtx.removeEventListener('message', messageListener);
       resolve(null);
     }, 5000);

+ 2 - 3
src/manifest.chrome.json

@@ -29,10 +29,9 @@
         "<all_urls>"
       ],
       "js": [
-        "shortcutListener.bundle.js"
+        "contentScript.bundle.js"
       ],
-      "run_at": "document_end",
-      "all_frames": false
+      "all_frames": true
     },
     {
       "matches": [

+ 2 - 3
src/manifest.firefox.json

@@ -34,10 +34,9 @@
         "<all_urls>"
       ],
       "js": [
-        "shortcutListener.bundle.js"
+        "contentScript.bundle.js"
       ],
-      "run_at": "document_end",
-      "all_frames": false
+      "all_frames": true
     },
     {
       "matches": [

+ 9 - 3
src/newtab/App.vue

@@ -23,7 +23,7 @@
       </template>
     </ui-dialog>
     <div
-      v-if="isUpdated"
+      v-if="false"
       class="p-4 shadow-2xl z-50 fixed bottom-8 left-1/2 -translate-x-1/2 rounded-lg bg-accent text-white dark:text-gray-900 flex items-center"
     >
       <v-remixicon name="riInformationLine" class="mr-3" />
@@ -297,11 +297,17 @@ window.addEventListener('beforeunload', () => {
 
 (async () => {
   try {
-    checkModal();
-
     const { isFirstTime } = await browser.storage.local.get('isFirstTime');
     isUpdated.value = !isFirstTime && compare(currentVersion, prevVersion, '>');
 
+    if (isFirstTime) {
+      modalState.show = false;
+      localStorage.setItem('has-testimonial', true);
+      localStorage.setItem('has-survey', Date.now());
+    } else {
+      checkModal();
+    }
+
     await Promise.allSettled([
       store.dispatch('retrieve', ['workflows', 'logs', 'collections']),
       store.dispatch('retrieveWorkflowState'),

+ 2 - 0
src/popup/pages/Home.vue

@@ -216,6 +216,8 @@ async function initElementSelector() {
     await browser.tabs.sendMessage(tab.id, {
       type: 'automa-element-selector',
     });
+
+    window.close();
   } catch (error) {
     if (error.message.includes('Could not establish connection.')) {
       await browser.tabs.executeScript(tab.id, {

File diff suppressed because it is too large
+ 0 - 0
src/utils/shared.js


+ 0 - 8
webpack.config.js

@@ -51,13 +51,6 @@ const options = {
       'recordWorkflow',
       'index.js'
     ),
-    shortcutListener: path.join(
-      __dirname,
-      'src',
-      'content',
-      'services',
-      'shortcutListener.js'
-    ),
     webService: path.join(
       __dirname,
       'src',
@@ -79,7 +72,6 @@ const options = {
       'contentScript',
       'recordWorkflow',
       'elementSelector',
-      'shortcutListener',
     ],
   },
   output: {

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