mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
feat(editor): "Executing" state in the output panel (#15470)
This commit is contained in:
@@ -230,7 +230,7 @@ describe('LogsPanel', () => {
|
|||||||
|
|
||||||
await fireEvent.click(rendered.getByText('Overview'));
|
await fireEvent.click(rendered.getByText('Overview'));
|
||||||
|
|
||||||
expect(rendered.getByText('Running')).toBeInTheDocument();
|
expect(rendered.getByText(/Running/)).toBeInTheDocument();
|
||||||
expect(rendered.queryByText('AI Agent')).not.toBeInTheDocument();
|
expect(rendered.queryByText('AI Agent')).not.toBeInTheDocument();
|
||||||
|
|
||||||
workflowsStore.addNodeExecutionStartedData({
|
workflowsStore.addNodeExecutionStartedData({
|
||||||
@@ -247,7 +247,7 @@ describe('LogsPanel', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(lastTreeItem.getByText('AI Agent')).toBeInTheDocument();
|
expect(lastTreeItem.getByText('AI Agent')).toBeInTheDocument();
|
||||||
expect(lastTreeItem.getByText('Running')).toBeInTheDocument();
|
expect(lastTreeItem.getByText(/Running/)).toBeInTheDocument();
|
||||||
|
|
||||||
workflowsStore.updateNodeExecutionData({
|
workflowsStore.updateNodeExecutionData({
|
||||||
nodeName: 'AI Agent',
|
nodeName: 'AI Agent',
|
||||||
|
|||||||
@@ -108,6 +108,24 @@ describe('LogDetailsPanel', () => {
|
|||||||
expect(await outputPanel.findByText('Hello!')).toBeInTheDocument();
|
expect(await outputPanel.findByText('Hello!')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should show a message in the output panel and data in the input panel when node is running', async () => {
|
||||||
|
const rendered = render({
|
||||||
|
isOpen: true,
|
||||||
|
logEntry: createLogEntry({
|
||||||
|
node: aiNode,
|
||||||
|
runIndex: 0,
|
||||||
|
runData: { ...aiNodeRunData, executionStatus: 'running' },
|
||||||
|
}),
|
||||||
|
panels: LOG_DETAILS_PANEL_STATE.BOTH,
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputPanel = within(rendered.getByTestId('log-details-input'));
|
||||||
|
const outputPanel = within(rendered.getByTestId('log-details-output'));
|
||||||
|
|
||||||
|
expect(await inputPanel.findByText('hey')).toBeInTheDocument();
|
||||||
|
expect(await outputPanel.findByText('Executing node...')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('should close input panel by dragging the divider to the left end', async () => {
|
it('should close input panel by dragging the divider to the left end', async () => {
|
||||||
const rendered = render({
|
const rendered = render({
|
||||||
isOpen: true,
|
isOpen: true,
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ function handleResizeEnd() {
|
|||||||
:class="$style.executionSummary"
|
:class="$style.executionSummary"
|
||||||
:status="logEntry.runData.executionStatus ?? 'unknown'"
|
:status="logEntry.runData.executionStatus ?? 'unknown'"
|
||||||
:consumed-tokens="consumedTokens"
|
:consumed-tokens="consumedTokens"
|
||||||
|
:start-time="logEntry.runData.startTime"
|
||||||
:time-took="logEntry.runData.executionTime"
|
:time-took="logEntry.runData.executionTime"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ watch(
|
|||||||
:class="$style.summary"
|
:class="$style.summary"
|
||||||
:status="execution.status"
|
:status="execution.status"
|
||||||
:consumed-tokens="consumedTokens"
|
:consumed-tokens="consumedTokens"
|
||||||
|
:start-time="+new Date(execution.startedAt)"
|
||||||
:time-took="
|
:time-took="
|
||||||
execution.startedAt && execution.stoppedAt
|
execution.startedAt && execution.stoppedAt
|
||||||
? +new Date(execution.stoppedAt) - +new Date(execution.startedAt)
|
? +new Date(execution.stoppedAt) - +new Date(execution.startedAt)
|
||||||
@@ -247,6 +248,8 @@ watch(
|
|||||||
.tree {
|
.tree {
|
||||||
padding: 0 var(--spacing-2xs) var(--spacing-2xs) var(--spacing-2xs);
|
padding: 0 var(--spacing-2xs) var(--spacing-2xs) var(--spacing-2xs);
|
||||||
|
|
||||||
|
scroll-padding-block: var(--spacing-3xs);
|
||||||
|
|
||||||
& :global(.el-icon) {
|
& :global(.el-icon) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
type LatestNodeInfo,
|
type LatestNodeInfo,
|
||||||
type LogEntry,
|
type LogEntry,
|
||||||
} from '@/components/RunDataAi/utils';
|
} from '@/components/RunDataAi/utils';
|
||||||
|
import { useTimestamp } from '@vueuse/core';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
data: LogEntry;
|
data: LogEntry;
|
||||||
@@ -34,12 +35,13 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const container = useTemplateRef('containerRef');
|
const container = useTemplateRef('containerRef');
|
||||||
const locale = useI18n();
|
const locale = useI18n();
|
||||||
|
const now = useTimestamp({ interval: 1000 });
|
||||||
const nodeTypeStore = useNodeTypesStore();
|
const nodeTypeStore = useNodeTypesStore();
|
||||||
const type = computed(() => nodeTypeStore.getNodeType(props.data.node.type));
|
const type = computed(() => nodeTypeStore.getNodeType(props.data.node.type));
|
||||||
const isSettled = computed(
|
const isSettled = computed(
|
||||||
() =>
|
() =>
|
||||||
props.data.runData.executionStatus &&
|
props.data.runData.executionStatus &&
|
||||||
['crashed', 'error', 'success'].includes(props.data.runData.executionStatus),
|
!['running', 'waiting'].includes(props.data.runData.executionStatus),
|
||||||
);
|
);
|
||||||
const isError = computed(() => !!props.data.runData.error);
|
const isError = computed(() => !!props.data.runData.error);
|
||||||
const startedAtText = computed(() => {
|
const startedAtText = computed(() => {
|
||||||
@@ -51,6 +53,15 @@ const startedAtText = computed(() => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const statusText = computed(() => upperFirst(props.data.runData.executionStatus));
|
||||||
|
const timeText = computed(() =>
|
||||||
|
locale.displayTimer(
|
||||||
|
isSettled.value
|
||||||
|
? props.data.runData.executionTime
|
||||||
|
: Math.floor((now.value - props.data.runData.startTime) / 1000) * 1000,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
const subtreeConsumedTokens = computed(() =>
|
const subtreeConsumedTokens = computed(() =>
|
||||||
props.shouldShowTokenCountColumn ? getSubtreeTotalConsumedTokens(props.data, false) : undefined,
|
props.shouldShowTokenCountColumn ? getSubtreeTotalConsumedTokens(props.data, false) : undefined,
|
||||||
@@ -126,19 +137,24 @@ watch(
|
|||||||
:is-deleted="latestInfo?.deleted ?? false"
|
:is-deleted="latestInfo?.deleted ?? false"
|
||||||
/>
|
/>
|
||||||
<N8nText v-if="!isCompact" tag="div" color="text-light" size="small" :class="$style.timeTook">
|
<N8nText v-if="!isCompact" tag="div" color="text-light" size="small" :class="$style.timeTook">
|
||||||
<I18nT v-if="isSettled" keypath="logs.overview.body.summaryText">
|
<I18nT v-if="isSettled" keypath="logs.overview.body.summaryText.in">
|
||||||
<template #status>
|
<template #status>
|
||||||
<N8nText v-if="isError" color="danger" :bold="true" size="small">
|
<N8nText v-if="isError" color="danger" :bold="true" size="small">
|
||||||
<N8nIcon icon="exclamation-triangle" :class="$style.errorIcon" />{{
|
<N8nIcon icon="exclamation-triangle" :class="$style.errorIcon" />
|
||||||
upperFirst(props.data.runData.executionStatus)
|
{{ statusText }}
|
||||||
}}
|
|
||||||
</N8nText>
|
</N8nText>
|
||||||
<template v-else>{{ upperFirst(props.data.runData.executionStatus) }}</template>
|
<template v-else>{{ statusText }}</template>
|
||||||
</template>
|
</template>
|
||||||
<template #time>{{ locale.displayTimer(props.data.runData.executionTime, true) }}</template>
|
<template #time>{{ timeText }}</template>
|
||||||
</I18nT>
|
</I18nT>
|
||||||
<template v-else>{{ upperFirst(props.data.runData.executionStatus) }}</template></N8nText
|
<template v-else>
|
||||||
>
|
{{
|
||||||
|
locale.baseText('logs.overview.body.summaryText.for', {
|
||||||
|
interpolate: { status: statusText, time: timeText },
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
</N8nText>
|
||||||
<N8nText
|
<N8nText
|
||||||
v-if="!isCompact"
|
v-if="!isCompact"
|
||||||
tag="div"
|
tag="div"
|
||||||
|
|||||||
@@ -3,26 +3,36 @@ import LogsViewConsumedTokenCountText from '@/components/CanvasChat/future/compo
|
|||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { type LlmTokenUsageData } from '@/Interface';
|
import { type LlmTokenUsageData } from '@/Interface';
|
||||||
import { N8nText } from '@n8n/design-system';
|
import { N8nText } from '@n8n/design-system';
|
||||||
|
import { useTimestamp } from '@vueuse/core';
|
||||||
import { upperFirst } from 'lodash-es';
|
import { upperFirst } from 'lodash-es';
|
||||||
import { type ExecutionStatus } from 'n8n-workflow';
|
import { type ExecutionStatus } from 'n8n-workflow';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const { status, consumedTokens, timeTook } = defineProps<{
|
const { status, consumedTokens, startTime, timeTook } = defineProps<{
|
||||||
status: ExecutionStatus;
|
status: ExecutionStatus;
|
||||||
consumedTokens: LlmTokenUsageData;
|
consumedTokens: LlmTokenUsageData;
|
||||||
|
startTime: number;
|
||||||
timeTook?: number;
|
timeTook?: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const locale = useI18n();
|
const locale = useI18n();
|
||||||
|
const now = useTimestamp({ interval: 1000 });
|
||||||
const executionStatusText = computed(() =>
|
const executionStatusText = computed(() =>
|
||||||
timeTook === undefined
|
status === 'running' || status === 'waiting'
|
||||||
? upperFirst(status)
|
? locale.baseText('logs.overview.body.summaryText.for', {
|
||||||
: locale.baseText('logs.overview.body.summaryText', {
|
|
||||||
interpolate: {
|
interpolate: {
|
||||||
status: upperFirst(status),
|
status: upperFirst(status),
|
||||||
time: locale.displayTimer(timeTook, true),
|
time: locale.displayTimer(Math.floor((now.value - startTime) / 1000) * 1000, true),
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
|
: timeTook === undefined
|
||||||
|
? upperFirst(status)
|
||||||
|
: locale.baseText('logs.overview.body.summaryText.in', {
|
||||||
|
interpolate: {
|
||||||
|
status: upperFirst(status),
|
||||||
|
time: locale.displayTimer(timeTook, true),
|
||||||
|
},
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { type LogEntry } from '@/components/RunDataAi/utils';
|
|||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { type IRunDataDisplayMode, type NodePanelType } from '@/Interface';
|
import { type IRunDataDisplayMode, type NodePanelType } from '@/Interface';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
|
import { waitingNodeTooltip } from '@/utils/executionUtils';
|
||||||
import { N8nLink, N8nText } from '@n8n/design-system';
|
import { N8nLink, N8nText } from '@n8n/design-system';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { I18nT } from 'vue-i18n';
|
import { I18nT } from 'vue-i18n';
|
||||||
@@ -42,6 +43,12 @@ const runDataProps = computed<
|
|||||||
overrideOutputs: [source.previousNodeOutput ?? 0],
|
overrideOutputs: [source.previousNodeOutput ?? 0],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
const isExecuting = computed(
|
||||||
|
() =>
|
||||||
|
paneType === 'output' &&
|
||||||
|
(logEntry.runData.executionStatus === 'running' ||
|
||||||
|
logEntry.runData.executionStatus === 'waiting'),
|
||||||
|
);
|
||||||
|
|
||||||
function handleClickOpenNdv() {
|
function handleClickOpenNdv() {
|
||||||
ndvStore.setActiveNodeName(logEntry.node.name);
|
ndvStore.setActiveNodeName(logEntry.node.name);
|
||||||
@@ -69,6 +76,7 @@ function handleChangeDisplayMode(value: IRunDataDisplayMode) {
|
|||||||
:disable-hover-highlight="true"
|
:disable-hover-highlight="true"
|
||||||
:display-mode="displayMode"
|
:display-mode="displayMode"
|
||||||
:disable-ai-content="logEntry.depth === 0"
|
:disable-ai-content="logEntry.depth === 0"
|
||||||
|
:is-executing="isExecuting"
|
||||||
table-header-bg-color="light"
|
table-header-bg-color="light"
|
||||||
@display-mode-change="handleChangeDisplayMode"
|
@display-mode-change="handleChangeDisplayMode"
|
||||||
>
|
>
|
||||||
@@ -84,6 +92,13 @@ function handleChangeDisplayMode(value: IRunDataDisplayMode) {
|
|||||||
</N8nText>
|
</N8nText>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #node-waiting>
|
||||||
|
<N8nText :bold="true" color="text-dark" size="large">
|
||||||
|
{{ locale.baseText('ndv.output.waitNodeWaiting.title') }}
|
||||||
|
</N8nText>
|
||||||
|
<N8nText v-n8n-html="waitingNodeTooltip(logEntry.node)"></N8nText>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-if="isMultipleInput" #content>
|
<template v-if="isMultipleInput" #content>
|
||||||
<!-- leave empty -->
|
<!-- leave empty -->
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -507,7 +507,9 @@ function activatePane() {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #node-waiting>
|
<template #node-waiting>
|
||||||
<N8nText :bold="true" color="text-dark" size="large">Waiting for input</N8nText>
|
<N8nText :bold="true" color="text-dark" size="large">
|
||||||
|
{{ i18n.baseText('ndv.output.waitNodeWaiting.title') }}
|
||||||
|
</N8nText>
|
||||||
<N8nText v-n8n-html="waitingMessage"></N8nText>
|
<N8nText v-n8n-html="waitingMessage"></N8nText>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -402,7 +402,9 @@ const activatePane = () => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #node-waiting>
|
<template #node-waiting>
|
||||||
<N8nText :bold="true" color="text-dark" size="large">Waiting for input</N8nText>
|
<N8nText :bold="true" color="text-dark" size="large">
|
||||||
|
{{ i18n.baseText('ndv.output.waitNodeWaiting.title') }}
|
||||||
|
</N8nText>
|
||||||
<N8nText v-n8n-html="waitingNodeTooltip(node)"></N8nText>
|
<N8nText v-n8n-html="waitingNodeTooltip(node)"></N8nText>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1005,7 +1005,8 @@
|
|||||||
"logs.overview.header.switch.overview": "Overview",
|
"logs.overview.header.switch.overview": "Overview",
|
||||||
"logs.overview.body.empty.message": "Nothing to display yet. Execute the workflow to see execution logs.",
|
"logs.overview.body.empty.message": "Nothing to display yet. Execute the workflow to see execution logs.",
|
||||||
"logs.overview.body.empty.action": "Execute the workflow",
|
"logs.overview.body.empty.action": "Execute the workflow",
|
||||||
"logs.overview.body.summaryText": "{status} in {time}",
|
"logs.overview.body.summaryText.for": "{status} for {time}",
|
||||||
|
"logs.overview.body.summaryText.in": "{status} in {time}",
|
||||||
"logs.overview.body.started": "Started {time}",
|
"logs.overview.body.started": "Started {time}",
|
||||||
"logs.overview.body.run": "Execute step",
|
"logs.overview.body.run": "Execute step",
|
||||||
"logs.overview.body.open": "Open...",
|
"logs.overview.body.open": "Open...",
|
||||||
@@ -1136,11 +1137,12 @@
|
|||||||
"ndv.output.run": "Run",
|
"ndv.output.run": "Run",
|
||||||
"ndv.output.runNodeHint": "Execute this node to view data",
|
"ndv.output.runNodeHint": "Execute this node to view data",
|
||||||
"ndv.output.runNodeHintSubNode": "Output will appear here once the parent node is run",
|
"ndv.output.runNodeHintSubNode": "Output will appear here once the parent node is run",
|
||||||
"ndv.output.waitNodeWaitingForWebhook": "Execution will continue when webhook is received on ",
|
|
||||||
"ndv.output.githubNodeWaitingForWebhook": "Execution will continue when the following webhook URL is called: ",
|
"ndv.output.githubNodeWaitingForWebhook": "Execution will continue when the following webhook URL is called: ",
|
||||||
"ndv.output.sendAndWaitWaitingApproval": "Execution will continue after the user's response",
|
"ndv.output.sendAndWaitWaitingApproval": "Execution will continue after the user's response",
|
||||||
"ndv.output.waitNodeWaitingForFormSubmission": "Execution will continue when form is submitted on ",
|
"ndv.output.waitNodeWaiting.title": "Waiting for input",
|
||||||
"ndv.output.waitNodeWaiting": "Execution will continue when wait time is over",
|
"ndv.output.waitNodeWaiting.description.webhook": "Execution will continue when webhook is received on ",
|
||||||
|
"ndv.output.waitNodeWaiting.description.form": "Execution will continue when form is submitted on ",
|
||||||
|
"ndv.output.waitNodeWaiting.description.timer": "Execution will continue when wait time is over",
|
||||||
"ndv.output.insertTestData": "set mock data",
|
"ndv.output.insertTestData": "set mock data",
|
||||||
"ndv.output.staleDataWarning.regular": "Node parameters have changed.<br>Test node again to refresh output.",
|
"ndv.output.staleDataWarning.regular": "Node parameters have changed.<br>Test node again to refresh output.",
|
||||||
"ndv.output.staleDataWarning.pinData": "Node parameter changes will not affect pinned output data.",
|
"ndv.output.staleDataWarning.pinData": "Node parameter changes will not affect pinned output data.",
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ vi.mock('@/plugins/i18n', () => ({
|
|||||||
i18n: {
|
i18n: {
|
||||||
baseText: (key: string, options?: { interpolate?: { error?: string; details?: string } }) => {
|
baseText: (key: string, options?: { interpolate?: { error?: string; details?: string } }) => {
|
||||||
const texts: { [key: string]: string } = {
|
const texts: { [key: string]: string } = {
|
||||||
'ndv.output.waitNodeWaiting': 'Waiting for execution to resume...',
|
'ndv.output.waitNodeWaiting.description.timer': 'Waiting for execution to resume...',
|
||||||
'ndv.output.waitNodeWaitingForFormSubmission': 'Waiting for form submission: ',
|
'ndv.output.waitNodeWaiting.description.form': 'Waiting for form submission: ',
|
||||||
'ndv.output.waitNodeWaitingForWebhook': 'Waiting for webhook call: ',
|
'ndv.output.waitNodeWaiting.description.webhook': 'Waiting for webhook call: ',
|
||||||
'ndv.output.githubNodeWaitingForWebhook': 'Waiting for webhook call: ',
|
'ndv.output.githubNodeWaitingForWebhook': 'Waiting for webhook call: ',
|
||||||
'ndv.output.sendAndWaitWaitingApproval': 'Waiting for approval...',
|
'ndv.output.sendAndWaitWaitingApproval': 'Waiting for approval...',
|
||||||
'pushConnection.executionError': `Execution error${options?.interpolate?.error}`,
|
'pushConnection.executionError': `Execution error${options?.interpolate?.error}`,
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ export const waitingNodeTooltip = (node: INodeUi | null | undefined) => {
|
|||||||
}
|
}
|
||||||
if (resume) {
|
if (resume) {
|
||||||
if (!['webhook', 'form'].includes(resume as string)) {
|
if (!['webhook', 'form'].includes(resume as string)) {
|
||||||
return i18n.baseText('ndv.output.waitNodeWaiting');
|
return i18n.baseText('ndv.output.waitNodeWaiting.description.timer');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { webhookSuffix } = (node.parameters.options ?? {}) as { webhookSuffix: string };
|
const { webhookSuffix } = (node.parameters.options ?? {}) as { webhookSuffix: string };
|
||||||
@@ -168,12 +168,12 @@ export const waitingNodeTooltip = (node: INodeUi | null | undefined) => {
|
|||||||
|
|
||||||
if (resume === 'form') {
|
if (resume === 'form') {
|
||||||
resumeUrl = `${useRootStore().formWaitingUrl}/${useWorkflowsStore().activeExecutionId}${suffix}`;
|
resumeUrl = `${useRootStore().formWaitingUrl}/${useWorkflowsStore().activeExecutionId}${suffix}`;
|
||||||
message = i18n.baseText('ndv.output.waitNodeWaitingForFormSubmission');
|
message = i18n.baseText('ndv.output.waitNodeWaiting.description.form');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resume === 'webhook') {
|
if (resume === 'webhook') {
|
||||||
resumeUrl = `${useRootStore().webhookWaitingUrl}/${useWorkflowsStore().activeExecutionId}${suffix}`;
|
resumeUrl = `${useRootStore().webhookWaitingUrl}/${useWorkflowsStore().activeExecutionId}${suffix}`;
|
||||||
message = i18n.baseText('ndv.output.waitNodeWaitingForWebhook');
|
message = i18n.baseText('ndv.output.waitNodeWaiting.description.webhook');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message && resumeUrl) {
|
if (message && resumeUrl) {
|
||||||
@@ -182,7 +182,7 @@ export const waitingNodeTooltip = (node: INodeUi | null | undefined) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (node?.type === FORM_NODE_TYPE) {
|
if (node?.type === FORM_NODE_TYPE) {
|
||||||
const message = i18n.baseText('ndv.output.waitNodeWaitingForFormSubmission');
|
const message = i18n.baseText('ndv.output.waitNodeWaiting.description.form');
|
||||||
const resumeUrl = `${useRootStore().formWaitingUrl}/${useWorkflowsStore().activeExecutionId}`;
|
const resumeUrl = `${useRootStore().formWaitingUrl}/${useWorkflowsStore().activeExecutionId}`;
|
||||||
return `${message}<a href="${resumeUrl}" target="_blank">${resumeUrl}</a>`;
|
return `${message}<a href="${resumeUrl}" target="_blank">${resumeUrl}</a>`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user