mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
fix(editor): Change label for unexecuted nodes (#14260)
This commit is contained in:
@@ -251,6 +251,8 @@ If that gets executed in one of the package folders it will only run the tests
|
||||
of this package. If it gets executed in the n8n-root folder it will run all
|
||||
tests of all packages.
|
||||
|
||||
If you made a change which requires an update on a `.test.ts.snap` file, pass `-u` to the command to run tests or press `u` in watch mode.
|
||||
|
||||
#### E2E tests
|
||||
|
||||
⚠️ You have to run `pnpm cypress:install` to install cypress before running the tests for the first time and to update cypress.
|
||||
|
||||
@@ -191,16 +191,14 @@ describe('VirtualSchema.vue', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('renders schema for empty data', async () => {
|
||||
it('renders schema for empty data for unexecuted nodes', async () => {
|
||||
const { getAllByText, getAllByTestId } = renderComponent();
|
||||
|
||||
await waitFor(() =>
|
||||
expect(getAllByText("No fields - item(s) exist, but they're empty").length).toBe(2),
|
||||
);
|
||||
await waitFor(() => expect(getAllByText('Execute previous nodes').length).toBe(2));
|
||||
|
||||
// Collapse second node
|
||||
await userEvent.click(getAllByTestId('run-data-schema-header')[1]);
|
||||
expect(getAllByText("No fields - item(s) exist, but they're empty").length).toBe(1);
|
||||
expect(getAllByText('Execute previous nodes').length).toBe(1);
|
||||
});
|
||||
|
||||
it('renders schema for empty data with binary', async () => {
|
||||
@@ -295,7 +293,7 @@ describe('VirtualSchema.vue', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
const items = getAllByTestId('run-data-schema-item');
|
||||
expect(items).toHaveLength(6);
|
||||
expect(items).toHaveLength(5);
|
||||
});
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
@@ -309,7 +307,7 @@ describe('VirtualSchema.vue', () => {
|
||||
|
||||
const { getAllByText } = renderComponent();
|
||||
await waitFor(() =>
|
||||
expect(getAllByText("No fields - item(s) exist, but they're empty").length).toBe(2),
|
||||
expect(getAllByText("No fields - item(s) exist, but they're empty").length).toBe(1),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -482,7 +480,7 @@ describe('VirtualSchema.vue', () => {
|
||||
const { getAllByTestId } = renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getAllByTestId('run-data-schema-item')).toHaveLength(6);
|
||||
expect(getAllByTestId('run-data-schema-item')).toHaveLength(5);
|
||||
});
|
||||
const items = getAllByTestId('run-data-schema-item');
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ import { asyncComputed } from '@vueuse/core';
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
|
||||
import { pick } from 'lodash-es';
|
||||
import { DateTime } from 'luxon';
|
||||
import NodeExecuteButton from './NodeExecuteButton.vue';
|
||||
|
||||
type Props = {
|
||||
nodes?: IConnectedNode[];
|
||||
@@ -89,7 +90,7 @@ const { getSchemaForExecutionData, getSchemaForJsonSchema, getSchema, filterSche
|
||||
useDataSchema();
|
||||
const { closedNodes, flattenSchema, flattenMultipleSchemas, toggleLeaf, toggleNode } =
|
||||
useFlattenSchema();
|
||||
const { getNodeInputData } = useNodeHelpers();
|
||||
const { getNodeInputData, getNodeTaskData } = useNodeHelpers();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'clear:search': [];
|
||||
@@ -104,6 +105,8 @@ const toggleNodeAndScrollTop = (id: string) => {
|
||||
|
||||
const getNodeSchema = async (fullNode: INodeUi, connectedNode: IConnectedNode) => {
|
||||
const pinData = workflowsStore.pinDataByNodeName(connectedNode.name);
|
||||
const hasPinnedData = pinData ? pinData.length > 0 : false;
|
||||
const isNodeExecuted = getNodeTaskData(fullNode, props.runIndex) !== null || hasPinnedData;
|
||||
const connectedOutputIndexes = connectedNode.indicies.length > 0 ? connectedNode.indicies : [0];
|
||||
const nodeData = connectedOutputIndexes.map((outputIndex) =>
|
||||
getNodeInputData(fullNode, props.runIndex, outputIndex, props.paneType, props.connectionType),
|
||||
@@ -128,6 +131,7 @@ const getNodeSchema = async (fullNode: INodeUi, connectedNode: IConnectedNode) =
|
||||
itemsCount: data.length,
|
||||
preview,
|
||||
hasBinary,
|
||||
isNodeExecuted,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -242,10 +246,8 @@ const nodesSchemas = asyncComputed<SchemaNode[]>(async () => {
|
||||
const nodeType = nodeTypesStore.getNodeType(fullNode.type, fullNode.typeVersion);
|
||||
if (!nodeType) continue;
|
||||
|
||||
const { schema, connectedOutputIndexes, itemsCount, preview, hasBinary } = await getNodeSchema(
|
||||
fullNode,
|
||||
node,
|
||||
);
|
||||
const { schema, connectedOutputIndexes, itemsCount, preview, hasBinary, isNodeExecuted } =
|
||||
await getNodeSchema(fullNode, node);
|
||||
|
||||
const filteredSchema = filterSchema(schema, search);
|
||||
|
||||
@@ -260,6 +262,7 @@ const nodesSchemas = asyncComputed<SchemaNode[]>(async () => {
|
||||
schema: filteredSchema,
|
||||
preview,
|
||||
hasBinary,
|
||||
isNodeExecuted,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -431,6 +434,34 @@ const onDragEnd = (el: HTMLElement) => {
|
||||
class="notice"
|
||||
:style="{ marginLeft: `calc(var(--spacing-l) + var(--spacing-l) * ${item.level})` }"
|
||||
/>
|
||||
<div
|
||||
v-else-if="item.type === 'empty'"
|
||||
:style="{
|
||||
paddingBottom: `var(--spacing-xs)`,
|
||||
marginLeft: `var(--spacing-xl)`,
|
||||
}"
|
||||
>
|
||||
<N8nText tag="div" size="small">
|
||||
<i18n-t
|
||||
v-if="item.key === 'executeSchema'"
|
||||
tag="span"
|
||||
keypath="dataMapping.schemaView.executeSchema"
|
||||
>
|
||||
<template #link>
|
||||
<NodeExecuteButton
|
||||
:node-name="item.nodeName"
|
||||
text
|
||||
telemetry-source="inputs"
|
||||
hide-icon
|
||||
:label="i18n.baseText('ndv.input.noOutputData.executePrevious')"
|
||||
size="small"
|
||||
:style="{ padding: 0 }"
|
||||
/>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<i18n-t v-else tag="span" :keypath="`dataMapping.schemaView.${item.key}`" />
|
||||
</N8nText>
|
||||
</div>
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
</DynamicScroller>
|
||||
|
||||
@@ -2005,32 +2005,40 @@ exports[`VirtualSchema.vue > renders schema with spaces and dots 1`] = `
|
||||
|
||||
|
||||
<div
|
||||
class="schema-item draggable"
|
||||
data-test-id="run-data-schema-item"
|
||||
data-v-0f5e7239=""
|
||||
data-v-d00cba9a=""
|
||||
type="item"
|
||||
>
|
||||
<div
|
||||
class="toggle-container"
|
||||
data-v-0f5e7239=""
|
||||
class="n8n-text size-small regular"
|
||||
data-v-d00cba9a=""
|
||||
>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
|
||||
<span
|
||||
class="content text"
|
||||
data-test-id="run-data-schema-item-value"
|
||||
data-v-0f5e7239=""
|
||||
data-v-d00cba9a=""
|
||||
>
|
||||
|
||||
<span>
|
||||
|
||||
<button
|
||||
aria-live="polite"
|
||||
class="button button primary small text el-tooltip__trigger el-tooltip__trigger"
|
||||
style="padding: 0px;"
|
||||
title="Runs the current node. Will also run previous nodes if they have not been run yet"
|
||||
transparent-background="false"
|
||||
>
|
||||
<!--v-if-->
|
||||
No fields - item(s) exist, but they're empty
|
||||
</span>
|
||||
<span>
|
||||
|
||||
Execute previous nodes
|
||||
|
||||
</span>
|
||||
</button>
|
||||
<!--teleport start-->
|
||||
<!--teleport end-->
|
||||
|
||||
|
||||
to see schema
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -233,6 +233,7 @@ export type SchemaNode = {
|
||||
itemsCount: number;
|
||||
schema: Schema;
|
||||
preview: boolean;
|
||||
isNodeExecuted: boolean;
|
||||
hasBinary: boolean;
|
||||
};
|
||||
|
||||
@@ -279,7 +280,14 @@ export type RenderNotice = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type Renders = RenderHeader | RenderItem | RenderIcon | RenderNotice;
|
||||
export type RenderEmpty = {
|
||||
id: string;
|
||||
type: 'empty';
|
||||
nodeName: string;
|
||||
key: 'emptyData' | 'emptyDataWithBinary' | 'executeSchema';
|
||||
};
|
||||
|
||||
export type Renders = RenderHeader | RenderItem | RenderIcon | RenderNotice | RenderEmpty;
|
||||
|
||||
const icons = {
|
||||
object: 'cube',
|
||||
@@ -296,13 +304,11 @@ const icons = {
|
||||
|
||||
const getIconBySchemaType = (type: Schema['type']): string => icons[type];
|
||||
|
||||
const emptyItem = (
|
||||
message = useI18n().baseText('dataMapping.schemaView.emptyData'),
|
||||
): RenderItem => ({
|
||||
const emptyItem = (key: RenderEmpty['key'], nodeName?: string): RenderEmpty => ({
|
||||
id: `empty-${window.crypto.randomUUID()}`,
|
||||
icon: '',
|
||||
value: message,
|
||||
type: 'item',
|
||||
type: 'empty',
|
||||
key,
|
||||
nodeName: nodeName || '',
|
||||
});
|
||||
|
||||
const moreFieldsItem = (): RenderIcon => ({
|
||||
@@ -361,10 +367,10 @@ export const useFlattenSchema = () => {
|
||||
prefix?: string;
|
||||
level?: number;
|
||||
preview?: boolean;
|
||||
}): RenderItem[] => {
|
||||
}): Renders[] => {
|
||||
// only show empty item for the first level
|
||||
if (isDataEmpty(schema) && depth <= 0) {
|
||||
return [emptyItem()];
|
||||
return [emptyItem('emptyData')];
|
||||
}
|
||||
|
||||
const expression = `{{ ${expressionPrefix ? expressionPrefix + schema.path : schema.path.slice(1)} }}`;
|
||||
@@ -372,7 +378,7 @@ export const useFlattenSchema = () => {
|
||||
const id = expression;
|
||||
|
||||
if (Array.isArray(schema.value)) {
|
||||
const items: RenderItem[] = [];
|
||||
const items: Renders[] = [];
|
||||
|
||||
if (schema.key) {
|
||||
items.push({
|
||||
@@ -459,13 +465,14 @@ export const useFlattenSchema = () => {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (isDataEmpty(item.schema) && !item.isNodeExecuted && !item.hasBinary) {
|
||||
acc.push(emptyItem('executeSchema', item.node.name));
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (isDataEmpty(item.schema)) {
|
||||
const message = useI18n().baseText(
|
||||
item.hasBinary
|
||||
? 'dataMapping.schemaView.emptyDataWithBinary'
|
||||
: 'dataMapping.schemaView.emptyData',
|
||||
);
|
||||
acc.push(emptyItem(message));
|
||||
const key = item.hasBinary ? 'emptyDataWithBinary' : 'emptyData';
|
||||
acc.push(emptyItem(key));
|
||||
return acc;
|
||||
}
|
||||
|
||||
|
||||
@@ -669,6 +669,7 @@
|
||||
"dataMapping.tableView.tableColumnsExceeded.tooltip.link": "JSON view",
|
||||
"dataMapping.schemaView.emptyData": "No fields - item(s) exist, but they're empty",
|
||||
"dataMapping.schemaView.emptyDataWithBinary": "Only binary data exists. View it using the 'Binary' tab",
|
||||
"dataMapping.schemaView.executeSchema": "{link} to see schema",
|
||||
"dataMapping.schemaView.disabled": "This node is disabled and will just pass data through",
|
||||
"dataMapping.schemaView.noMatches": "No results for '{search}'",
|
||||
"dataMapping.schemaView.preview": "Usually outputs the following fields. Execute the node to see the actual ones. {link}",
|
||||
|
||||
Reference in New Issue
Block a user