From 36b6c5fe81350bfdc558edf20ab02eb9d77a783f Mon Sep 17 00:00:00 2001 From: Ahmad Kholid Date: Sat, 6 Nov 2021 15:31:10 +0800 Subject: [PATCH] feat: add "javascript code" block --- src/assets/css/prism-editor.css | 13 +++ src/background/blocks-handler.js | 59 ++++++++++-- src/background/workflow-engine.js | 13 +++ src/components/newtab/logs/LogsDataViewer.vue | 21 +---- .../newtab/workflow/WorkflowEditBlock.vue | 37 +++----- .../workflow/edit/EditJavascriptCode.vue | 91 +++++++++++++++++++ src/components/ui/UiModal.vue | 6 +- src/content/blocks-handler.js | 42 +++++++++ src/content/index.js | 13 ++- src/lib/prism.js | 13 +++ src/lib/v-remixicon.js | 2 + src/newtab/App.vue | 1 + src/utils/helper.js | 2 +- src/utils/reference-data.js | 37 ++++---- src/utils/shared.js | 17 ++++ 15 files changed, 293 insertions(+), 74 deletions(-) create mode 100644 src/assets/css/prism-editor.css create mode 100644 src/components/newtab/workflow/edit/EditJavascriptCode.vue create mode 100644 src/lib/prism.js diff --git a/src/assets/css/prism-editor.css b/src/assets/css/prism-editor.css new file mode 100644 index 000000000..aab8e06b8 --- /dev/null +++ b/src/assets/css/prism-editor.css @@ -0,0 +1,13 @@ +.my-editor, +.prism-editor-wrapper { + color: #ccc; + font-family: JetBrains Mono, Fira code, Fira Mono, Consolas, Menlo, Courier, + monospace; + font-size: 14px; + line-height: 1.5; + padding: 5px; + @apply bg-gray-900 rounded-lg; +} +.prism-editor__textarea:focus { + outline: none; +} diff --git a/src/background/blocks-handler.js b/src/background/blocks-handler.js index e1230946c..bfbf4fada 100644 --- a/src/background/blocks-handler.js +++ b/src/background/blocks-handler.js @@ -1,6 +1,6 @@ /* eslint-disable no-underscore-dangle */ import browser from 'webextension-polyfill'; -import { objectHasKey, fileSaver } from '@/utils/helper'; +import { objectHasKey, fileSaver, isObject } from '@/utils/helper'; import { tasks } from '@/utils/shared'; import dataExporter from '@/utils/data-exporter'; import compareBlockValue from '@/utils/compare-block-value'; @@ -26,8 +26,8 @@ function convertData(data, type) { return result; } -function generateBlockError(block) { - const message = errorMessage('no-tab', tasks[block.name]); +function generateBlockError(block, code) { + const message = errorMessage(code || 'no-tab', tasks[block.name]); const error = new Error(message); error.nextBlockId = getBlockConnection(block); @@ -279,22 +279,61 @@ export function interactionHandler(block) { once: true, delay: block.name === 'link' ? 5000 : 0, callback: (data) => { + if (data?.isError) { + const error = new Error(data.message); + error.nextBlockId = nextBlockId; + + reject(error); + return; + } + + const getColumn = (name) => + this.workflow.dataColumns.find((item) => item.name === name) || { + name: 'column', + type: 'text', + }; + const pushData = (column, value) => { + this.data[column.name]?.push(convertData(value, column.type)); + }; + if (objectHasKey(block.data, 'dataColumn')) { - const { name, type } = Object.values(this.workflow.dataColumns).find( - (item) => item.name === block.data.dataColumn - ) || { name: 'column', type: 'text' }; + const column = getColumn(block.data.dataColumn); if (block.data.saveData) { - if (!objectHasKey(this.data, name)) this.data[name] = []; - if (Array.isArray(data)) { data.forEach((item) => { - this.data[name].push(convertData(item, type)); + pushData(column, item); }); } else { - this.data[name].push(convertData(data, type)); + pushData(column, data); } } + } else if (block.name === 'javascript-code') { + const memoColumn = {}; + const pushObjectData = (obj) => { + Object.entries(obj).forEach(([key, value]) => { + let column; + + if (memoColumn[key]) { + column = memoColumn[key]; + } else { + const currentColumn = getColumn(key); + + column = currentColumn; + memoColumn[key] = currentColumn; + } + + pushData(column, value); + }); + }; + + if (Array.isArray(data)) { + data.forEach((obj) => { + if (isObject(obj)) pushObjectData(obj); + }); + } else if (isObject(data)) { + pushObjectData(data); + } } resolve({ diff --git a/src/background/workflow-engine.js b/src/background/workflow-engine.js index ee3c24091..f90b3dab2 100644 --- a/src/background/workflow-engine.js +++ b/src/background/workflow-engine.js @@ -118,8 +118,21 @@ class WorkflowEngine { browser.tabs.onUpdated.addListener(this.tabUpdatedHandler); browser.tabs.onRemoved.addListener(this.tabRemovedHandler); + const dataColumns = Array.isArray(this.workflow.dataColumns) + ? this.workflow.dataColumns + : Object.values(this.workflow.dataColumns); + this.blocks = blocks; this.startedTimestamp = Date.now(); + this.workflow.dataColumns = dataColumns; + this.data = dataColumns.reduce( + (acc, column) => { + acc[column.name] = []; + + return acc; + }, + { column: [] } + ); workflowState .add(this.id, { diff --git a/src/components/newtab/logs/LogsDataViewer.vue b/src/components/newtab/logs/LogsDataViewer.vue index 917f3ed92..d4232555f 100644 --- a/src/components/newtab/logs/LogsDataViewer.vue +++ b/src/components/newtab/logs/LogsDataViewer.vue @@ -24,7 +24,7 @@ import { ref } from 'vue'; import { PrismEditor } from 'vue-prism-editor'; -import { highlight, languages } from 'prismjs/components/prism-core'; +import { highlighter } from '@/lib/prism'; import { dataExportTypes } from '@/utils/shared'; import dataExporter, { generateJSON } from '@/utils/data-exporter'; -import 'vue-prism-editor/dist/prismeditor.min.css'; -import 'prismjs/components/prism-json'; -import 'prismjs/themes/prism-tomorrow.css'; const props = defineProps({ log: { @@ -55,22 +52,8 @@ const data = generateJSON(Object.keys(props.log.data), props.log.data); const dataStr = JSON.stringify(data, null, 2); const fileName = ref(props.log.name); -const highlighter = (code) => highlight(code, languages.json); function exportData(type) { dataExporter(data, { name: fileName.value, type }, true); } - diff --git a/src/components/newtab/workflow/WorkflowEditBlock.vue b/src/components/newtab/workflow/WorkflowEditBlock.vue index 5d1a1e9f1..308c12bee 100644 --- a/src/components/newtab/workflow/WorkflowEditBlock.vue +++ b/src/components/newtab/workflow/WorkflowEditBlock.vue @@ -17,30 +17,23 @@ + diff --git a/src/components/ui/UiModal.vue b/src/components/ui/UiModal.vue index 19cc1b93c..8009220a9 100644 --- a/src/components/ui/UiModal.vue +++ b/src/components/ui/UiModal.vue @@ -31,7 +31,7 @@
- + {{ title }} { + const isScriptExists = document.getElementById('automa-custom-js'); + + if (isScriptExists) isScriptExists.remove(); + + const script = document.createElement('script'); + let timeout; + + script.id = 'automa-custom-js'; + script.innerHTML = `${automaScript} ${block.data.code}`; + + window.addEventListener('__automa-next-block__', ({ detail }) => { + clearTimeout(timeout); + resolve(detail || {}); + }); + window.addEventListener('__automa-reset-timeout__', () => { + clearTimeout(timeout); + + timeout = setTimeout(() => { + resolve(''); + }, block.data.timeout); + }); + + document.body.appendChild(script); + + timeout = setTimeout(() => { + resolve(''); + }, block.data.timeout); + }); +} + export function elementScroll(block) { return new Promise((resolve) => { const { data } = block; diff --git a/src/content/index.js b/src/content/index.js index d3ee0039d..69e2fd5f9 100644 --- a/src/content/index.js +++ b/src/content/index.js @@ -9,9 +9,16 @@ function onConnectListener() { const handler = blocksHandler[toCamelCase(data.name)]; if (handler) { - handler(data).then((result) => { - port.postMessage({ type: data.name, data: result }); - }); + handler(data) + .then((result) => { + port.postMessage({ type: data.name, data: result }); + }) + .catch((error) => { + port.postMessage({ + isError: true, + message: error?.message || error, + }); + }); } else { console.error(`"${data.name}" doesn't have a handler`); } diff --git a/src/lib/prism.js b/src/lib/prism.js new file mode 100644 index 000000000..5e98e6066 --- /dev/null +++ b/src/lib/prism.js @@ -0,0 +1,13 @@ +import { highlight, languages } from 'prismjs/components/prism-core'; +import 'vue-prism-editor/dist/prismeditor.min.css'; +import 'prismjs/components/prism-clike'; +import 'prismjs/components/prism-javascript'; +import 'prismjs/components/prism-json'; +import 'prismjs/themes/prism-tomorrow.css'; +import '@/assets/css/prism-editor.css'; + +export function highlighter(language) { + return function (code) { + return highlight(code, languages[language]); + }; +} diff --git a/src/lib/v-remixicon.js b/src/lib/v-remixicon.js index 30fa896e3..0103b15cb 100644 --- a/src/lib/v-remixicon.js +++ b/src/lib/v-remixicon.js @@ -2,6 +2,7 @@ import vRemixicon from 'v-remixicon'; import { riHome5Line, riGithubFill, + riCodeSSlashLine, riRecordCircleLine, riErrorWarningLine, riCalendarLine, @@ -66,6 +67,7 @@ import { export const icons = { riHome5Line, riGithubFill, + riCodeSSlashLine, riRecordCircleLine, riErrorWarningLine, riCalendarLine, diff --git a/src/newtab/App.vue b/src/newtab/App.vue index 87401fc6d..ea718a1aa 100644 --- a/src/newtab/App.vue +++ b/src/newtab/App.vue @@ -6,6 +6,7 @@