fix(editor): Show Transform Node in Panel only if available (#14830)

This commit is contained in:
Mutasem Aldmour
2025-04-24 09:59:22 +02:00
committed by GitHub
parent 67240ee069
commit 92e2a8e61a
5 changed files with 234 additions and 3 deletions

View File

@@ -62,6 +62,8 @@ export const mockNodeTypeDescription = ({
codex = undefined,
properties = [],
group,
hidden,
description,
}: {
name?: INodeTypeDescription['name'];
icon?: INodeTypeDescription['icon'];
@@ -72,12 +74,14 @@ export const mockNodeTypeDescription = ({
codex?: INodeTypeDescription['codex'];
properties?: INodeTypeDescription['properties'];
group?: INodeTypeDescription['group'];
hidden?: INodeTypeDescription['hidden'];
description?: INodeTypeDescription['description'];
} = {}) =>
mock<INodeTypeDescription>({
name,
icon,
displayName: name,
description: '',
description: description ?? '',
version,
defaults: {
name,
@@ -93,6 +97,7 @@ export const mockNodeTypeDescription = ({
documentationUrl: 'https://docs',
iconUrl: 'nodes/test-node/icon.svg',
webhooks: undefined,
hidden,
});
export const mockLoadedNodeType = (name: string) =>

View File

@@ -0,0 +1,134 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`viewsData > AIView > should return ai view with ai transform node 1`] = `
{
"items": [
{
"key": "ai_templates_root",
"properties": {
"description": "See what's possible and get started 5x faster",
"icon": "box-open",
"name": "ai_templates_root",
"tag": {
"text": "Recommended",
"type": "info",
},
"title": "AI Templates",
"url": "template-repository-url.n8n.io?test=value&utm_user_role=AdvancedAI",
},
"type": "link",
},
{
"key": "agent",
"properties": {
"description": "example mock agent node",
"displayName": "agent",
"group": [],
"icon": "fa:pen",
"iconUrl": "nodes/test-node/icon.svg",
"name": "agent",
"title": "agent",
},
"type": "node",
},
{
"key": "chain",
"properties": {
"description": "example mock chain node",
"displayName": "chain",
"group": [],
"icon": "fa:pen",
"iconUrl": "nodes/test-node/icon.svg",
"name": "chain",
"title": "chain",
},
"type": "node",
},
{
"key": "n8n-nodes-base.aiTransform",
"properties": {
"description": "",
"displayName": "n8n-nodes-base.aiTransform",
"group": [],
"icon": "fa:pen",
"iconUrl": "nodes/test-node/icon.svg",
"name": "n8n-nodes-base.aiTransform",
"title": "n8n-nodes-base.aiTransform",
},
"type": "node",
},
{
"key": "AI Other",
"properties": {
"description": "Embeddings, Vector Stores, LLMs and other AI nodes",
"icon": "robot",
"title": "Other AI Nodes",
},
"type": "view",
},
],
"subtitle": "Select an AI Node to add to your workflow",
"title": "AI Nodes",
"value": "AI",
}
`;
exports[`viewsData > AIView > should return ai view without ai transform node if ask ai is not enabled 1`] = `
{
"items": [
{
"key": "ai_templates_root",
"properties": {
"description": "See what's possible and get started 5x faster",
"icon": "box-open",
"name": "ai_templates_root",
"tag": {
"text": "Recommended",
"type": "info",
},
"title": "AI Templates",
"url": "template-repository-url.n8n.io?test=value&utm_user_role=AdvancedAI",
},
"type": "link",
},
{
"key": "agent",
"properties": {
"description": "example mock agent node",
"displayName": "agent",
"group": [],
"icon": "fa:pen",
"iconUrl": "nodes/test-node/icon.svg",
"name": "agent",
"title": "agent",
},
"type": "node",
},
{
"key": "chain",
"properties": {
"description": "example mock chain node",
"displayName": "chain",
"group": [],
"icon": "fa:pen",
"iconUrl": "nodes/test-node/icon.svg",
"name": "chain",
"title": "chain",
},
"type": "node",
},
{
"key": "AI Other",
"properties": {
"description": "Embeddings, Vector Stores, LLMs and other AI nodes",
"icon": "robot",
"title": "Other AI Nodes",
},
"type": "view",
},
],
"subtitle": "Select an AI Node to add to your workflow",
"title": "AI Nodes",
"value": "AI",
}
`;

View File

@@ -0,0 +1,90 @@
import { setActivePinia } from 'pinia';
import { createTestingPinia } from '@pinia/testing';
import { AI_CATEGORY_AGENTS, AI_CATEGORY_CHAINS, AI_TRANSFORM_NODE_TYPE } from '@/constants';
import type { INodeTypeDescription } from 'n8n-workflow';
import { START_NODE_TYPE } from 'n8n-workflow';
import { useSettingsStore } from '@/stores/settings.store';
import { AIView } from './viewsData';
import { mockNodeTypeDescription } from '@/__tests__/mocks';
import { useTemplatesStore } from '@/stores/templates.store';
const getNodeType = vi.fn();
const aiTransformNode = mockNodeTypeDescription({ name: AI_TRANSFORM_NODE_TYPE });
const otherNodes = (
[
{ name: START_NODE_TYPE },
{
name: 'agentHidden',
description: 'example mock agent node',
hidden: true,
codex: { subcategories: { AI: [AI_CATEGORY_AGENTS] } },
},
{
name: 'agent',
description: 'example mock agent node',
codex: { subcategories: { AI: [AI_CATEGORY_AGENTS] } },
},
{
name: 'chainHidden',
description: 'example mock chain node',
hidden: true,
codex: { subcategories: { AI: [AI_CATEGORY_CHAINS] } },
},
{
name: 'chain',
description: 'example mock chain node',
codex: { subcategories: { AI: [AI_CATEGORY_CHAINS] } },
},
] as Array<Partial<INodeTypeDescription>>
).map(mockNodeTypeDescription);
vi.mock('@/stores/nodeTypes.store', () => ({
useNodeTypesStore: vi.fn(() => ({
getNodeType,
allLatestNodeTypes: [aiTransformNode, ...otherNodes],
})),
}));
describe('viewsData', () => {
beforeAll(() => {
setActivePinia(createTestingPinia());
const templatesStore = useTemplatesStore();
vi.spyOn(templatesStore, 'websiteTemplateRepositoryParameters', 'get').mockImplementation(
() => new URLSearchParams({ test: 'value' }),
);
vi.spyOn(templatesStore, 'constructTemplateRepositoryURL').mockImplementation(
(params) => `template-repository-url.n8n.io?${params.toString()}`,
);
getNodeType.mockImplementation((nodeName: string) => {
if (nodeName === AI_TRANSFORM_NODE_TYPE) {
return aiTransformNode;
}
return null;
});
});
afterEach(() => {
vi.clearAllMocks();
});
describe('AIView', () => {
test('should return ai view with ai transform node', () => {
const settingsStore = useSettingsStore();
vi.spyOn(settingsStore, 'isAskAiEnabled', 'get').mockReturnValue(true);
expect(AIView([])).toMatchSnapshot();
});
test('should return ai view without ai transform node if ask ai is not enabled', () => {
const settingsStore = useSettingsStore();
vi.spyOn(settingsStore, 'isAskAiEnabled', 'get').mockReturnValue(false);
expect(AIView([])).toMatchSnapshot();
});
});
});

View File

@@ -67,6 +67,7 @@ import type { NodeConnectionType } from 'n8n-workflow';
import { useTemplatesStore } from '@/stores/templates.store';
import type { BaseTextKey } from '@/plugins/i18n';
import { camelCase } from 'lodash-es';
import { useSettingsStore } from '@/stores/settings.store';
export interface NodeViewItemSection {
key: string;
@@ -149,8 +150,9 @@ export function AIView(_nodes: SimplifiedNodeType[]): NodeView {
const websiteCategoryURL =
templatesStore.constructTemplateRepositoryURL(websiteCategoryURLParams);
const askAiEnabled = useSettingsStore().isAskAiEnabled;
const aiTransformNode = nodeTypesStore.getNodeType(AI_TRANSFORM_NODE_TYPE);
const transformNode = aiTransformNode ? [getNodeView(aiTransformNode)] : [];
const transformNode = askAiEnabled && aiTransformNode ? [getNodeView(aiTransformNode)] : [];
return {
value: AI_NODE_CREATOR_VIEW,

View File

@@ -1281,7 +1281,7 @@
"nodeCreator.aiPanel.aiNodes": "AI Nodes",
"nodeCreator.aiPanel.aiOtherNodes": "Other AI Nodes",
"nodeCreator.aiPanel.aiOtherNodesDescription": "Embeddings, Vector Stores, LLMs and other AI nodes",
"nodeCreator.aiPanel.selectAiNode": "Select an Al Node to add to your workflow",
"nodeCreator.aiPanel.selectAiNode": "Select an AI Node to add to your workflow",
"nodeCreator.aiPanel.nodesForAi": "Build autonomous agents, summarize or search documents, etc.",
"nodeCreator.aiPanel.newTag": "New",
"nodeCreator.aiPanel.langchainAiNodes": "AI",