diff --git a/packages/frontend/editor-ui/src/components/VirtualSchema.vue b/packages/frontend/editor-ui/src/components/VirtualSchema.vue index 3fb6d6009e..12e59d9b60 100644 --- a/packages/frontend/editor-ui/src/components/VirtualSchema.vue +++ b/packages/frontend/editor-ui/src/components/VirtualSchema.vue @@ -193,7 +193,8 @@ const contextItems = computed(() => { return []; } - const fields: Renders[] = flattenSchema({ schema, depth: 1 }).flatMap((renderItem) => { + const flatSchema = flattenSchema({ schema, depth: 1, isDataEmpty: false }); + const fields: Renders[] = flatSchema.flatMap((renderItem) => { const isVars = renderItem.type === 'item' && renderItem.depth === 1 && renderItem.title === '$vars'; @@ -320,7 +321,14 @@ const flattenedNodes = computed(() => ); const flattenNodeSchema = computed(() => - nodeSchema.value ? flattenSchema({ schema: nodeSchema.value, depth: 0, level: -1 }) : [], + nodeSchema.value + ? flattenSchema({ + schema: nodeSchema.value, + depth: 0, + level: -1, + isDataEmpty: props.data.length === 0, + }) + : [], ); /** diff --git a/packages/frontend/editor-ui/src/composables/useDataSchema.test.ts b/packages/frontend/editor-ui/src/composables/useDataSchema.test.ts index 6ed1db3700..4cda707a4f 100644 --- a/packages/frontend/editor-ui/src/composables/useDataSchema.test.ts +++ b/packages/frontend/editor-ui/src/composables/useDataSchema.test.ts @@ -817,6 +817,7 @@ describe('useFlattenSchema', () => { expect( useFlattenSchema().flattenSchema({ schema, + isDataEmpty: false, }).length, ).toBe(3); }); @@ -835,8 +836,18 @@ describe('useFlattenSchema', () => { }, ], }; - const node1Schema = flattenSchema({ schema, expressionPrefix: '$("First Node")', depth: 1 }); - const node2Schema = flattenSchema({ schema, expressionPrefix: '$("Second Node")', depth: 1 }); + const node1Schema = flattenSchema({ + schema, + expressionPrefix: '$("First Node")', + depth: 1, + isDataEmpty: false, + }); + const node2Schema = flattenSchema({ + schema, + expressionPrefix: '$("Second Node")', + depth: 1, + isDataEmpty: false, + }); expect(node1Schema[0].id).not.toBe(node2Schema[0].id); }); diff --git a/packages/frontend/editor-ui/src/composables/useDataSchema.ts b/packages/frontend/editor-ui/src/composables/useDataSchema.ts index 850d74288c..a02520132d 100644 --- a/packages/frontend/editor-ui/src/composables/useDataSchema.ts +++ b/packages/frontend/editor-ui/src/composables/useDataSchema.ts @@ -347,6 +347,7 @@ export const useFlattenSchema = () => { }; const flattenSchema = ({ + isDataEmpty, schema, nodeType, nodeName, @@ -356,6 +357,7 @@ export const useFlattenSchema = () => { level = 0, preview, }: { + isDataEmpty: boolean; schema: Schema; expressionPrefix?: string; nodeType?: string; @@ -367,7 +369,7 @@ export const useFlattenSchema = () => { }): Renders[] => { // only show empty item for the first level if (isEmptySchema(schema) && level < 0) { - return [emptyItem('emptyData')]; + return [emptyItem(isDataEmpty ? 'emptyData' : 'emptySchema')]; } const expression = `{{ ${expressionPrefix ? expressionPrefix + schema.path : schema.path.slice(1)} }}`; @@ -403,6 +405,7 @@ export const useFlattenSchema = () => { .map((item) => { const itemPrefix = schema.type === 'array' ? schema.key : ''; return flattenSchema({ + isDataEmpty, schema: item, expressionPrefix, nodeType, @@ -474,6 +477,7 @@ export const useFlattenSchema = () => { acc = acc.concat( flattenSchema({ + isDataEmpty: item.isDataEmpty, schema: item.schema, depth: item.depth, nodeType: item.node.type, diff --git a/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.test.ts b/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.test.ts index dbdf523c35..937cef0655 100644 --- a/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.test.ts +++ b/packages/frontend/editor-ui/src/features/logs/components/LogDetailsPanel.test.ts @@ -10,16 +10,13 @@ import { createTestWorkflow, createTestWorkflowObject, } from '@/__tests__/mocks'; -import { mockedStore } from '@/__tests__/utils'; -import { useSettingsStore } from '@/stores/settings.store'; -import { type FrontendSettings } from '@n8n/api-types'; import { LOG_DETAILS_PANEL_STATE } from '@/features/logs/logs.constants'; import type { LogEntry } from '../logs.types'; import { createTestLogEntry } from '../__test__/mocks'; +import { NodeConnectionTypes } from 'n8n-workflow'; describe('LogDetailsPanel', () => { let pinia: TestingPinia; - let settingsStore: ReturnType>; const aiNode = createTestNode({ name: 'AI Agent' }); const workflowData = createTestWorkflow({ @@ -84,11 +81,6 @@ describe('LogDetailsPanel', () => { beforeEach(() => { pinia = createTestingPinia({ stubActions: false, fakeApp: true }); - - settingsStore = mockedStore(useSettingsStore); - settingsStore.isEnterpriseFeatureEnabled = {} as FrontendSettings['enterprise']; - - localStorage.clear(); }); it('should show name, run status, input, and output of the node', async () => { @@ -155,4 +147,29 @@ describe('LogDetailsPanel', () => { expect(rendered.emitted()).toEqual({ toggleOutputOpen: [[false]] }); }); + + it('should display correct message when input data is empty', async () => { + const nodeA = createTestNode({ name: 'A' }); + const nodeB = createTestNode({ name: 'B' }); + const runDataA = createTestTaskData({ data: { [NodeConnectionTypes.Main]: [[{ json: {} }]] } }); + const runDataB = createTestTaskData({ source: [{ previousNode: 'A' }] }); + const workflow = createTestWorkflowObject({ nodes: [nodeA, nodeB] }); + const rendered = render({ + isOpen: true, + logEntry: createLogEntry({ + node: nodeB, + runIndex: 0, + runData: runDataB, + workflow, + execution: { resultData: { runData: { A: [runDataA], B: [runDataB] } } }, + }), + panels: LOG_DETAILS_PANEL_STATE.BOTH, + }); + + expect( + await within(rendered.getByTestId('log-details-input')).findByText( + "No fields - item(s) exist, but they're empty", + ), + ).toBeInTheDocument(); + }); });