mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 10:31:15 +00:00
feat: Data transformation nodes and actions in Nodes Panel (#7760)
- Split Items List node into separate nodes per action - Review node descriptions - New icons - New sections in subcategories --------- Co-authored-by: Giulio Andreini <andreini@netseven.it> Co-authored-by: Deborah <deborah@starfallprojects.co.uk> Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
@@ -162,7 +162,7 @@ function subcategoriesMapper(item: INodeCreateElement) {
|
||||
}
|
||||
|
||||
function baseSubcategoriesFilter(item: INodeCreateElement): boolean {
|
||||
if (item.type === 'section') return item.children.every(baseSubcategoriesFilter);
|
||||
if (item.type === 'section') return true;
|
||||
if (item.type !== 'node') return false;
|
||||
|
||||
const hasTriggerGroup = item.properties.group.includes('trigger');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SectionCreateElement } from '@/Interface';
|
||||
import { groupItemsInSections } from '../utils';
|
||||
import { mockNodeCreateElement } from './utils';
|
||||
import { groupItemsInSections, sortNodeCreateElements } from '../utils';
|
||||
import { mockActionCreateElement, mockNodeCreateElement, mockSectionCreateElement } from './utils';
|
||||
|
||||
describe('NodeCreator - utils', () => {
|
||||
describe('groupItemsInSections', () => {
|
||||
@@ -46,4 +46,20 @@ describe('NodeCreator - utils', () => {
|
||||
expect(result).toEqual([node1, node2, node3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortNodeCreateElements', () => {
|
||||
it('should sort nodes alphabetically by displayName', () => {
|
||||
const node1 = mockNodeCreateElement({ key: 'newNode' }, { displayName: 'xyz' });
|
||||
const node2 = mockNodeCreateElement({ key: 'popularNode' }, { displayName: 'abc' });
|
||||
const node3 = mockNodeCreateElement({ key: 'otherNode' }, { displayName: 'ABC' });
|
||||
expect(sortNodeCreateElements([node1, node2, node3])).toEqual([node2, node3, node1]);
|
||||
});
|
||||
|
||||
it('should not change order for other types (sections, actions)', () => {
|
||||
const node1 = mockSectionCreateElement();
|
||||
const node2 = mockActionCreateElement();
|
||||
const node3 = mockSectionCreateElement();
|
||||
expect(sortNodeCreateElements([node1, node2, node3])).toEqual([node1, node2, node3]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -222,7 +222,7 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
|
||||
|
||||
// Sort only if non-root view
|
||||
if (!stack.items) {
|
||||
sortNodeCreateElements(stackItems);
|
||||
stackItems = sortNodeCreateElements(stackItems);
|
||||
}
|
||||
|
||||
updateCurrentViewStack({ baselineItems: stackItems });
|
||||
|
||||
@@ -59,7 +59,7 @@ export function subcategorizeItems(items: SimplifiedNodeType[]) {
|
||||
|
||||
export function sortNodeCreateElements(nodes: INodeCreateElement[]) {
|
||||
return nodes.sort((a, b) => {
|
||||
if (a.type !== 'node' || b.type !== 'node') return -1;
|
||||
if (a.type !== 'node' || b.type !== 'node') return 0;
|
||||
const displayNameA = a.properties?.displayName?.toLowerCase() || a.key;
|
||||
const displayNameB = b.properties?.displayName?.toLowerCase() || b.key;
|
||||
|
||||
@@ -101,16 +101,16 @@ export function groupItemsInSections(
|
||||
type: 'section',
|
||||
key: section.key,
|
||||
title: section.title,
|
||||
children: itemsBySection[section.key],
|
||||
children: sortNodeCreateElements(itemsBySection[section.key] ?? []),
|
||||
}),
|
||||
)
|
||||
.concat({
|
||||
type: 'section',
|
||||
key: 'other',
|
||||
title: i18n.baseText('nodeCreator.sectionNames.other'),
|
||||
children: itemsBySection.other,
|
||||
children: sortNodeCreateElements(itemsBySection.other ?? []),
|
||||
})
|
||||
.filter((section) => section.children);
|
||||
.filter((section) => section.children.length > 0);
|
||||
|
||||
if (result.length <= 1) {
|
||||
return items;
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
TRANSFORM_DATA_SUBCATEGORY,
|
||||
FILES_SUBCATEGORY,
|
||||
FLOWS_CONTROL_SUBCATEGORY,
|
||||
HELPERS_SUBCATEGORY,
|
||||
TRIGGER_NODE_CREATOR_VIEW,
|
||||
EMAIL_IMAP_NODE_TYPE,
|
||||
DEFAULT_SUBCATEGORY,
|
||||
@@ -29,6 +28,26 @@ import {
|
||||
AI_CATEGORY_EMBEDDING,
|
||||
AI_OTHERS_NODE_CREATOR_VIEW,
|
||||
AI_UNCATEGORIZED_CATEGORY,
|
||||
SET_NODE_TYPE,
|
||||
CODE_NODE_TYPE,
|
||||
DATETIME_NODE_TYPE,
|
||||
FILTER_NODE_TYPE,
|
||||
REMOVE_DUPLICATES_NODE_TYPE,
|
||||
SPLIT_OUT_NODE_TYPE,
|
||||
LIMIT_NODE_TYPE,
|
||||
SUMMARIZE_NODE_TYPE,
|
||||
AGGREGATE_NODE_TYPE,
|
||||
MERGE_NODE_TYPE,
|
||||
HTML_NODE_TYPE,
|
||||
MARKDOWN_NODE_TYPE,
|
||||
XML_NODE_TYPE,
|
||||
CRYPTO_NODE_TYPE,
|
||||
IF_NODE_TYPE,
|
||||
SPLIT_IN_BATCHES_NODE_TYPE,
|
||||
HTTP_REQUEST_NODE_TYPE,
|
||||
HELPERS_SUBCATEGORY,
|
||||
RSS_READ_NODE_TYPE,
|
||||
EMAIL_SEND_NODE_TYPE,
|
||||
} from '@/constants';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
@@ -340,6 +359,7 @@ export function RegularView(nodes: SimplifiedNodeType[]) {
|
||||
properties: {
|
||||
title: 'App Regular Nodes',
|
||||
icon: 'globe',
|
||||
forceIncludeNodes: [RSS_READ_NODE_TYPE, EMAIL_SEND_NODE_TYPE],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -353,20 +373,31 @@ export function RegularView(nodes: SimplifiedNodeType[]) {
|
||||
{
|
||||
key: 'popular',
|
||||
title: i18n.baseText('nodeCreator.sectionNames.popular'),
|
||||
items: [],
|
||||
items: [SET_NODE_TYPE, CODE_NODE_TYPE, DATETIME_NODE_TYPE],
|
||||
},
|
||||
{
|
||||
key: 'addOrRemove',
|
||||
title: i18n.baseText('nodeCreator.sectionNames.transform.addOrRemove'),
|
||||
items: [
|
||||
FILTER_NODE_TYPE,
|
||||
REMOVE_DUPLICATES_NODE_TYPE,
|
||||
SPLIT_OUT_NODE_TYPE,
|
||||
LIMIT_NODE_TYPE,
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'combine',
|
||||
title: i18n.baseText('nodeCreator.sectionNames.transform.combine'),
|
||||
items: [SUMMARIZE_NODE_TYPE, AGGREGATE_NODE_TYPE, MERGE_NODE_TYPE],
|
||||
},
|
||||
{
|
||||
key: 'convert',
|
||||
title: i18n.baseText('nodeCreator.sectionNames.transform.convert'),
|
||||
items: [HTML_NODE_TYPE, MARKDOWN_NODE_TYPE, XML_NODE_TYPE, CRYPTO_NODE_TYPE],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subcategory',
|
||||
key: HELPERS_SUBCATEGORY,
|
||||
category: CORE_NODES_CATEGORY,
|
||||
properties: {
|
||||
title: HELPERS_SUBCATEGORY,
|
||||
icon: 'toolbox',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subcategory',
|
||||
key: FLOWS_CONTROL_SUBCATEGORY,
|
||||
@@ -374,6 +405,13 @@ export function RegularView(nodes: SimplifiedNodeType[]) {
|
||||
properties: {
|
||||
title: FLOWS_CONTROL_SUBCATEGORY,
|
||||
icon: 'code-branch',
|
||||
sections: [
|
||||
{
|
||||
key: 'popular',
|
||||
title: i18n.baseText('nodeCreator.sectionNames.popular'),
|
||||
items: [FILTER_NODE_TYPE, IF_NODE_TYPE, SPLIT_IN_BATCHES_NODE_TYPE, MERGE_NODE_TYPE],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -385,6 +423,22 @@ export function RegularView(nodes: SimplifiedNodeType[]) {
|
||||
icon: 'file-alt',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'subcategory',
|
||||
key: HELPERS_SUBCATEGORY,
|
||||
category: CORE_NODES_CATEGORY,
|
||||
properties: {
|
||||
title: HELPERS_SUBCATEGORY,
|
||||
icon: 'toolbox',
|
||||
sections: [
|
||||
{
|
||||
key: 'popular',
|
||||
title: i18n.baseText('nodeCreator.sectionNames.popular'),
|
||||
items: [HTTP_REQUEST_NODE_TYPE, WEBHOOK_NODE_TYPE, CODE_NODE_TYPE],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user