diff --git a/packages/@n8n/constants/src/execution.ts b/packages/@n8n/constants/src/execution.ts new file mode 100644 index 0000000000..7e8e07dc15 --- /dev/null +++ b/packages/@n8n/constants/src/execution.ts @@ -0,0 +1 @@ +export const TOOL_EXECUTOR_NODE_NAME = 'PartialExecutionToolExecutor'; diff --git a/packages/@n8n/constants/src/index.ts b/packages/@n8n/constants/src/index.ts index 00df13c755..fa469ebeff 100644 --- a/packages/@n8n/constants/src/index.ts +++ b/packages/@n8n/constants/src/index.ts @@ -2,6 +2,7 @@ export * from './api'; export * from './browser'; export * from './community-nodes'; export * from './instance'; +export * from './execution'; export const LICENSE_FEATURES = { SHARING: 'feat:sharing', diff --git a/packages/core/src/execution-engine/partial-execution-utils/rewire-graph.ts b/packages/core/src/execution-engine/partial-execution-utils/rewire-graph.ts index 98b1c533b8..1447611db3 100644 --- a/packages/core/src/execution-engine/partial-execution-utils/rewire-graph.ts +++ b/packages/core/src/execution-engine/partial-execution-utils/rewire-graph.ts @@ -1,10 +1,9 @@ +import { TOOL_EXECUTOR_NODE_NAME } from '@n8n/constants'; import * as a from 'assert/strict'; import { type AiAgentRequest, type INode, NodeConnectionTypes } from 'n8n-workflow'; import { type DirectedGraph } from './directed-graph'; -export const TOOL_EXECUTOR_NODE_NAME = 'PartialExecutionToolExecutor'; - export function rewireGraph( tool: INode, graph: DirectedGraph, diff --git a/packages/core/src/execution-engine/workflow-execute.ts b/packages/core/src/execution-engine/workflow-execute.ts index 2657d6c429..1b97dd18e1 100644 --- a/packages/core/src/execution-engine/workflow-execute.ts +++ b/packages/core/src/execution-engine/workflow-execute.ts @@ -2,6 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ +import { TOOL_EXECUTOR_NODE_NAME } from '@n8n/constants'; import { Container } from '@n8n/di'; import * as assert from 'assert/strict'; import { setMaxListeners } from 'events'; @@ -74,7 +75,6 @@ import { rewireGraph, getNextExecutionIndex, } from './partial-execution-utils'; -import { TOOL_EXECUTOR_NODE_NAME } from './partial-execution-utils/rewire-graph'; import { RoutingNode } from './routing-node'; import { TriggersAndPollers } from './triggers-and-pollers'; diff --git a/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.vue b/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.vue index 5f2d7b3526..672254043a 100644 --- a/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.vue +++ b/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.vue @@ -12,11 +12,12 @@ import NodeIcon from '@/components/NodeIcon.vue'; import { useI18n } from '@n8n/i18n'; import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import LogsViewNodeName from '@/features/logs/components/LogsViewNodeName.vue'; -import { N8nButton, N8nResizeWrapper } from '@n8n/design-system'; +import { N8nButton, N8nResizeWrapper, N8nText } from '@n8n/design-system'; import { computed, useTemplateRef } from 'vue'; import KeyboardShortcutTooltip from '@/components/KeyboardShortcutTooltip.vue'; import { getSubtreeTotalConsumedTokens } from '@/features/logs/logs.utils'; import { LOG_DETAILS_PANEL_STATE } from '@/features/logs/logs.constants'; +import { isPlaceholderLog } from '@/features/logs/logs.utils'; const MIN_IO_PANEL_WIDTH = 200; @@ -82,7 +83,7 @@ function handleResizeEnd() { :is-deleted="latestInfo?.deleted ?? false" /> @@ -218,4 +226,11 @@ function handleResizeEnd() { border-right: var(--border-base); } } + +.placeholder { + flex-grow: 1; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/packages/frontend/editor-ui/src/features/logs/components/LogsOverviewRow.vue b/packages/frontend/editor-ui/src/features/logs/components/LogsOverviewRow.vue index 3e9a170e02..281102b791 100644 --- a/packages/frontend/editor-ui/src/features/logs/components/LogsOverviewRow.vue +++ b/packages/frontend/editor-ui/src/features/logs/components/LogsOverviewRow.vue @@ -37,11 +37,15 @@ const nodeTypeStore = useNodeTypesStore(); const type = computed(() => nodeTypeStore.getNodeType(props.data.node.type)); const isSettled = computed( () => - props.data.runData.executionStatus && + 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(() => { + if (props.data.runData === undefined) { + return '—'; + } + const time = new Date(props.data.runData.startTime); return locale.baseText('logs.overview.body.started', { @@ -50,14 +54,16 @@ const startedAtText = computed(() => { }, }); }); -const statusText = computed(() => upperFirst(props.data.runData.executionStatus)); +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, - ), + props.data.runData + ? locale.displayTimer( + isSettled.value + ? props.data.runData.executionTime + : Math.floor((now.value - props.data.runData.startTime) / 1000) * 1000, + true, + ) + : undefined, ); const subtreeConsumedTokens = computed(() => @@ -65,7 +71,7 @@ const subtreeConsumedTokens = computed(() => ); const hasChildren = computed( - () => props.data.children.length > 0 || !!props.data.runData.metadata?.subExecution, + () => props.data.children.length > 0 || !!props.data.runData?.metadata?.subExecution, ); function isLastChild(level: number) { @@ -144,13 +150,14 @@ watch( -