diff --git a/package.json b/package.json index 6e627a7d..939b1266 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "automa", - "version": "1.28.23", + "version": "1.28.24", "description": "An extension for automating your browser by connecting blocks", "repository": { "type": "git", diff --git a/src/components/newtab/workflow/edit/EditPressKey.vue b/src/components/newtab/workflow/edit/EditPressKey.vue index 043f75c5..8912a236 100644 --- a/src/components/newtab/workflow/edit/EditPressKey.vue +++ b/src/components/newtab/workflow/edit/EditPressKey.vue @@ -76,12 +76,11 @@ @change="updateData({ keysToPress: $event })" /> diff --git a/src/components/newtab/workflow/editor/EditorLocalActions.vue b/src/components/newtab/workflow/editor/EditorLocalActions.vue index 19dd57c7..e0ec83a2 100644 --- a/src/components/newtab/workflow/editor/EditorLocalActions.vue +++ b/src/components/newtab/workflow/editor/EditorLocalActions.vue @@ -131,7 +131,7 @@ :class="[ { 'cursor-default': isDataChanged }, workflow.testingMode - ? 'bg-primary bg-primary bg-opacity-20 text-primary' + ? 'bg-primary bg-opacity-20 text-primary' : 'hoverable', ]" class="rounded-lg p-2" @@ -333,6 +333,7 @@ import { useToast } from 'vue-toastification'; import browser from 'webextension-polyfill'; import { fetchApi } from '@/utils/api'; import { useUserStore } from '@/stores/user'; +import { useStore } from '@/stores/main'; import { useWorkflowStore } from '@/stores/workflow'; import { useTeamWorkflowStore } from '@/stores/teamWorkflow'; import { useSharedWorkflowStore } from '@/stores/sharedWorkflow'; @@ -381,6 +382,7 @@ const { t } = useI18n(); const toast = useToast(); const router = useRouter(); const dialog = useDialog(); +const mainStore = useStore(); const userStore = useUserStore(); const packageStore = usePackageStore(); const workflowStore = useWorkflowStore(); @@ -468,6 +470,11 @@ function updateWorkflowDescription(value) { state.showEditDescription = false; } function executeCurrWorkflow() { + if (mainStore.settings.editor.saveWhenExecute && props.isDataChanged) { + // eslint-disable-next-line no-use-before-define + saveWorkflow(); + } + executeWorkflow({ ...props.workflow, isTesting: props.isDataChanged, diff --git a/src/content/blocksHandler/handlerElementScroll.js b/src/content/blocksHandler/handlerElementScroll.js index e932502b..35848e52 100644 --- a/src/content/blocksHandler/handlerElementScroll.js +++ b/src/content/blocksHandler/handlerElementScroll.js @@ -2,15 +2,13 @@ import handleSelector from '../handleSelector'; function isElScrollable(element) { const excludedTags = ['SCRIPT', 'STYLE', 'SVG', 'HEAD']; - - const isOverflow = /scroll|auto/.test(getComputedStyle(element).overflow); const isScrollable = element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth; const isExcluded = element.tagName.includes('-') || excludedTags.includes(element.tagName); - return isOverflow && isScrollable && !isExcluded; + return isScrollable && !isExcluded; } function findScrollableElement( diff --git a/src/content/blocksHandler/handlerPressKey.js b/src/content/blocksHandler/handlerPressKey.js index 4bda6adb..00b724d4 100644 --- a/src/content/blocksHandler/handlerPressKey.js +++ b/src/content/blocksHandler/handlerPressKey.js @@ -60,11 +60,13 @@ async function pressKeyWithJs({ element, keys, pressTime }) { const isTextField = textFieldTags.includes(element.tagName); if (isEditable || isTextField) { - const isDigit = /^[0-9]$/.test(key); const contentKey = isEditable ? 'textContent' : 'value'; - - if (isLetter || isDigit) { - element[contentKey] += key; + if (isLetter || (keyDefinitions[key] && key.length === 1)) { + if (isEditable && document.execCommand) { + document.execCommand('insertText', false, key); + } else { + element[contentKey] += key; + } return; } @@ -174,7 +176,7 @@ async function pressKey({ data, debugMode, activeTabId }) { element, activeTabId, actionType: data.action, - pressTime: Number.isNaN(+data.pressTime) ? 0 : +data.pressTime, + pressTime: Number.isNaN(+data.pressTime) ? 0 : Math.abs(+data.pressTime), }); return ''; diff --git a/src/locales/en/newtab.json b/src/locales/en/newtab.json index 6b5133c9..b1f34d90 100644 --- a/src/locales/en/newtab.json +++ b/src/locales/en/newtab.json @@ -123,6 +123,10 @@ "snapGrid": { "title": "Snap to the grid", "description": "Snap to the grid when moving a block" + }, + "saveWhenExecute": { + "title": "Auto-save when execute workflow", + "description": "Workflow changes will be saved when executing the workflow" } }, "deleteLog": { diff --git a/src/newtab/pages/settings/SettingsBackup.vue b/src/newtab/pages/settings/SettingsBackup.vue index 13b1284a..8b5e2723 100644 --- a/src/newtab/pages/settings/SettingsBackup.vue +++ b/src/newtab/pages/settings/SettingsBackup.vue @@ -416,7 +416,10 @@ async function restoreWorkflows() { }; reader.onload = ({ target }) => { - const payload = parseJSON(window.decodeURIComponent(target.result), null); + let payload = parseJSON(target.result, null); + if (!payload) + payload = parseJSON(window.decodeURIComponent(target.result), null); + if (!payload) return; const storageTables = parseJSON(payload.storageTables, null); diff --git a/src/newtab/pages/settings/SettingsEditor.vue b/src/newtab/pages/settings/SettingsEditor.vue index 77586101..6513fe32 100644 --- a/src/newtab/pages/settings/SettingsEditor.vue +++ b/src/newtab/pages/settings/SettingsEditor.vue @@ -54,6 +54,17 @@ /> + + + + + {{ t('settings.editor.saveWhenExecute.title') }} + + + {{ t('settings.editor.saveWhenExecute.description') }} + + + diff --git a/src/newtab/pages/workflows/[id].vue b/src/newtab/pages/workflows/[id].vue index 690e7fae..00f4f1e3 100644 --- a/src/newtab/pages/workflows/[id].vue +++ b/src/newtab/pages/workflows/[id].vue @@ -296,6 +296,7 @@ import { computed, onMounted, shallowRef, + onDeactivated, onBeforeUnmount, } from 'vue'; import cloneDeep from 'lodash.clonedeep'; @@ -1529,7 +1530,7 @@ function checkWorkflowUpdate() { /* eslint-disable consistent-return */ function onBeforeLeave() { // disselect node before leave - const selectedNodes = editor.value.getSelectedNodes.value; + const selectedNodes = editor.value?.getSelectedNodes?.value; selectedNodes?.forEach((node) => { node.selected = false; }); @@ -1579,6 +1580,12 @@ watch( } ); +onDeactivated(() => { + const selectedNodes = editor.value?.getSelectedNodes?.value; + selectedNodes?.forEach((node) => { + node.selected = false; + }); +}); onBeforeRouteLeave(onBeforeLeave); onMounted(() => { if (!workflow.value) { diff --git a/src/stores/main.js b/src/stores/main.js index 8ce781e8..3058b5fa 100644 --- a/src/stores/main.js +++ b/src/stores/main.js @@ -25,6 +25,7 @@ export const useStore = defineStore('main', { arrow: true, snapToGrid: false, lineType: 'default', + saveWhenExecute: false, snapGrid: { 0: 15, 1: 15 }, }, }, diff --git a/src/stores/workflow.js b/src/stores/workflow.js index 245350b1..b7b06a1a 100644 --- a/src/stores/workflow.js +++ b/src/stores/workflow.js @@ -282,8 +282,9 @@ export const useWorkflowStore = defineStore('workflow', { const { pinnedWorkflows } = await browser.storage.local.get( 'pinnedWorkflows' ); - const pinnedWorkflowIndex = - pinnedWorkflows && pinnedWorkflows.indexOf(id); + const pinnedWorkflowIndex = pinnedWorkflows + ? pinnedWorkflows.indexOf(id) + : -1; if (pinnedWorkflowIndex !== -1) { pinnedWorkflows.splice(pinnedWorkflowIndex, 1); await browser.storage.local.set({ pinnedWorkflows }); diff --git a/src/utils/shared.js b/src/utils/shared.js index d2ec4369..bfaa75b1 100644 --- a/src/utils/shared.js +++ b/src/utils/shared.js @@ -1047,12 +1047,12 @@ export const tasks = { outputs: 1, allowedInputs: true, maxConnection: 1, - refDataKeys: ['selector', 'keys', 'keysToPress'], + refDataKeys: ['selector', 'keys', 'keysToPress', 'pressTime'], data: { disableBlock: false, keys: '', selector: '', - pressTime: 0, + pressTime: '0', description: '', keysToPress: '', action: 'press-key', diff --git a/src/workflowEngine/blocksHandler/handlerDelay.js b/src/workflowEngine/blocksHandler/handlerDelay.js index 13ba91bb..dd95788d 100644 --- a/src/workflowEngine/blocksHandler/handlerDelay.js +++ b/src/workflowEngine/blocksHandler/handlerDelay.js @@ -1,7 +1,6 @@ function delay(block) { return new Promise((resolve) => { const delayTime = +block.data.time || 500; - console.log(delayTime, 'huh', block); setTimeout(() => { resolve({ data: '', diff --git a/src/workflowEngine/blocksHandler/handlerParameterPrompt.js b/src/workflowEngine/blocksHandler/handlerParameterPrompt.js index 7c0de0c7..dcfc9384 100644 --- a/src/workflowEngine/blocksHandler/handlerParameterPrompt.js +++ b/src/workflowEngine/blocksHandler/handlerParameterPrompt.js @@ -1,6 +1,7 @@ import { nanoid } from 'nanoid/non-secure'; import browser from 'webextension-polyfill'; import { sleep } from '@/utils/helper'; +import renderString from '../templating/renderString'; function getInputtedParams(promptId, ms = 10000) { return new Promise((resolve, reject) => { @@ -33,7 +34,23 @@ function getInputtedParams(promptId, ms = 10000) { }); } -export default async function ({ data, id }) { +async function renderParamValue(param, refData, isPopup) { + const renderedVals = {}; + + const keys = ['defaultValue', 'description', 'placeholder']; + await Promise.allSettled( + keys.map(async (key) => { + if (!param[key]) return; + renderedVals[key] = ( + await renderString(param[key], refData, isPopup) + ).value; + }) + ); + + return { ...param, ...renderedVals }; +} + +export default async function ({ data, id }, { refData }) { const paramURL = browser.runtime.getURL('/params.html'); let tab = (await browser.tabs.query({})).find((item) => item.url.includes(paramURL) @@ -58,14 +75,20 @@ export default async function ({ data, id }) { const promptId = `params-prompt:${nanoid(4)}__${id}`; const { timeout } = data; + const params = await Promise.all( + data.parameters.map((item) => + renderParamValue(item, refData, this.engine.isPopup) + ) + ); + await browser.tabs.sendMessage(tab.id, { name: 'workflow:params-block', data: { + params, promptId, blockId: id, timeoutMs: timeout, execId: this.engine.id, - params: data.parameters, timeout: Date.now() + timeout, name: this.engine.workflow.name, icon: this.engine.workflow.icon,
+ {{ t('settings.editor.saveWhenExecute.title') }} +
+ {{ t('settings.editor.saveWhenExecute.description') }} +