123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- <template>
- <div class="mb-2 mt-4">
- <ui-textarea
- :model-value="data.description"
- autoresize
- :placeholder="t('common.description')"
- class="w-full mb-1"
- @change="updateData({ description: $event })"
- />
- <ui-input
- v-if="!data.everyNewTab"
- :model-value="data.timeout"
- :label="t('workflow.blocks.javascript-code.timeout.placeholder')"
- :title="t('workflow.blocks.javascript-code.timeout.title')"
- type="number"
- class="mb-2 w-full"
- @change="updateData({ timeout: +$event })"
- />
- <p class="text-sm ml-1 text-gray-600 dark:text-gray-200">
- {{ t('workflow.blocks.javascript-code.name') }}
- </p>
- <pre
- v-if="!state.showCodeModal"
- class="rounded-lg overflow-auto text-gray-200 p-4 max-h-80 bg-gray-900"
- @click="state.showCodeModal = true"
- v-text="data.code"
- />
- <ui-checkbox
- :model-value="data.everyNewTab"
- class="mt-2"
- @change="updateData({ everyNewTab: $event })"
- >
- {{ t('workflow.blocks.javascript-code.everyNewTab') }}
- </ui-checkbox>
- <ui-modal v-model="state.showCodeModal" content-class="max-w-3xl">
- <template #header>
- <ui-tabs v-model="state.activeTab" class="border-none">
- <ui-tab value="code">
- {{ t('workflow.blocks.javascript-code.modal.tabs.code') }}
- </ui-tab>
- <ui-tab value="preloadScript">
- {{ t('workflow.blocks.javascript-code.modal.tabs.preloadScript') }}
- </ui-tab>
- </ui-tabs>
- </template>
- <ui-tab-panels
- v-model="state.activeTab"
- class="overflow-auto"
- style="height: calc(100vh - 9rem)"
- >
- <ui-tab-panel value="code" class="h-full">
- <shared-codemirror
- v-model="state.code"
- :extensions="codemirrorExts"
- :style="{ height: data.everyNewTab ? '100%' : '87%' }"
- class="overflow-auto"
- />
- <template v-if="!data.everyNewTab">
- <p class="mt-1 text-sm">
- {{ t('workflow.blocks.javascript-code.availabeFuncs') }}
- </p>
- <p
- class="space-x-1 whitespace-nowrap overflow-x-auto overflow-y-hidden pb-1 scroll"
- >
- <a
- v-for="func in availableFuncs"
- :key="func.id"
- :href="`https://docs.automa.site/blocks/javascript-code.html#${func.id}`"
- target="_blank"
- rel="noopener"
- class="inline-block"
- >
- <code>
- {{ func.name }}
- </code>
- </a>
- </p>
- </template>
- </ui-tab-panel>
- <ui-tab-panel value="preloadScript">
- <div
- v-for="(script, index) in state.preloadScripts"
- :key="index"
- class="flex items-center mt-4"
- >
- <v-remixicon
- name="riDeleteBin7Line"
- class="mr-2 cursor-pointer"
- @click="state.preloadScripts.splice(index, 1)"
- />
- <ui-input
- v-model="state.preloadScripts[index].src"
- placeholder="http://example.com/script.js"
- class="flex-1 mr-4"
- />
- <ui-checkbox
- v-if="!data.everyNewTab"
- v-model="state.preloadScripts[index].removeAfterExec"
- >
- {{ t('workflow.blocks.javascript-code.removeAfterExec') }}
- </ui-checkbox>
- </div>
- <ui-button variant="accent" class="w-20 mt-4" @click="addScript">
- {{ t('common.add') }}
- </ui-button>
- </ui-tab-panel>
- </ui-tab-panels>
- </ui-modal>
- </div>
- </template>
- <script setup>
- import { watch, reactive, defineAsyncComponent } from 'vue';
- import { useI18n } from 'vue-i18n';
- import { syntaxTree } from '@codemirror/language';
- import { autocompletion, snippet } from '@codemirror/autocomplete';
- const SharedCodemirror = defineAsyncComponent(() =>
- import('@/components/newtab/shared/SharedCodemirror.vue')
- );
- const props = defineProps({
- data: {
- type: Object,
- default: () => ({}),
- },
- });
- const emit = defineEmits(['update:data']);
- const { t } = useI18n();
- const availableFuncs = [
- { name: 'automaNextBlock(data, insert?)', id: 'automanextblock-data' },
- { name: 'automaRefData(keyword, path?)', id: 'automarefdata-keyword-path' },
- {
- name: 'automaSetVariable(name, value)',
- id: 'automasetvariable-name-value',
- },
- { name: 'automaResetTimeout()', id: 'automaresettimeout' },
- ];
- const state = reactive({
- activeTab: 'code',
- code: `${props.data.code}`,
- preloadScripts: [...Object.values(props.data.preloadScripts || [])],
- showCodeModal: false,
- });
- function updateData(value) {
- emit('update:data', { ...props.data, ...value });
- }
- function addScript() {
- state.preloadScripts.push({ src: '', removeAfterExec: true });
- }
- const dontCompleteIn = [
- 'String',
- 'TemplateString',
- 'LineComment',
- 'BlockComment',
- 'VariableDefinition',
- 'PropertyDefinition',
- ];
- /* eslint-disable no-template-curly-in-string */
- function automaFuncsCompletion(context) {
- const word = context.matchBefore(/\w*/);
- const nodeBefore = syntaxTree(context.state).resolveInner(context.pos, -1);
- if (
- (word.from === word.to && !context.explicit) ||
- dontCompleteIn.includes(nodeBefore.name)
- )
- return null;
- return {
- from: word.from,
- options: [
- {
- label: 'automaNextBlock',
- type: 'function',
- apply: snippet('automaNextBlock(${data})'),
- info: () => {
- const container = document.createElement('div');
- container.innerHTML = `
- <code>automaNextBlock(<i>data</i>, <i>insert?</i>)</code>
- <p class="mt-2">
- Execute the next block
- <a href="https://docs.automa.site/blocks/javascript-code.html#automanextblock-data" target="_blank" class="underline">
- Read more
- </a>
- </p>
- `;
- return container;
- },
- },
- {
- label: 'automaSetVariable',
- type: 'function',
- apply: snippet("automaSetVariable('${name}', ${value})"),
- info: () => {
- const container = document.createElement('div');
- container.innerHTML = `
- <code>automaRefData(<i>name</i>, <i>value</i>)</code>
- <p class="mt-2">
- Set the value of a variable
- </p>
- `;
- return container;
- },
- },
- {
- label: 'automaRefData',
- type: 'function',
- apply: snippet("automaRefData('${keyword}', '${path}')"),
- info: () => {
- const container = document.createElement('div');
- container.innerHTML = `
- <code>automaRefData(<i>keyword</i>, <i>path</i>)</code>
- <p class="mt-2">
- Use this function to
- <a href="https://docs.automa.site/api-reference/reference-data.html" target="_blank" class="underline">
- reference data
- </a>
- </p>
- `;
- return container;
- },
- },
- {
- label: 'automaResetTimeout',
- type: 'function',
- info: 'Reset javascript execution timeout',
- apply: 'automaResetTimeout()',
- },
- ],
- };
- }
- const codemirrorExts = [autocompletion({ override: [automaFuncsCompletion] })];
- watch(
- () => state.code,
- (value) => {
- updateData({ code: value });
- }
- );
- watch(
- () => state.preloadScripts,
- (value) => {
- updateData({ preloadScripts: value });
- },
- { deep: true }
- );
- </script>
- <style scoped>
- code {
- @apply bg-gray-900 text-sm text-white p-1 rounded-md;
- }
- </style>
|