Skip to content

Commit

Permalink
feat: add testing mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Kholid060 committed Feb 15, 2023
1 parent f5c8e74 commit c5a6e6e
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 44 deletions.
8 changes: 8 additions & 0 deletions src/background/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ message.on('recording:stop', async () => {
console.error(error);
}
});
message.on('workflow:resume', ({ id, nextBlock }) => {
if (!id) return;
workflowState.resume(id, nextBlock);
});
message.on('workflow:breakpoint', (id) => {
if (!id) return;
workflowState.update(id, { status: 'breakpoint' });
});

automa('background', message);

Expand Down
10 changes: 10 additions & 0 deletions src/components/block/BlockBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@
</div>
<slot name="prepend" />
<ui-card :class="contentClass" class="block-base__content relative z-10">
<v-remixicon
v-if="workflow?.data?.value.testingMode"
:class="{ 'text-red-500 dark:text-red-400': data.$breakpoint }"
class="absolute left-0 top-0"
name="riRecordCircleFill"
title="Set as breakpoint"
size="20"
@click="$emit('update', { $breakpoint: !data.$breakpoint })"
/>
<slot></slot>
</ui-card>
<slot name="append" />
Expand Down Expand Up @@ -95,6 +104,7 @@ const props = defineProps({
defineEmits(['delete', 'edit', 'update', 'settings']);
const isCopied = ref(false);
const workflow = inject('workflow', null);
const workflowUtils = inject('workflow-utils', null);
function insertToClipboard() {
Expand Down
169 changes: 169 additions & 0 deletions src/components/newtab/workflow/editor/EditorDebugging.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<template>
<ui-card
v-if="workflowState?.state"
class="shadow-xl flex items-start fixed bottom-8 z-50 left-1/2 -translate-x-1/2"
>
<div class="mr-4 w-52">
<div class="flex items-center gap-2">
<ui-button
:disabled="workflowState.state.nextBlockBreakpoint"
variant="accent"
class="flex-1"
@click="toggleExecution"
>
<v-remixicon
:name="
workflowState.status === 'breakpoint'
? 'riPlayLine'
: 'riPauseLine'
"
class="mr-2 -ml-1"
/>
<span>
{{
t(
`common.${
workflowState.status === 'breakpoint' ? 'resume' : 'pause'
}`
)
}}
</span>
</ui-button>
<ui-button
v-tooltip="t('workflow.testing.nextBlock')"
:disabled="workflowState.status !== 'breakpoint'"
icon
@click="nextBlock"
>
<v-remixicon name="riArrowLeftSLine" rotate="180" />
</ui-button>
<ui-button
v-tooltip="t('common.stop')"
icon
class="text-red-500 dark:text-red-600"
@click="stopWorkflow"
>
<v-remixicon name="riStopLine" />
</ui-button>
</div>
<ui-list
v-if="workflowState.state"
class="mt-4 overflow-auto h-[105px] scroll"
>
<ui-list-item
v-for="block in workflowState.state.currentBlock"
:key="block.id"
small
>
<div class="text-overflow text-sm w-full">
<div class="flex items-center">
<p class="flex-1 text-overflow">
{{ getBlockName(block.name) }}
</p>
<v-remixicon
title="Go to block"
name="riEyeLine"
size="18"
class="text-gray-600 dark:text-gray-200 cursor-pointer"
@click="$emit('goToBlock', block.id)"
/>
</div>
<p
class="leading-tight text-overflow text-gray-600 dark:text-gray-200"
>
{{ t('workflow.testing.startRun') }}:
{{ dayjs(block.startedAt).format('HH:mm:ss, SSS') }}
</p>
</div>
</ui-list-item>
</ui-list>
</div>
<shared-codemirror
:model-value="JSON.stringify(workflowData, null, 2)"
:line-numbers="false"
hide-lang
readonly
lang="json"
class="h-40 w-64 scroll breakpoint-data"
/>
</ui-card>
</template>
<script setup>
import { defineAsyncComponent, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import dayjs from '@/lib/dayjs';
import { tasks } from '@/utils/shared';
import { sendMessage } from '@/utils/message';
const SharedCodemirror = defineAsyncComponent(() =>
import('@/components/newtab/shared/SharedCodemirror.vue')
);
const props = defineProps({
states: {
type: Array,
default: () => [],
},
editor: {
type: Object,
default: () => ({}),
},
});
defineEmits(['goToBlock']);
const { t, te } = useI18n();
const workflowState = computed(() => props.states[0]);
const workflowData = computed(() => {
if (!workflowState.value?.state?.ctxData) return {};
const { ctxData, dataSnapshot } = workflowState.value.state.ctxData;
const latestData = Object.values(ctxData).at(-1);
if (!latestData) return {};
return {
...latestData,
referenceData: {
...latestData.referenceData,
loopData: dataSnapshot[latestData.referenceData.loopData] ?? {},
variables: dataSnapshot[latestData.referenceData.variables] ?? {},
},
};
});
function getBlockName(blockId) {
const key = `workflow.blocks.${blockId}.name`;
return te(key) ? t(key) : tasks[blockId].name;
}
function toggleExecution() {
if (!workflowState.value) return;
if (workflowState.value.status === 'running') {
sendMessage('workflow:breakpoint', workflowState.value.id, 'background');
} else {
sendMessage(
'workflow:resume',
{ id: workflowState.value.id },
'background'
);
}
}
function stopWorkflow() {
if (!workflowState.value) return;
sendMessage('workflow:stop', workflowState.value.id, 'background');
}
function nextBlock() {
sendMessage(
'workflow:resume',
{ id: workflowState.value.id, nextBlock: true },
'background'
);
}
</script>
<style>
.breakpoint-data .cm-editor {
font-size: 13px;
padding-bottom: 0;
}
</style>
68 changes: 45 additions & 23 deletions src/components/newtab/workflow/editor/EditorLocalActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,18 +122,35 @@
</ui-list-item>
</ui-list>
</ui-popover>
<button
v-if="!workflow.isDisabled"
v-tooltip.group="
`${t('common.execute')} (${
shortcuts['editor:execute-workflow'].readable
})`
"
class="hoverable rounded-lg p-2"
@click="executeCurrWorkflow"
>
<v-remixicon name="riPlayLine" />
</button>
<template v-if="!workflow.isDisabled">
<button
v-if="canEdit"
v-tooltip.group="
t(`workflow.testing.${isDataChanged ? 'disabled' : 'title'}`)
"
:class="[
{ 'cursor-default': isDataChanged },
workflow.testingMode
? 'bg-primary bg-primary bg-opacity-20 text-primary'
: 'hoverable',
]"
class="rounded-lg p-2"
@click="toggleTestingMode"
>
<v-remixicon name="riBug2Line" />
</button>
<button
v-tooltip.group="
`${t('common.execute')} (${
shortcuts['editor:execute-workflow'].readable
})`
"
class="hoverable rounded-lg p-2"
@click="executeCurrWorkflow"
>
<v-remixicon name="riPlayLine" />
</button>
</template>
<button
v-else
v-tooltip="t('workflow.clickToEnable')"
Expand Down Expand Up @@ -401,17 +418,6 @@ const userDontHaveTeamsAccess = computed(() => {
);
});
function copyWorkflowId() {
navigator.clipboard.writeText(props.workflow.id).catch((error) => {
console.error(error);
const textarea = document.createElement('textarea');
textarea.value = props.workflow.id;
textarea.select();
document.execCommand('copy');
textarea.blur();
});
}
function updateWorkflow(data = {}, changedIndicator = false) {
let store = null;
Expand All @@ -434,6 +440,22 @@ function updateWorkflow(data = {}, changedIndicator = false) {
return result;
});
}
function toggleTestingMode() {
if (props.isDataChanged) return;
updateWorkflow({ testingMode: !props.workflow.testingMode });
}
function copyWorkflowId() {
navigator.clipboard.writeText(props.workflow.id).catch((error) => {
console.error(error);
const textarea = document.createElement('textarea');
textarea.value = props.workflow.id;
textarea.select();
document.execCommand('copy');
textarea.blur();
});
}
function updateWorkflowDescription(value) {
const keys = ['description', 'category', 'content', 'tag', 'name'];
const payload = {};
Expand Down
4 changes: 4 additions & 0 deletions src/lib/vRemixicon.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
riTimeLine,
riFlagLine,
riFileLine,
riBug2Line,
riTeamLine,
riLinksLine,
riGroupLine,
Expand Down Expand Up @@ -122,6 +123,7 @@ import {
riArrowGoBackLine,
riInputCursorMove,
riCloseCircleLine,
riRecordCircleFill,
riRecordCircleLine,
riErrorWarningLine,
riExternalLinkLine,
Expand Down Expand Up @@ -160,6 +162,7 @@ export const icons = {
riTimeLine,
riFlagLine,
riFileLine,
riBug2Line,
riTeamLine,
riLinksLine,
riGroupLine,
Expand Down Expand Up @@ -260,6 +263,7 @@ export const icons = {
riArrowGoBackLine,
riInputCursorMove,
riCloseCircleLine,
riRecordCircleFill,
riRecordCircleLine,
riErrorWarningLine,
riExternalLinkLine,
Expand Down
2 changes: 2 additions & 0 deletions src/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
"data": "data",
"stop": "Stop",
"sheet": "Sheet",
"pause": "Pause",
"resume": "Resume",
"action": "Action | Actions",
"packages": "Packages",
"storage": "Storage",
Expand Down
6 changes: 6 additions & 0 deletions src/locales/en/newtab.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@
"preferInTab": "Prefer input parameters in the tab"
},
"my": "My workflows",
"testing": {
"title": "Testing mode",
"nextBlock": "Next block",
"startRun": "Start run at",
"disabled": "Save changes first"
},
"import": "Import workflow",
"new": "New workflow",
"delete": "Delete workflow",
Expand Down
1 change: 0 additions & 1 deletion src/newtab/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ browser.runtime.onMessage.addListener(({ type, data }) => {
browser.storage.local.onChanged.addListener(({ workflowStates }) => {
if (!workflowStates) return;
const states = Object.values(workflowStates.newValue);
workflowStore.states = states;
});
Expand Down
6 changes: 6 additions & 0 deletions src/newtab/pages/workflows/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@
</ui-tab-panel>
</template>
<ui-tab-panel cache value="editor" class="w-full" @keydown="onKeydown">
<editor-debugging
v-if="workflow.testingMode && workflowStates.length > 0"
:states="workflowStates"
@goToBlock="goToBlock"
/>
<workflow-editor
v-if="state.workflowConverted"
:id="route.params.id"
Expand Down Expand Up @@ -337,6 +342,7 @@ import WorkflowGlobalData from '@/components/newtab/workflow/WorkflowGlobalData.
import WorkflowDetailsCard from '@/components/newtab/workflow/WorkflowDetailsCard.vue';
import SharedPermissionsModal from '@/components/newtab/shared/SharedPermissionsModal.vue';
import EditorAddPackage from '@/components/newtab/workflow/editor/EditorAddPackage.vue';
import EditorDebugging from '@/components/newtab/workflow/editor/EditorDebugging.vue';
import EditorPkgActions from '@/components/newtab/workflow/editor/EditorPkgActions.vue';
import EditorLocalCtxMenu from '@/components/newtab/workflow/editor/EditorLocalCtxMenu.vue';
import EditorLocalActions from '@/components/newtab/workflow/editor/EditorLocalActions.vue';
Expand Down
Loading

0 comments on commit c5a6e6e

Please sign in to comment.