mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(editor): Node Creator AI nodes improvements (#9484)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
This commit is contained in:
parent
e68a3fd6ce
commit
be4f54de15
|
@ -35,7 +35,7 @@ export const INSTANCE_MEMBERS = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export const MANUAL_TRIGGER_NODE_NAME = 'Manual Trigger';
|
export const MANUAL_TRIGGER_NODE_NAME = 'Manual Trigger';
|
||||||
export const MANUAL_TRIGGER_NODE_DISPLAY_NAME = 'When clicking "Test workflow"';
|
export const MANUAL_TRIGGER_NODE_DISPLAY_NAME = 'When clicking ‘Test workflow’';
|
||||||
export const MANUAL_CHAT_TRIGGER_NODE_NAME = 'Chat Trigger';
|
export const MANUAL_CHAT_TRIGGER_NODE_NAME = 'Chat Trigger';
|
||||||
export const SCHEDULE_TRIGGER_NODE_NAME = 'Schedule Trigger';
|
export const SCHEDULE_TRIGGER_NODE_NAME = 'Schedule Trigger';
|
||||||
export const CODE_NODE_NAME = 'Code';
|
export const CODE_NODE_NAME = 'Code';
|
||||||
|
|
|
@ -510,7 +510,7 @@ describe('Execution', () => {
|
||||||
|
|
||||||
cy.wait('@workflowRun').then((interception) => {
|
cy.wait('@workflowRun').then((interception) => {
|
||||||
expect(interception.request.body).to.have.property('runData').that.is.an('object');
|
expect(interception.request.body).to.have.property('runData').that.is.an('object');
|
||||||
const expectedKeys = ['When clicking "Test workflow"', 'fetch 5 random users'];
|
const expectedKeys = ['When clicking ‘Test workflow’', 'fetch 5 random users'];
|
||||||
|
|
||||||
expect(Object.keys(interception.request.body.runData)).to.have.lengthOf(expectedKeys.length);
|
expect(Object.keys(interception.request.body.runData)).to.have.lengthOf(expectedKeys.length);
|
||||||
expect(interception.request.body.runData).to.include.all.keys(expectedKeys);
|
expect(interception.request.body.runData).to.include.all.keys(expectedKeys);
|
||||||
|
|
|
@ -35,7 +35,7 @@ describe('Node Creator', () => {
|
||||||
nodeCreatorFeature.actions.openNodeCreator();
|
nodeCreatorFeature.actions.openNodeCreator();
|
||||||
|
|
||||||
nodeCreatorFeature.getters.searchBar().find('input').type('manual');
|
nodeCreatorFeature.getters.searchBar().find('input').type('manual');
|
||||||
nodeCreatorFeature.getters.creatorItem().should('have.length', 2);
|
nodeCreatorFeature.getters.creatorItem().should('have.length', 1);
|
||||||
nodeCreatorFeature.getters.searchBar().find('input').clear().type('manual123');
|
nodeCreatorFeature.getters.searchBar().find('input').clear().type('manual123');
|
||||||
nodeCreatorFeature.getters.creatorItem().should('have.length', 0);
|
nodeCreatorFeature.getters.creatorItem().should('have.length', 0);
|
||||||
nodeCreatorFeature.getters
|
nodeCreatorFeature.getters
|
||||||
|
@ -159,7 +159,7 @@ describe('Node Creator', () => {
|
||||||
|
|
||||||
it('should have "Triggers" section collapsed when opening actions view from Regular root view', () => {
|
it('should have "Triggers" section collapsed when opening actions view from Regular root view', () => {
|
||||||
nodeCreatorFeature.actions.openNodeCreator();
|
nodeCreatorFeature.actions.openNodeCreator();
|
||||||
nodeCreatorFeature.getters.getCreatorItem('Manually').click();
|
nodeCreatorFeature.getters.getCreatorItem('Trigger manually').click();
|
||||||
|
|
||||||
nodeCreatorFeature.actions.openNodeCreator();
|
nodeCreatorFeature.actions.openNodeCreator();
|
||||||
nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n');
|
nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n');
|
||||||
|
@ -308,7 +308,7 @@ describe('Node Creator', () => {
|
||||||
nodeCreatorFeature.getters.getCategoryItem('Actions').click();
|
nodeCreatorFeature.getters.getCategoryItem('Actions').click();
|
||||||
nodeCreatorFeature.getters.getCreatorItem('Create a credential').click();
|
nodeCreatorFeature.getters.getCreatorItem('Create a credential').click();
|
||||||
NDVModal.actions.close();
|
NDVModal.actions.close();
|
||||||
WorkflowPage.actions.deleteNode('When clicking "Test workflow"');
|
WorkflowPage.actions.deleteNode('When clicking ‘Test workflow’');
|
||||||
WorkflowPage.getters.canvasNodePlusEndpointByName('n8n').click();
|
WorkflowPage.getters.canvasNodePlusEndpointByName('n8n').click();
|
||||||
nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n');
|
nodeCreatorFeature.getters.searchBar().find('input').clear().type('n8n');
|
||||||
nodeCreatorFeature.getters.getCreatorItem('n8n').click();
|
nodeCreatorFeature.getters.getCreatorItem('n8n').click();
|
||||||
|
|
|
@ -38,7 +38,7 @@ describe('Editors', () => {
|
||||||
});
|
});
|
||||||
ndv.actions.close();
|
ndv.actions.close();
|
||||||
|
|
||||||
workflowPage.actions.openNode('When clicking "Test workflow"');
|
workflowPage.actions.openNode('When clicking ‘Test workflow’');
|
||||||
ndv.actions.setPinnedData([{ table: 'test_table' }]);
|
ndv.actions.setPinnedData([{ table: 'test_table' }]);
|
||||||
ndv.actions.close();
|
ndv.actions.close();
|
||||||
|
|
||||||
|
|
|
@ -652,7 +652,7 @@ describe('NDV', () => {
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
workflowPage.actions.executeWorkflow();
|
workflowPage.actions.executeWorkflow();
|
||||||
// Manual tigger node should show success indicator
|
// Manual tigger node should show success indicator
|
||||||
workflowPage.actions.openNode('When clicking "Test workflow"');
|
workflowPage.actions.openNode('When clicking ‘Test workflow’');
|
||||||
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
||||||
// Code node should show error
|
// Code node should show error
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "d0eda550-2526-42a1-aa19-dee411c8acf9",
|
"id": "d0eda550-2526-42a1-aa19-dee411c8acf9",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
],
|
],
|
||||||
"pinData": {},
|
"pinData": {},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "369fe424-dd3b-4399-9de3-50bd4ce1f75b",
|
"id": "369fe424-dd3b-4399-9de3-50bd4ce1f75b",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -570,7 +570,7 @@
|
||||||
],
|
],
|
||||||
"pinData": {},
|
"pinData": {},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "5ae8991f-08a2-4b27-b61c-85e3b8a83693",
|
"id": "5ae8991f-08a2-4b27-b61c-85e3b8a83693",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -78,14 +78,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"When clicking \"Test workflow\"": [
|
"When clicking ‘Test workflow’": [
|
||||||
{
|
{
|
||||||
"json": {}
|
"json": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "b3f0815d-b733-413f-ab3f-74e48277bd3a",
|
"id": "b3f0815d-b733-413f-ab3f-74e48277bd3a",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -160,7 +160,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "46770685-44d1-4aad-9107-1d790cf26b50",
|
"id": "46770685-44d1-4aad-9107-1d790cf26b50",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"pinData": {
|
"pinData": {
|
||||||
"When clicking \"Test workflow\"": [
|
"When clicking ‘Test workflow’": [
|
||||||
{
|
{
|
||||||
"json": {
|
"json": {
|
||||||
"id": "654cfa05fa51480dcb543b1a",
|
"id": "654cfa05fa51480dcb543b1a",
|
||||||
|
@ -599,7 +599,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -191,7 +191,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -241,7 +241,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -374,7 +374,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -424,7 +424,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -524,7 +524,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
"id": "551313bb-1e01-4133-9956-e6f09968f2ce",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -574,7 +574,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "f26332f3-c61a-4843-94bd-64a73ad161ff",
|
"id": "f26332f3-c61a-4843-94bd-64a73ad161ff",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
],
|
],
|
||||||
"pinData": {},
|
"pinData": {},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "449ab540-d9d7-480d-b131-05e9989a69cd",
|
"id": "449ab540-d9d7-480d-b131-05e9989a69cd",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "ef63cdc5-50bc-4525-9873-7e7f7589a60e",
|
"id": "ef63cdc5-50bc-4525-9873-7e7f7589a60e",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -199,7 +199,7 @@
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "f332a7d1-31b4-4e78-b31e-9e8db945bf3f",
|
"id": "f332a7d1-31b4-4e78-b31e-9e8db945bf3f",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
],
|
],
|
||||||
"pinData": {},
|
"pinData": {},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "4f4c6527-d565-448a-96bd-8f5414caf8cc",
|
"id": "4f4c6527-d565-448a-96bd-8f5414caf8cc",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -136,7 +136,7 @@
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"id": "2acca986-10a6-451e-b20a-86e95b50e627",
|
"id": "2acca986-10a6-451e-b20a-86e95b50e627",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [460, 460]
|
"position": [460, 460]
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "09e4325e-ede1-40cf-a1ba-58612bbc7f1b",
|
"id": "09e4325e-ede1-40cf-a1ba-58612bbc7f1b",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "58512a93-dabf-4584-817f-27c608c1bdd5",
|
"id": "58512a93-dabf-4584-817f-27c608c1bdd5",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "3dc7cf26-ff25-4437-b9fd-0e8b127ebec9",
|
"id": "3dc7cf26-ff25-4437-b9fd-0e8b127ebec9",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -552,7 +552,7 @@
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "0a60e507-7f34-41c0-a0f9-697d852033b6",
|
"id": "0a60e507-7f34-41c0-a0f9-697d852033b6",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "8108d313-8b03-4aa4-963d-cd1c0fe8f85c",
|
"id": "8108d313-8b03-4aa4-963d-cd1c0fe8f85c",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "bcb6abdf-d34b-4ea7-a8ed-58155b708c43",
|
"id": "bcb6abdf-d34b-4ea7-a8ed-58155b708c43",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "25ff0c17-7064-4e14-aec6-45c71d63201b",
|
"id": "25ff0c17-7064-4e14-aec6-45c71d63201b",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "acdd1bdc-c642-4ea6-ad67-f4201b640cfa",
|
"id": "acdd1bdc-c642-4ea6-ad67-f4201b640cfa",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "40720511-19b6-4421-bdb0-3fb6efef4bc5",
|
"id": "40720511-19b6-4421-bdb0-3fb6efef4bc5",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -247,7 +247,7 @@ export class Agent implements INodeType {
|
||||||
alias: ['LangChain'],
|
alias: ['LangChain'],
|
||||||
categories: ['AI'],
|
categories: ['AI'],
|
||||||
subcategories: {
|
subcategories: {
|
||||||
AI: ['Agents'],
|
AI: ['Agents', 'Root Nodes'],
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
primaryDocumentation: [
|
primaryDocumentation: [
|
||||||
|
|
|
@ -31,7 +31,7 @@ export class OpenAiAssistant implements INodeType {
|
||||||
alias: ['LangChain'],
|
alias: ['LangChain'],
|
||||||
categories: ['AI'],
|
categories: ['AI'],
|
||||||
subcategories: {
|
subcategories: {
|
||||||
AI: ['Agents'],
|
AI: ['Agents', 'Root Nodes'],
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
primaryDocumentation: [
|
primaryDocumentation: [
|
||||||
|
|
|
@ -257,7 +257,7 @@ export class ChainLlm implements INodeType {
|
||||||
alias: ['LangChain'],
|
alias: ['LangChain'],
|
||||||
categories: ['AI'],
|
categories: ['AI'],
|
||||||
subcategories: {
|
subcategories: {
|
||||||
AI: ['Chains'],
|
AI: ['Chains', 'Root Nodes'],
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
primaryDocumentation: [
|
primaryDocumentation: [
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class ChainRetrievalQa implements INodeType {
|
||||||
alias: ['LangChain'],
|
alias: ['LangChain'],
|
||||||
categories: ['AI'],
|
categories: ['AI'],
|
||||||
subcategories: {
|
subcategories: {
|
||||||
AI: ['Chains'],
|
AI: ['Chains', 'Root Nodes'],
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
primaryDocumentation: [
|
primaryDocumentation: [
|
||||||
|
|
|
@ -16,7 +16,7 @@ export class ChainSummarization extends VersionedNodeType {
|
||||||
alias: ['LangChain'],
|
alias: ['LangChain'],
|
||||||
categories: ['AI'],
|
categories: ['AI'],
|
||||||
subcategories: {
|
subcategories: {
|
||||||
AI: ['Chains'],
|
AI: ['Chains', 'Root Nodes'],
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
primaryDocumentation: [
|
primaryDocumentation: [
|
||||||
|
|
|
@ -77,7 +77,7 @@ export class MemoryManager implements INodeType {
|
||||||
codex: {
|
codex: {
|
||||||
categories: ['AI'],
|
categories: ['AI'],
|
||||||
subcategories: {
|
subcategories: {
|
||||||
AI: ['Miscellaneous'],
|
AI: ['Miscellaneous', 'Root Nodes'],
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
primaryDocumentation: [
|
primaryDocumentation: [
|
||||||
|
|
|
@ -146,6 +146,79 @@ export class OutputParserStructured implements INodeType {
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Schema Type',
|
||||||
|
name: 'schemaType',
|
||||||
|
type: 'options',
|
||||||
|
noDataExpression: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Generate From JSON Example',
|
||||||
|
value: 'fromJson',
|
||||||
|
description: 'Generate a schema from an example JSON object',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Define Below',
|
||||||
|
value: 'manual',
|
||||||
|
description: 'Define the JSON schema manually',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'fromJson',
|
||||||
|
description: 'How to specify the schema for the function',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
'@version': [{ _cnd: { gte: 1.2 } }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'JSON Example',
|
||||||
|
name: 'jsonSchemaExample',
|
||||||
|
type: 'json',
|
||||||
|
default: `{
|
||||||
|
"state": "California",
|
||||||
|
"cities": ["Los Angeles", "San Francisco", "San Diego"]
|
||||||
|
}`,
|
||||||
|
noDataExpression: true,
|
||||||
|
typeOptions: {
|
||||||
|
rows: 10,
|
||||||
|
},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
schemaType: ['fromJson'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Example JSON object to use to generate the schema',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Input Schema',
|
||||||
|
name: 'inputSchema',
|
||||||
|
type: 'json',
|
||||||
|
default: `{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"state": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"cities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
noDataExpression: true,
|
||||||
|
typeOptions: {
|
||||||
|
rows: 10,
|
||||||
|
},
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
schemaType: ['manual'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Schema to use for the function',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
displayName: 'JSON Schema',
|
displayName: 'JSON Schema',
|
||||||
name: 'jsonSchema',
|
name: 'jsonSchema',
|
||||||
|
|
|
@ -34,9 +34,6 @@ export class ChatTrigger implements INodeType {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
subcategories: {
|
|
||||||
'Core Nodes': ['Other Trigger Nodes'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
supportsCORS: true,
|
supportsCORS: true,
|
||||||
maxNodes: 1,
|
maxNodes: 1,
|
||||||
|
|
|
@ -79,7 +79,7 @@ export const versionDescription: INodeTypeDescription = {
|
||||||
alias: ['LangChain', 'ChatGPT', 'DallE'],
|
alias: ['LangChain', 'ChatGPT', 'DallE'],
|
||||||
categories: ['AI'],
|
categories: ['AI'],
|
||||||
subcategories: {
|
subcategories: {
|
||||||
AI: ['Agents', 'Miscellaneous'],
|
AI: ['Agents', 'Miscellaneous', 'Root Nodes'],
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
primaryDocumentation: [
|
primaryDocumentation: [
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from '../../composables/useI18n';
|
import { useI18n } from '../../composables/useI18n';
|
||||||
|
import type { NodeCreatorTag } from '../../types/node-creator-node';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||||
import N8nTooltip from '../N8nTooltip';
|
import N8nTooltip from '../N8nTooltip';
|
||||||
import { ElTag } from 'element-plus';
|
import { ElTag } from 'element-plus';
|
||||||
|
@ -9,7 +10,7 @@ export interface Props {
|
||||||
isAi?: boolean;
|
isAi?: boolean;
|
||||||
isTrigger?: boolean;
|
isTrigger?: boolean;
|
||||||
description?: string;
|
description?: string;
|
||||||
tag?: string;
|
tag?: NodeCreatorTag;
|
||||||
title: string;
|
title: string;
|
||||||
showActionArrow?: boolean;
|
showActionArrow?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -37,8 +38,8 @@ const { t } = useI18n();
|
||||||
<div>
|
<div>
|
||||||
<div :class="$style.details">
|
<div :class="$style.details">
|
||||||
<span :class="$style.name" data-test-id="node-creator-item-name" v-text="title" />
|
<span :class="$style.name" data-test-id="node-creator-item-name" v-text="title" />
|
||||||
<ElTag v-if="tag" :class="$style.tag" size="small" round type="success">
|
<ElTag v-if="tag" :class="$style.tag" size="small" round :type="tag.type ?? 'success'">
|
||||||
{{ tag }}
|
{{ tag.text }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
v-if="isTrigger"
|
v-if="isTrigger"
|
||||||
|
@ -87,8 +88,16 @@ const { t } = useI18n();
|
||||||
.creatorNode:hover .panelIcon {
|
.creatorNode:hover .panelIcon {
|
||||||
color: var(--action-arrow-color-hover, var(--color-text-light));
|
color: var(--action-arrow-color-hover, var(--color-text-light));
|
||||||
}
|
}
|
||||||
.tag {
|
:root .tag {
|
||||||
margin-left: var(--spacing-2xs);
|
margin-left: var(--spacing-2xs);
|
||||||
|
line-height: var(--font-size-3xs);
|
||||||
|
font-size: var(--font-size-3xs);
|
||||||
|
padding: 0.1875rem var(--spacing-3xs) var(--spacing-4xs) var(--spacing-3xs);
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: var(--font-size-2xs) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.panelIcon {
|
.panelIcon {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
|
@ -8,3 +8,4 @@ export * from './menu';
|
||||||
export * from './select';
|
export * from './select';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
export * from './keyboardshortcut';
|
export * from './keyboardshortcut';
|
||||||
|
export * from './node-creator-node';
|
||||||
|
|
6
packages/design-system/src/types/node-creator-node.ts
Normal file
6
packages/design-system/src/types/node-creator-node.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import type { ElTag } from 'element-plus';
|
||||||
|
|
||||||
|
export type NodeCreatorTag = {
|
||||||
|
text: string;
|
||||||
|
type?: (typeof ElTag)['type'];
|
||||||
|
};
|
|
@ -9,7 +9,7 @@ import type {
|
||||||
VIEWS,
|
VIEWS,
|
||||||
ROLE,
|
ROLE,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import type { IMenuItem } from 'n8n-design-system';
|
import type { IMenuItem, NodeCreatorTag } from 'n8n-design-system';
|
||||||
import {
|
import {
|
||||||
type GenericValue,
|
type GenericValue,
|
||||||
type IConnections,
|
type IConnections,
|
||||||
|
@ -932,7 +932,9 @@ export type SimplifiedNodeType = Pick<
|
||||||
| 'codex'
|
| 'codex'
|
||||||
| 'defaults'
|
| 'defaults'
|
||||||
| 'outputs'
|
| 'outputs'
|
||||||
>;
|
> & {
|
||||||
|
tag?: string;
|
||||||
|
};
|
||||||
export interface SubcategoryItemProps {
|
export interface SubcategoryItemProps {
|
||||||
description?: string;
|
description?: string;
|
||||||
iconType?: string;
|
iconType?: string;
|
||||||
|
@ -951,11 +953,21 @@ export interface ViewItemProps {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
tag?: string;
|
tag?: NodeCreatorTag;
|
||||||
|
borderless?: boolean;
|
||||||
}
|
}
|
||||||
export interface LabelItemProps {
|
export interface LabelItemProps {
|
||||||
key: string;
|
key: string;
|
||||||
}
|
}
|
||||||
|
export interface LinkItemProps {
|
||||||
|
url: string;
|
||||||
|
key: string;
|
||||||
|
newTab?: boolean;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
icon: string;
|
||||||
|
tag?: NodeCreatorTag;
|
||||||
|
}
|
||||||
export interface ActionTypeDescription extends SimplifiedNodeType {
|
export interface ActionTypeDescription extends SimplifiedNodeType {
|
||||||
displayOptions?: IDisplayOptions;
|
displayOptions?: IDisplayOptions;
|
||||||
values?: IDataObject;
|
values?: IDataObject;
|
||||||
|
@ -1010,6 +1022,11 @@ export interface LabelCreateElement extends CreateElementBase {
|
||||||
properties: LabelItemProps;
|
properties: LabelItemProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LinkCreateElement extends CreateElementBase {
|
||||||
|
type: 'link';
|
||||||
|
properties: LinkItemProps;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ActionCreateElement extends CreateElementBase {
|
export interface ActionCreateElement extends CreateElementBase {
|
||||||
type: 'action';
|
type: 'action';
|
||||||
subcategory: string;
|
subcategory: string;
|
||||||
|
@ -1023,7 +1040,8 @@ export type INodeCreateElement =
|
||||||
| SectionCreateElement
|
| SectionCreateElement
|
||||||
| ViewCreateElement
|
| ViewCreateElement
|
||||||
| LabelCreateElement
|
| LabelCreateElement
|
||||||
| ActionCreateElement;
|
| ActionCreateElement
|
||||||
|
| LinkCreateElement;
|
||||||
|
|
||||||
export interface SubcategorizedNodeTypes {
|
export interface SubcategorizedNodeTypes {
|
||||||
[subcategory: string]: INodeCreateElement[];
|
[subcategory: string]: INodeCreateElement[];
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<template>
|
||||||
|
<n8n-node-creator-node
|
||||||
|
:class="$style.creatorLink"
|
||||||
|
:title="link.title"
|
||||||
|
:is-trigger="false"
|
||||||
|
:description="link.description"
|
||||||
|
:tag="link.tag"
|
||||||
|
:show-action-arrow="true"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n8n-node-icon type="icon" :name="link.icon" :circle="false" :show-tooltip="false" />
|
||||||
|
</template>
|
||||||
|
</n8n-node-creator-node>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { LinkItemProps } from '@/Interface';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
link: LinkItemProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.creatorLink {
|
||||||
|
--action-arrow-color: var(--color-text-light);
|
||||||
|
margin-left: var(--spacing-s);
|
||||||
|
margin-right: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,6 +8,7 @@
|
||||||
:show-action-arrow="showActionArrow"
|
:show-action-arrow="showActionArrow"
|
||||||
:is-trigger="isTrigger"
|
:is-trigger="isTrigger"
|
||||||
:data-test-id="dataTestId"
|
:data-test-id="dataTestId"
|
||||||
|
:tag="nodeType.tag"
|
||||||
@dragstart="onDragStart"
|
@dragstart="onDragStart"
|
||||||
@dragend="onDragEnd"
|
@dragend="onDragEnd"
|
||||||
>
|
>
|
||||||
|
|
|
@ -139,6 +139,13 @@ function onSelected(item: INodeCreateElement) {
|
||||||
searchItems: mergedNodes,
|
searchItems: mergedNodes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.type === 'link') {
|
||||||
|
window.open(item.properties.url, '_blank');
|
||||||
|
telemetry.trackNodesPanel('nodeCreateList.onLinkSelected', {
|
||||||
|
link: item.properties.url,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function subcategoriesMapper(item: INodeCreateElement) {
|
function subcategoriesMapper(item: INodeCreateElement) {
|
||||||
|
@ -195,13 +202,13 @@ function onKeySelect(activeItemId: string) {
|
||||||
|
|
||||||
registerKeyHook('MainViewArrowRight', {
|
registerKeyHook('MainViewArrowRight', {
|
||||||
keyboardKeys: ['ArrowRight', 'Enter'],
|
keyboardKeys: ['ArrowRight', 'Enter'],
|
||||||
condition: (type) => ['subcategory', 'node', 'view'].includes(type),
|
condition: (type) => ['subcategory', 'node', 'link', 'view'].includes(type),
|
||||||
handler: onKeySelect,
|
handler: onKeySelect,
|
||||||
});
|
});
|
||||||
|
|
||||||
registerKeyHook('MainViewArrowLeft', {
|
registerKeyHook('MainViewArrowLeft', {
|
||||||
keyboardKeys: ['ArrowLeft'],
|
keyboardKeys: ['ArrowLeft'],
|
||||||
condition: (type) => ['subcategory', 'node', 'view'].includes(type),
|
condition: (type) => ['subcategory', 'node', 'link', 'view'].includes(type),
|
||||||
handler: arrowLeft,
|
handler: arrowLeft,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import SubcategoryItem from '../ItemTypes/SubcategoryItem.vue';
|
||||||
import LabelItem from '../ItemTypes/LabelItem.vue';
|
import LabelItem from '../ItemTypes/LabelItem.vue';
|
||||||
import ActionItem from '../ItemTypes/ActionItem.vue';
|
import ActionItem from '../ItemTypes/ActionItem.vue';
|
||||||
import ViewItem from '../ItemTypes/ViewItem.vue';
|
import ViewItem from '../ItemTypes/ViewItem.vue';
|
||||||
|
import LinkItem from '../ItemTypes/LinkItem.vue';
|
||||||
import CategorizedItemsRenderer from './CategorizedItemsRenderer.vue';
|
import CategorizedItemsRenderer from './CategorizedItemsRenderer.vue';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -147,6 +148,8 @@ watch(
|
||||||
[$style.active]: activeItemId === item.uuid,
|
[$style.active]: activeItemId === item.uuid,
|
||||||
[$style.iteratorItem]: true,
|
[$style.iteratorItem]: true,
|
||||||
[$style[item.type]]: true,
|
[$style[item.type]]: true,
|
||||||
|
// Borderless is only applied to views
|
||||||
|
[$style.borderless]: item.type === 'view' && item.properties.borderless === true,
|
||||||
}"
|
}"
|
||||||
data-test-id="item-iterator-item"
|
data-test-id="item-iterator-item"
|
||||||
:data-keyboard-nav-type="item.type !== 'label' ? item.type : undefined"
|
:data-keyboard-nav-type="item.type !== 'label' ? item.type : undefined"
|
||||||
|
@ -175,6 +178,12 @@ watch(
|
||||||
:view="item.properties"
|
:view="item.properties"
|
||||||
:class="$style.viewItem"
|
:class="$style.viewItem"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<LinkItem
|
||||||
|
v-else-if="item.type === 'link'"
|
||||||
|
:link="item.properties"
|
||||||
|
:class="$style.linkItem"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<n8n-loading v-else :loading="true" :rows="1" variant="p" :class="$style.itemSkeleton" />
|
<n8n-loading v-else :loading="true" :rows="1" variant="p" :class="$style.itemSkeleton" />
|
||||||
|
@ -223,12 +232,14 @@ watch(
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.view {
|
.view {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-top: var(--spacing-s);
|
margin-top: var(--spacing-s);
|
||||||
padding-top: var(--spacing-xs);
|
padding-top: var(--spacing-xs);
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -241,4 +252,34 @@ watch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.link {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: var(--spacing-s);
|
||||||
|
padding-bottom: var(--spacing-xs);
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: var(--spacing-s);
|
||||||
|
right: var(--spacing-s);
|
||||||
|
top: 0;
|
||||||
|
margin: auto;
|
||||||
|
bottom: 0;
|
||||||
|
border-bottom: 1px solid var(--color-foreground-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.borderless {
|
||||||
|
&:last-child {
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -76,7 +76,7 @@ describe('NodesListPanel', () => {
|
||||||
await fireEvent.click(container.querySelector('.backButton')!);
|
await fireEvent.click(container.querySelector('.backButton')!);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(screen.queryAllByTestId('item-iterator-item')).toHaveLength(7);
|
expect(screen.queryAllByTestId('item-iterator-item')).toHaveLength(8);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render regular nodes', async () => {
|
it('should render regular nodes', async () => {
|
||||||
|
@ -136,7 +136,7 @@ describe('NodesListPanel', () => {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(screen.getByText('What happens next?')).toBeInTheDocument();
|
expect(screen.getByText('What happens next?')).toBeInTheDocument();
|
||||||
expect(screen.queryAllByTestId('item-iterator-item')).toHaveLength(6);
|
expect(screen.queryAllByTestId('item-iterator-item')).toHaveLength(5);
|
||||||
|
|
||||||
screen.getByText('Action in an app').click();
|
screen.getByText('Action in an app').click();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
|
@ -1,19 +1,29 @@
|
||||||
import type { INodeCreateElement, NodeFilterType, SimplifiedNodeType } from '@/Interface';
|
import type {
|
||||||
|
INodeCreateElement,
|
||||||
|
NodeCreateElement,
|
||||||
|
NodeFilterType,
|
||||||
|
SimplifiedNodeType,
|
||||||
|
} from '@/Interface';
|
||||||
import {
|
import {
|
||||||
|
AI_CATEGORY_ROOT_NODES,
|
||||||
AI_CODE_NODE_TYPE,
|
AI_CODE_NODE_TYPE,
|
||||||
|
AI_NODE_CREATOR_VIEW,
|
||||||
AI_OTHERS_NODE_CREATOR_VIEW,
|
AI_OTHERS_NODE_CREATOR_VIEW,
|
||||||
|
AI_SUBCATEGORY,
|
||||||
DEFAULT_SUBCATEGORY,
|
DEFAULT_SUBCATEGORY,
|
||||||
TRIGGER_NODE_CREATOR_VIEW,
|
TRIGGER_NODE_CREATOR_VIEW,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { computed, nextTick, ref } from 'vue';
|
import { computed, nextTick, ref } from 'vue';
|
||||||
|
import difference from 'lodash-es/difference';
|
||||||
|
|
||||||
import { useNodeCreatorStore } from '@/stores/nodeCreator.store';
|
import { useNodeCreatorStore } from '@/stores/nodeCreator.store';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
flattenCreateElements,
|
flattenCreateElements,
|
||||||
groupItemsInSections,
|
groupItemsInSections,
|
||||||
|
isAINode,
|
||||||
searchNodes,
|
searchNodes,
|
||||||
sortNodeCreateElements,
|
sortNodeCreateElements,
|
||||||
subcategorizeItems,
|
subcategorizeItems,
|
||||||
|
@ -27,6 +37,7 @@ import { useKeyboardNavigation } from './useKeyboardNavigation';
|
||||||
|
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import type { INodeInputFilter, NodeConnectionType } from 'n8n-workflow';
|
import type { INodeInputFilter, NodeConnectionType } from 'n8n-workflow';
|
||||||
|
import { useCanvasStore } from '@/stores/canvas.store';
|
||||||
|
|
||||||
interface ViewStack {
|
interface ViewStack {
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
|
@ -60,11 +71,12 @@ interface ViewStack {
|
||||||
export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
|
export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
|
||||||
const nodeCreatorStore = useNodeCreatorStore();
|
const nodeCreatorStore = useNodeCreatorStore();
|
||||||
const { getActiveItemIndex } = useKeyboardNavigation();
|
const { getActiveItemIndex } = useKeyboardNavigation();
|
||||||
|
const i18n = useI18n();
|
||||||
|
|
||||||
const viewStacks = ref<ViewStack[]>([]);
|
const viewStacks = ref<ViewStack[]>([]);
|
||||||
|
|
||||||
const activeStackItems = computed<INodeCreateElement[]>(() => {
|
const activeStackItems = computed<INodeCreateElement[]>(() => {
|
||||||
const stack = viewStacks.value[viewStacks.value.length - 1];
|
const stack = getLastActiveStack();
|
||||||
|
|
||||||
if (!stack?.baselineItems) {
|
if (!stack?.baselineItems) {
|
||||||
return stack.items ? extendItemsWithUUID(stack.items) : [];
|
return stack.items ? extendItemsWithUUID(stack.items) : [];
|
||||||
|
@ -76,13 +88,24 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
|
||||||
? searchBaseItems.value
|
? searchBaseItems.value
|
||||||
: flattenCreateElements(stack.baselineItems ?? []);
|
: flattenCreateElements(stack.baselineItems ?? []);
|
||||||
|
|
||||||
return extendItemsWithUUID(searchNodes(stack.search || '', searchBase));
|
const canvasHasAINodes = useCanvasStore().aiNodes.length > 0;
|
||||||
|
const filteredNodes =
|
||||||
|
isAiRootView(stack) || canvasHasAINodes ? searchBase : filterOutAiNodes(searchBase);
|
||||||
|
|
||||||
|
const searchResults = extendItemsWithUUID(searchNodes(stack.search || '', filteredNodes));
|
||||||
|
|
||||||
|
const groupedNodes = groupIfAiNodes(searchResults, false) ?? searchResults;
|
||||||
|
// Set the active index to the second item if there's a section
|
||||||
|
// as the first item is collapsable
|
||||||
|
stack.activeIndex = groupedNodes.some((node) => node.type === 'section') ? 1 : 0;
|
||||||
|
|
||||||
|
return groupedNodes;
|
||||||
}
|
}
|
||||||
return extendItemsWithUUID(stack.baselineItems);
|
return extendItemsWithUUID(groupIfAiNodes(stack.baselineItems, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
const activeViewStack = computed<ViewStack>(() => {
|
const activeViewStack = computed<ViewStack>(() => {
|
||||||
const stack = viewStacks.value[viewStacks.value.length - 1];
|
const stack = getLastActiveStack();
|
||||||
if (!stack) return {};
|
if (!stack) return {};
|
||||||
|
|
||||||
const flatBaselineItems = flattenCreateElements(stack.baselineItems ?? []);
|
const flatBaselineItems = flattenCreateElements(stack.baselineItems ?? []);
|
||||||
|
@ -99,34 +122,148 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const searchBaseItems = computed<INodeCreateElement[]>(() => {
|
const searchBaseItems = computed<INodeCreateElement[]>(() => {
|
||||||
const stack = viewStacks.value[viewStacks.value.length - 1];
|
const stack = getLastActiveStack();
|
||||||
if (!stack?.searchItems) return [];
|
if (!stack?.searchItems) return [];
|
||||||
|
|
||||||
return stack.searchItems.map((item) => transformNodeType(item, stack.subcategory));
|
return stack.searchItems.map((item) => transformNodeType(item, stack.subcategory));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getLastActiveStack() {
|
||||||
|
return viewStacks.value[viewStacks.value.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
// Generate a delta between the global search results(all nodes) and the stack search results
|
// Generate a delta between the global search results(all nodes) and the stack search results
|
||||||
const globalSearchItemsDiff = computed<INodeCreateElement[]>(() => {
|
const globalSearchItemsDiff = computed<INodeCreateElement[]>(() => {
|
||||||
const stack = viewStacks.value[viewStacks.value.length - 1];
|
const stack = getLastActiveStack();
|
||||||
if (!stack?.search) return [];
|
if (!stack?.search) return [];
|
||||||
|
|
||||||
const allNodes = nodeCreatorStore.mergedNodes.map((item) => transformNodeType(item));
|
const allNodes = nodeCreatorStore.mergedNodes.map((item) => transformNodeType(item));
|
||||||
const globalSearchResult = extendItemsWithUUID(searchNodes(stack.search || '', allNodes));
|
// Apply filtering for AI nodes if the current view is not the AI root view
|
||||||
|
const filteredNodes = isAiRootView(stack) ? allNodes : filterOutAiNodes(allNodes);
|
||||||
|
|
||||||
return globalSearchResult.filter((item) => {
|
let globalSearchResult: INodeCreateElement[] = extendItemsWithUUID(
|
||||||
return !activeStackItems.value.find((activeItem) => activeItem.key === item.key);
|
searchNodes(stack.search || '', filteredNodes),
|
||||||
|
);
|
||||||
|
if (isAiRootView(stack)) {
|
||||||
|
globalSearchResult = groupIfAiNodes(globalSearchResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredItems = globalSearchResult.filter((item) => {
|
||||||
|
return !activeStackItems.value.find((activeItem) => {
|
||||||
|
if (activeItem.type === 'section') {
|
||||||
|
const matchingSectionItem = activeItem.children.some(
|
||||||
|
(sectionItem) => sectionItem.key === item.key,
|
||||||
|
);
|
||||||
|
return matchingSectionItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeItem.key === item.key;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Filter out empty sections if all of their children are filtered out
|
||||||
|
const filteredSections = filteredItems.filter((item) => {
|
||||||
|
if (item.type === 'section') {
|
||||||
|
const hasVisibleChildren = item.children.some((child) =>
|
||||||
|
activeStackItems.value.some((filteredItem) => filteredItem.key === child.key),
|
||||||
|
);
|
||||||
|
|
||||||
|
return hasVisibleChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return filteredSections;
|
||||||
|
});
|
||||||
|
|
||||||
const itemsBySubcategory = computed(() => subcategorizeItems(nodeCreatorStore.mergedNodes));
|
const itemsBySubcategory = computed(() => subcategorizeItems(nodeCreatorStore.mergedNodes));
|
||||||
|
|
||||||
|
function isAiRootView(stack: ViewStack) {
|
||||||
|
return stack.rootView === AI_NODE_CREATOR_VIEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupIfAiNodes(items: INodeCreateElement[], sortAlphabetically = true) {
|
||||||
|
const aiNodes = items.filter((node): node is NodeCreateElement => isAINode(node));
|
||||||
|
|
||||||
|
if (aiNodes.length > 0) {
|
||||||
|
const sectionsMap = new Map<string, NodeViewItemSection>();
|
||||||
|
aiNodes.forEach((node) => {
|
||||||
|
const section = node.properties.codex?.subcategories?.[AI_SUBCATEGORY]?.[0];
|
||||||
|
|
||||||
|
if (section) {
|
||||||
|
const currentItems = sectionsMap.get(section)?.items ?? [];
|
||||||
|
const isSubnodesSection =
|
||||||
|
!node.properties.codex?.subcategories?.[AI_SUBCATEGORY].includes(
|
||||||
|
AI_CATEGORY_ROOT_NODES,
|
||||||
|
);
|
||||||
|
|
||||||
|
sectionsMap.set(section, {
|
||||||
|
key: section,
|
||||||
|
title: isSubnodesSection
|
||||||
|
? `${section} (${i18n.baseText('nodeCreator.subnodes')})`
|
||||||
|
: section,
|
||||||
|
items: [...currentItems, node.key],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const nonAiNodes = difference(items, aiNodes);
|
||||||
|
const nonAiTriggerNodes = nonAiNodes.filter(
|
||||||
|
(item) => item.type === 'node' && useNodeTypesStore().isTriggerNode(item.properties.name),
|
||||||
|
);
|
||||||
|
|
||||||
|
const nonAiRegularNodes = difference(nonAiNodes, nonAiTriggerNodes);
|
||||||
|
|
||||||
|
if (nonAiNodes.length > 0) {
|
||||||
|
let sectionKey = '';
|
||||||
|
if (nonAiRegularNodes.length && nonAiTriggerNodes.length) {
|
||||||
|
sectionKey = i18n.baseText('nodeCreator.actionsCategory.regularAndTriggers');
|
||||||
|
} else {
|
||||||
|
sectionKey = nonAiRegularNodes.length
|
||||||
|
? i18n.baseText('nodeCreator.actionsCategory.regularNodes')
|
||||||
|
: i18n.baseText('nodeCreator.actionsCategory.triggerNodes');
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodesKeys = nonAiNodes.map((node) => node.key);
|
||||||
|
|
||||||
|
sectionsMap.set(sectionKey, {
|
||||||
|
key: sectionKey,
|
||||||
|
title: sectionKey,
|
||||||
|
items: [...nodesKeys],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Convert sectionsMap to array of sections
|
||||||
|
const sections = Array.from(sectionsMap.values());
|
||||||
|
|
||||||
|
return groupItemsInSections(items, sections, sortAlphabetically);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterOutAiNodes(items: INodeCreateElement[]) {
|
||||||
|
const filteredSearchBase = items.filter((item) => {
|
||||||
|
if (item.type === 'node') {
|
||||||
|
const isAICategory = item.properties.codex?.categories?.includes(AI_SUBCATEGORY) === true;
|
||||||
|
|
||||||
|
if (!isAICategory) return true;
|
||||||
|
|
||||||
|
const isRootNodeSubcategory =
|
||||||
|
item.properties.codex?.subcategories?.[AI_SUBCATEGORY]?.includes(AI_CATEGORY_ROOT_NODES);
|
||||||
|
|
||||||
|
return isRootNodeSubcategory;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return filteredSearchBase;
|
||||||
|
}
|
||||||
|
|
||||||
async function gotoCompatibleConnectionView(
|
async function gotoCompatibleConnectionView(
|
||||||
connectionType: NodeConnectionType,
|
connectionType: NodeConnectionType,
|
||||||
isOutput?: boolean,
|
isOutput?: boolean,
|
||||||
filter?: INodeInputFilter,
|
filter?: INodeInputFilter,
|
||||||
) {
|
) {
|
||||||
const i18n = useI18n();
|
|
||||||
|
|
||||||
let nodesByConnectionType: { [key: string]: string[] };
|
let nodesByConnectionType: { [key: string]: string[] };
|
||||||
let relatedAIView: { properties: NodeViewItem['properties'] } | undefined;
|
let relatedAIView: { properties: NodeViewItem['properties'] } | undefined;
|
||||||
|
|
||||||
|
@ -185,7 +322,7 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStackBaselineItems() {
|
function setStackBaselineItems() {
|
||||||
const stack = viewStacks.value[viewStacks.value.length - 1];
|
const stack = getLastActiveStack();
|
||||||
if (!stack || !activeViewStack.value.uuid) return;
|
if (!stack || !activeViewStack.value.uuid) return;
|
||||||
|
|
||||||
let stackItems = stack?.items ?? [];
|
let stackItems = stack?.items ?? [];
|
||||||
|
@ -258,7 +395,7 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCurrentViewStack(stack: Partial<ViewStack>) {
|
function updateCurrentViewStack(stack: Partial<ViewStack>) {
|
||||||
const currentStack = viewStacks.value[viewStacks.value.length - 1];
|
const currentStack = getLastActiveStack();
|
||||||
const matchedIndex = viewStacks.value.findIndex((s) => s.uuid === currentStack.uuid);
|
const matchedIndex = viewStacks.value.findIndex((s) => s.uuid === currentStack.uuid);
|
||||||
if (!currentStack) return;
|
if (!currentStack) return;
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,18 @@ import type {
|
||||||
INodeCreateElement,
|
INodeCreateElement,
|
||||||
SectionCreateElement,
|
SectionCreateElement,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
import { AI_SUBCATEGORY, CORE_NODES_CATEGORY, DEFAULT_SUBCATEGORY } from '@/constants';
|
import {
|
||||||
|
AI_CATEGORY_AGENTS,
|
||||||
|
AI_SUBCATEGORY,
|
||||||
|
CORE_NODES_CATEGORY,
|
||||||
|
DEFAULT_SUBCATEGORY,
|
||||||
|
} from '@/constants';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { sublimeSearch } from '@/utils/sortUtils';
|
import { sublimeSearch } from '@/utils/sortUtils';
|
||||||
import { i18n } from '@/plugins/i18n';
|
|
||||||
import type { NodeViewItemSection } from './viewsData';
|
import type { NodeViewItemSection } from './viewsData';
|
||||||
|
import { i18n } from '@/plugins/i18n';
|
||||||
|
import { sortBy } from 'lodash-es';
|
||||||
|
|
||||||
export function transformNodeType(
|
export function transformNodeType(
|
||||||
node: SimplifiedNodeType,
|
node: SimplifiedNodeType,
|
||||||
|
@ -70,6 +76,7 @@ export function sortNodeCreateElements(nodes: INodeCreateElement[]) {
|
||||||
export function searchNodes(searchFilter: string, items: INodeCreateElement[]) {
|
export function searchNodes(searchFilter: string, items: INodeCreateElement[]) {
|
||||||
// In order to support the old search we need to remove the 'trigger' part
|
// In order to support the old search we need to remove the 'trigger' part
|
||||||
const trimmedFilter = searchFilter.toLowerCase().replace('trigger', '').trimEnd();
|
const trimmedFilter = searchFilter.toLowerCase().replace('trigger', '').trimEnd();
|
||||||
|
|
||||||
const result = (
|
const result = (
|
||||||
sublimeSearch<INodeCreateElement>(trimmedFilter, items, [
|
sublimeSearch<INodeCreateElement>(trimmedFilter, items, [
|
||||||
{ key: 'properties.displayName', weight: 1.3 },
|
{ key: 'properties.displayName', weight: 1.3 },
|
||||||
|
@ -83,38 +90,72 @@ export function searchNodes(searchFilter: string, items: INodeCreateElement[]) {
|
||||||
export function flattenCreateElements(items: INodeCreateElement[]): INodeCreateElement[] {
|
export function flattenCreateElements(items: INodeCreateElement[]): INodeCreateElement[] {
|
||||||
return items.map((item) => (item.type === 'section' ? item.children : item)).flat();
|
return items.map((item) => (item.type === 'section' ? item.children : item)).flat();
|
||||||
}
|
}
|
||||||
|
export function isAINode(node: INodeCreateElement) {
|
||||||
|
const isNode = node.type === 'node';
|
||||||
|
if (!isNode) return false;
|
||||||
|
|
||||||
|
if (node.properties.codex?.categories?.includes(AI_SUBCATEGORY)) {
|
||||||
|
const isAgentSubcategory =
|
||||||
|
node.properties.codex?.subcategories?.[AI_SUBCATEGORY]?.includes(AI_CATEGORY_AGENTS);
|
||||||
|
|
||||||
|
return !isAgentSubcategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
export function groupItemsInSections(
|
export function groupItemsInSections(
|
||||||
items: INodeCreateElement[],
|
items: INodeCreateElement[],
|
||||||
sections: string[] | NodeViewItemSection[],
|
sections: string[] | NodeViewItemSection[],
|
||||||
|
sortAlphabetically = true,
|
||||||
): INodeCreateElement[] {
|
): INodeCreateElement[] {
|
||||||
const filteredSections = sections.filter(
|
const filteredSections = sections.filter(
|
||||||
(section): section is NodeViewItemSection => typeof section === 'object',
|
(section): section is NodeViewItemSection => typeof section === 'object',
|
||||||
);
|
);
|
||||||
|
|
||||||
const itemsBySection = items.reduce((acc: Record<string, INodeCreateElement[]>, item) => {
|
const itemsBySection = (items2: INodeCreateElement[]) =>
|
||||||
|
items2.reduce((acc: Record<string, INodeCreateElement[]>, item) => {
|
||||||
const section = filteredSections.find((s) => s.items.includes(item.key));
|
const section = filteredSections.find((s) => s.items.includes(item.key));
|
||||||
|
|
||||||
const key = section?.key ?? 'other';
|
const key = section?.key ?? 'other';
|
||||||
|
if (key) {
|
||||||
acc[key] = [...(acc[key] ?? []), item];
|
acc[key] = [...(acc[key] ?? []), item];
|
||||||
|
}
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const result: SectionCreateElement[] = filteredSections
|
const mapNewSections = (
|
||||||
.map(
|
newSections: NodeViewItemSection[],
|
||||||
|
children: Record<string, INodeCreateElement[]>,
|
||||||
|
) =>
|
||||||
|
newSections.map(
|
||||||
(section): SectionCreateElement => ({
|
(section): SectionCreateElement => ({
|
||||||
type: 'section',
|
type: 'section',
|
||||||
key: section.key,
|
key: section.key,
|
||||||
title: section.title,
|
title: section.title,
|
||||||
children: sortNodeCreateElements(itemsBySection[section.key] ?? []),
|
children: sortAlphabetically
|
||||||
|
? sortNodeCreateElements(children[section.key] ?? [])
|
||||||
|
: children[section.key] ?? [],
|
||||||
}),
|
}),
|
||||||
)
|
);
|
||||||
|
|
||||||
|
const nonAINodes = items.filter((item) => !isAINode(item));
|
||||||
|
const AINodes = items.filter((item) => isAINode(item));
|
||||||
|
|
||||||
|
const nonAINodesBySection = itemsBySection(nonAINodes);
|
||||||
|
const nonAINodesSections = mapNewSections(filteredSections, nonAINodesBySection);
|
||||||
|
|
||||||
|
const AINodesBySection = itemsBySection(AINodes);
|
||||||
|
|
||||||
|
const AINodesSections = mapNewSections(sortBy(filteredSections, ['title']), AINodesBySection);
|
||||||
|
|
||||||
|
const result = [...nonAINodesSections, ...AINodesSections]
|
||||||
.concat({
|
.concat({
|
||||||
type: 'section',
|
type: 'section',
|
||||||
key: 'other',
|
key: 'other',
|
||||||
title: i18n.baseText('nodeCreator.sectionNames.other'),
|
title: i18n.baseText('nodeCreator.sectionNames.other'),
|
||||||
children: sortNodeCreateElements(itemsBySection.other ?? []),
|
children: sortNodeCreateElements(nonAINodesBySection.other ?? []),
|
||||||
})
|
})
|
||||||
.filter((section) => section.children.length > 0);
|
.filter((section) => section.type !== 'section' || section.children.length > 0);
|
||||||
|
|
||||||
if (result.length <= 1) {
|
if (result.length <= 1) {
|
||||||
return items;
|
return items;
|
||||||
|
|
|
@ -5,10 +5,10 @@ import {
|
||||||
EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||||
FORM_TRIGGER_NODE_TYPE,
|
FORM_TRIGGER_NODE_TYPE,
|
||||||
MANUAL_TRIGGER_NODE_TYPE,
|
MANUAL_TRIGGER_NODE_TYPE,
|
||||||
|
MANUAL_CHAT_TRIGGER_NODE_TYPE,
|
||||||
SCHEDULE_TRIGGER_NODE_TYPE,
|
SCHEDULE_TRIGGER_NODE_TYPE,
|
||||||
REGULAR_NODE_CREATOR_VIEW,
|
REGULAR_NODE_CREATOR_VIEW,
|
||||||
TRANSFORM_DATA_SUBCATEGORY,
|
TRANSFORM_DATA_SUBCATEGORY,
|
||||||
FILES_SUBCATEGORY,
|
|
||||||
FLOWS_CONTROL_SUBCATEGORY,
|
FLOWS_CONTROL_SUBCATEGORY,
|
||||||
TRIGGER_NODE_CREATOR_VIEW,
|
TRIGGER_NODE_CREATOR_VIEW,
|
||||||
EMAIL_IMAP_NODE_TYPE,
|
EMAIL_IMAP_NODE_TYPE,
|
||||||
|
@ -52,6 +52,8 @@ import {
|
||||||
EMAIL_SEND_NODE_TYPE,
|
EMAIL_SEND_NODE_TYPE,
|
||||||
EDIT_IMAGE_NODE_TYPE,
|
EDIT_IMAGE_NODE_TYPE,
|
||||||
COMPRESSION_NODE_TYPE,
|
COMPRESSION_NODE_TYPE,
|
||||||
|
AI_CODE_TOOL_LANGCHAIN_NODE_TYPE,
|
||||||
|
AI_WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
|
@ -76,13 +78,17 @@ export interface NodeViewItem {
|
||||||
iconProps?: {
|
iconProps?: {
|
||||||
color?: string;
|
color?: string;
|
||||||
};
|
};
|
||||||
|
url?: string;
|
||||||
connectionType?: NodeConnectionType;
|
connectionType?: NodeConnectionType;
|
||||||
panelClass?: string;
|
panelClass?: string;
|
||||||
group?: string[];
|
group?: string[];
|
||||||
sections?: NodeViewItemSection[];
|
sections?: NodeViewItemSection[];
|
||||||
description?: string;
|
description?: string;
|
||||||
displayName?: string;
|
displayName?: string;
|
||||||
tag?: string;
|
tag?: {
|
||||||
|
type: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
forceIncludeNodes?: string[];
|
forceIncludeNodes?: string[];
|
||||||
iconData?: {
|
iconData?: {
|
||||||
type: string;
|
type: string;
|
||||||
|
@ -141,12 +147,24 @@ export function AIView(_nodes: SimplifiedNodeType[]): NodeView {
|
||||||
value: AI_NODE_CREATOR_VIEW,
|
value: AI_NODE_CREATOR_VIEW,
|
||||||
title: i18n.baseText('nodeCreator.aiPanel.aiNodes'),
|
title: i18n.baseText('nodeCreator.aiPanel.aiNodes'),
|
||||||
subtitle: i18n.baseText('nodeCreator.aiPanel.selectAiNode'),
|
subtitle: i18n.baseText('nodeCreator.aiPanel.selectAiNode'),
|
||||||
info: i18n.baseText('nodeCreator.aiPanel.infoBox', {
|
|
||||||
interpolate: { link: templatesStore.getWebsiteCategoryURL('ai') },
|
|
||||||
}),
|
|
||||||
items: [
|
items: [
|
||||||
...chainNodes,
|
{
|
||||||
|
key: 'ai_templates_root',
|
||||||
|
type: 'link',
|
||||||
|
properties: {
|
||||||
|
title: i18n.baseText('nodeCreator.aiPanel.linkItem.title'),
|
||||||
|
icon: 'box-open',
|
||||||
|
description: i18n.baseText('nodeCreator.aiPanel.linkItem.description'),
|
||||||
|
name: 'ai_templates_root',
|
||||||
|
url: templatesStore.getWebsiteCategoryURL(undefined, 'AdvancedAI'),
|
||||||
|
tag: {
|
||||||
|
type: 'info',
|
||||||
|
text: i18n.baseText('nodeCreator.triggerHelperPanel.manualTriggerTag'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
...agentNodes,
|
...agentNodes,
|
||||||
|
...chainNodes,
|
||||||
{
|
{
|
||||||
key: AI_OTHERS_NODE_CREATOR_VIEW,
|
key: AI_OTHERS_NODE_CREATOR_VIEW,
|
||||||
type: 'view',
|
type: 'view',
|
||||||
|
@ -159,6 +177,7 @@ export function AIView(_nodes: SimplifiedNodeType[]): NodeView {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
|
export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
@ -232,12 +251,20 @@ export function AINodesView(_nodes: SimplifiedNodeType[]): NodeView {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: AI_CATEGORY_TOOLS,
|
|
||||||
type: 'subcategory',
|
type: 'subcategory',
|
||||||
|
key: AI_CATEGORY_TOOLS,
|
||||||
|
category: CORE_NODES_CATEGORY,
|
||||||
properties: {
|
properties: {
|
||||||
title: AI_CATEGORY_TOOLS,
|
title: AI_CATEGORY_TOOLS,
|
||||||
icon: 'tools',
|
icon: 'tools',
|
||||||
...getAISubcategoryProperties(NodeConnectionType.AiTool),
|
...getAISubcategoryProperties(NodeConnectionType.AiTool),
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
key: 'popular',
|
||||||
|
title: i18n.baseText('nodeCreator.sectionNames.popular'),
|
||||||
|
items: [AI_WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE, AI_CODE_TOOL_LANGCHAIN_NODE_TYPE],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -278,6 +305,18 @@ export function TriggerView() {
|
||||||
title: i18n.baseText('nodeCreator.triggerHelperPanel.selectATrigger'),
|
title: i18n.baseText('nodeCreator.triggerHelperPanel.selectATrigger'),
|
||||||
subtitle: i18n.baseText('nodeCreator.triggerHelperPanel.selectATriggerDescription'),
|
subtitle: i18n.baseText('nodeCreator.triggerHelperPanel.selectATriggerDescription'),
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
key: MANUAL_TRIGGER_NODE_TYPE,
|
||||||
|
type: 'node',
|
||||||
|
category: [CORE_NODES_CATEGORY],
|
||||||
|
properties: {
|
||||||
|
group: [],
|
||||||
|
name: MANUAL_TRIGGER_NODE_TYPE,
|
||||||
|
displayName: i18n.baseText('nodeCreator.triggerHelperPanel.manualTriggerDisplayName'),
|
||||||
|
description: i18n.baseText('nodeCreator.triggerHelperPanel.manualTriggerDescription'),
|
||||||
|
icon: 'fa:mouse-pointer',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: DEFAULT_SUBCATEGORY,
|
key: DEFAULT_SUBCATEGORY,
|
||||||
type: 'subcategory',
|
type: 'subcategory',
|
||||||
|
@ -331,18 +370,6 @@ export function TriggerView() {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: MANUAL_TRIGGER_NODE_TYPE,
|
|
||||||
type: 'node',
|
|
||||||
category: [CORE_NODES_CATEGORY],
|
|
||||||
properties: {
|
|
||||||
group: [],
|
|
||||||
name: MANUAL_TRIGGER_NODE_TYPE,
|
|
||||||
displayName: i18n.baseText('nodeCreator.triggerHelperPanel.manualTriggerDisplayName'),
|
|
||||||
description: i18n.baseText('nodeCreator.triggerHelperPanel.manualTriggerDescription'),
|
|
||||||
icon: 'fa:mouse-pointer',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
key: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||||
type: 'node',
|
type: 'node',
|
||||||
|
@ -355,6 +382,18 @@ export function TriggerView() {
|
||||||
icon: 'fa:sign-out-alt',
|
icon: 'fa:sign-out-alt',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: MANUAL_CHAT_TRIGGER_NODE_TYPE,
|
||||||
|
type: 'node',
|
||||||
|
category: [CORE_NODES_CATEGORY],
|
||||||
|
properties: {
|
||||||
|
group: [],
|
||||||
|
name: MANUAL_CHAT_TRIGGER_NODE_TYPE,
|
||||||
|
displayName: i18n.baseText('nodeCreator.triggerHelperPanel.manualChatTriggerDisplayName'),
|
||||||
|
description: i18n.baseText('nodeCreator.triggerHelperPanel.manualChatTriggerDescription'),
|
||||||
|
icon: 'fa:comments',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'subcategory',
|
type: 'subcategory',
|
||||||
key: OTHER_TRIGGER_NODES_SUBCATEGORY,
|
key: OTHER_TRIGGER_NODES_SUBCATEGORY,
|
||||||
|
@ -447,22 +486,6 @@ export function RegularView(nodes: SimplifiedNodeType[]) {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: 'subcategory',
|
|
||||||
key: FILES_SUBCATEGORY,
|
|
||||||
category: CORE_NODES_CATEGORY,
|
|
||||||
properties: {
|
|
||||||
title: FILES_SUBCATEGORY,
|
|
||||||
icon: 'file-alt',
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
key: 'popular',
|
|
||||||
title: i18n.baseText('nodeCreator.sectionNames.popular'),
|
|
||||||
items: [CONVERT_TO_FILE_NODE_TYPE, EXTRACT_FROM_FILE_NODE_TYPE],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: 'subcategory',
|
type: 'subcategory',
|
||||||
key: HELPERS_SUBCATEGORY,
|
key: HELPERS_SUBCATEGORY,
|
||||||
|
@ -491,9 +514,13 @@ export function RegularView(nodes: SimplifiedNodeType[]) {
|
||||||
title: i18n.baseText('nodeCreator.aiPanel.langchainAiNodes'),
|
title: i18n.baseText('nodeCreator.aiPanel.langchainAiNodes'),
|
||||||
icon: 'robot',
|
icon: 'robot',
|
||||||
description: i18n.baseText('nodeCreator.aiPanel.nodesForAi'),
|
description: i18n.baseText('nodeCreator.aiPanel.nodesForAi'),
|
||||||
tag: i18n.baseText('nodeCreator.aiPanel.newTag'),
|
tag: {
|
||||||
|
type: 'success',
|
||||||
|
text: i18n.baseText('nodeCreator.aiPanel.newTag'),
|
||||||
},
|
},
|
||||||
});
|
borderless: true,
|
||||||
|
},
|
||||||
|
} as NodeViewItem);
|
||||||
|
|
||||||
view.items.push({
|
view.items.push({
|
||||||
key: TRIGGER_NODE_CREATOR_VIEW,
|
key: TRIGGER_NODE_CREATOR_VIEW,
|
||||||
|
|
|
@ -264,8 +264,10 @@ export const AI_CATEGORY_RETRIEVERS = 'Retrievers';
|
||||||
export const AI_CATEGORY_EMBEDDING = 'Embeddings';
|
export const AI_CATEGORY_EMBEDDING = 'Embeddings';
|
||||||
export const AI_CATEGORY_DOCUMENT_LOADERS = 'Document Loaders';
|
export const AI_CATEGORY_DOCUMENT_LOADERS = 'Document Loaders';
|
||||||
export const AI_CATEGORY_TEXT_SPLITTERS = 'Text Splitters';
|
export const AI_CATEGORY_TEXT_SPLITTERS = 'Text Splitters';
|
||||||
|
export const AI_CATEGORY_ROOT_NODES = 'Root Nodes';
|
||||||
export const AI_UNCATEGORIZED_CATEGORY = 'Miscellaneous';
|
export const AI_UNCATEGORIZED_CATEGORY = 'Miscellaneous';
|
||||||
|
export const AI_CODE_TOOL_LANGCHAIN_NODE_TYPE = '@n8n/n8n-nodes-langchain.toolCode';
|
||||||
|
export const AI_WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE = '@n8n/n8n-nodes-langchain.toolWorkflow';
|
||||||
export const REQUEST_NODE_FORM_URL = 'https://n8n-community.typeform.com/to/K1fBVTZ3';
|
export const REQUEST_NODE_FORM_URL = 'https://n8n-community.typeform.com/to/K1fBVTZ3';
|
||||||
|
|
||||||
// Node Connection Types
|
// Node Connection Types
|
||||||
|
@ -674,10 +676,17 @@ export const AI_ASSISTANT_EXPERIMENT = {
|
||||||
variant: 'variant',
|
variant: 'variant',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CANVAS_AUTO_ADD_MANUAL_TRIGGER_EXPERIMENT = {
|
||||||
|
name: '20_canvas_auto_add_manual_trigger',
|
||||||
|
control: 'control',
|
||||||
|
variant: 'variant',
|
||||||
|
};
|
||||||
|
|
||||||
export const EXPERIMENTS_TO_TRACK = [
|
export const EXPERIMENTS_TO_TRACK = [
|
||||||
ASK_AI_EXPERIMENT.name,
|
ASK_AI_EXPERIMENT.name,
|
||||||
TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT,
|
TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT,
|
||||||
AI_ASSISTANT_EXPERIMENT.name,
|
AI_ASSISTANT_EXPERIMENT.name,
|
||||||
|
CANVAS_AUTO_ADD_MANUAL_TRIGGER_EXPERIMENT.name,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const MFA_AUTHENTICATION_REQUIRED_ERROR_CODE = 998;
|
export const MFA_AUTHENTICATION_REQUIRED_ERROR_CODE = 998;
|
||||||
|
|
|
@ -928,9 +928,9 @@
|
||||||
"ndv.output.of": " of ",
|
"ndv.output.of": " of ",
|
||||||
"ndv.output.pageSize": "Page Size",
|
"ndv.output.pageSize": "Page Size",
|
||||||
"ndv.output.run": "Run",
|
"ndv.output.run": "Run",
|
||||||
"ndv.output.runNodeHint": "Test this node to output data",
|
"ndv.output.runNodeHint": "Execute this node to view data",
|
||||||
"ndv.output.runNodeHintSubNode": "Output will appear here once the parent node is run",
|
"ndv.output.runNodeHintSubNode": "Output will appear here once the parent node is run",
|
||||||
"ndv.output.insertTestData": "insert test data",
|
"ndv.output.insertTestData": "set mock data",
|
||||||
"ndv.output.staleDataWarning.regular": "Node parameters have changed.<br>Test node again to refresh output.",
|
"ndv.output.staleDataWarning.regular": "Node parameters have changed.<br>Test node again to refresh output.",
|
||||||
"ndv.output.staleDataWarning.pinData": "Node parameter changes will not affect pinned output data.",
|
"ndv.output.staleDataWarning.pinData": "Node parameter changes will not affect pinned output data.",
|
||||||
"ndv.output.tooMuchData.message": "The node contains {size} MB of data. Displaying it may cause problems. <br /> If you do decide to display it, avoid the JSON view.",
|
"ndv.output.tooMuchData.message": "The node contains {size} MB of data. Displaying it may cause problems. <br /> If you do decide to display it, avoid the JSON view.",
|
||||||
|
@ -986,6 +986,9 @@
|
||||||
"nodeCreator.actionsCategory.onNewEvent": "On new {event} event",
|
"nodeCreator.actionsCategory.onNewEvent": "On new {event} event",
|
||||||
"nodeCreator.actionsCategory.onEvent": "On {event}",
|
"nodeCreator.actionsCategory.onEvent": "On {event}",
|
||||||
"nodeCreator.actionsCategory.triggers": "Triggers",
|
"nodeCreator.actionsCategory.triggers": "Triggers",
|
||||||
|
"nodeCreator.actionsCategory.triggerNodes": "Trigger Nodes",
|
||||||
|
"nodeCreator.actionsCategory.regularNodes": "Regular Nodes",
|
||||||
|
"nodeCreator.actionsCategory.regularAndTriggers": "Regular & Trigger Nodes",
|
||||||
"nodeCreator.actionsCategory.searchActions": "Search {node} Actions...",
|
"nodeCreator.actionsCategory.searchActions": "Search {node} Actions...",
|
||||||
"nodeCreator.actionsCategory.noMatchingActions": "No matching Actions. <i>Reset search</i>",
|
"nodeCreator.actionsCategory.noMatchingActions": "No matching Actions. <i>Reset search</i>",
|
||||||
"nodeCreator.actionsCategory.noMatchingTriggers": "No matching Triggers. <i>Reset search</i>",
|
"nodeCreator.actionsCategory.noMatchingTriggers": "No matching Triggers. <i>Reset search</i>",
|
||||||
|
@ -996,6 +999,7 @@
|
||||||
"nodeCreator.actionsTooltip.actionsPerformStep": "Actions perform a step once your workflow has already started. <a target=\"_blank\" href=\"https://docs.n8n.io/integrations/builtin/\"> Learn more</a>",
|
"nodeCreator.actionsTooltip.actionsPerformStep": "Actions perform a step once your workflow has already started. <a target=\"_blank\" href=\"https://docs.n8n.io/integrations/builtin/\"> Learn more</a>",
|
||||||
"nodeCreator.actionsCallout.noTriggerItems": "No <strong>{nodeName}</strong> Triggers available. Users often combine the following Triggers with <strong>{nodeName}</strong> Actions.",
|
"nodeCreator.actionsCallout.noTriggerItems": "No <strong>{nodeName}</strong> Triggers available. Users often combine the following Triggers with <strong>{nodeName}</strong> Actions.",
|
||||||
"nodeCreator.categoryNames.otherCategories": "Results in other categories",
|
"nodeCreator.categoryNames.otherCategories": "Results in other categories",
|
||||||
|
"nodeCreator.subnodes": "sub-nodes",
|
||||||
"nodeCreator.noResults.dontWorryYouCanProbablyDoItWithThe": "Don’t worry, you can probably do it with the",
|
"nodeCreator.noResults.dontWorryYouCanProbablyDoItWithThe": "Don’t worry, you can probably do it with the",
|
||||||
"nodeCreator.noResults.httpRequest": "HTTP Request",
|
"nodeCreator.noResults.httpRequest": "HTTP Request",
|
||||||
"nodeCreator.noResults.node": "node",
|
"nodeCreator.noResults.node": "node",
|
||||||
|
@ -1007,10 +1011,10 @@
|
||||||
"nodeCreator.searchBar.searchNodes": "Search nodes...",
|
"nodeCreator.searchBar.searchNodes": "Search nodes...",
|
||||||
"nodeCreator.subcategoryDescriptions.appTriggerNodes": "Runs the flow when something happens in an app like Telegram, Notion or Airtable",
|
"nodeCreator.subcategoryDescriptions.appTriggerNodes": "Runs the flow when something happens in an app like Telegram, Notion or Airtable",
|
||||||
"nodeCreator.subcategoryDescriptions.appRegularNodes": "Do something in an app or service like Google Sheets, Telegram or Notion",
|
"nodeCreator.subcategoryDescriptions.appRegularNodes": "Do something in an app or service like Google Sheets, Telegram or Notion",
|
||||||
"nodeCreator.subcategoryDescriptions.dataTransformation": "Manipulate data, run JavaScript code, etc.",
|
"nodeCreator.subcategoryDescriptions.dataTransformation": "Manipulate, filter or convert data",
|
||||||
"nodeCreator.subcategoryDescriptions.files": "CSV, XLS, XML, text, images, etc.",
|
"nodeCreator.subcategoryDescriptions.files": "CSV, XLS, XML, text, images, etc.",
|
||||||
"nodeCreator.subcategoryDescriptions.flow": "IF, Switch, Wait, Compare and Merge data, etc.",
|
"nodeCreator.subcategoryDescriptions.flow": "Branch, merge or loop the flow, etc.",
|
||||||
"nodeCreator.subcategoryDescriptions.helpers": "Code, HTTP Requests (API Calls), Webhook, and other helpers",
|
"nodeCreator.subcategoryDescriptions.helpers": "Run code, make HTTP requests, set webhooks, etc.",
|
||||||
"nodeCreator.subcategoryDescriptions.otherTriggerNodes": "Runs the flow on workflow errors, file changes, etc.",
|
"nodeCreator.subcategoryDescriptions.otherTriggerNodes": "Runs the flow on workflow errors, file changes, etc.",
|
||||||
"nodeCreator.subcategoryDescriptions.agents": "Autonomous entities that interact and make decisions.",
|
"nodeCreator.subcategoryDescriptions.agents": "Autonomous entities that interact and make decisions.",
|
||||||
"nodeCreator.subcategoryDescriptions.chains": "Structured assemblies for specific tasks.",
|
"nodeCreator.subcategoryDescriptions.chains": "Structured assemblies for specific tasks.",
|
||||||
|
@ -1054,11 +1058,14 @@
|
||||||
"nodeCreator.triggerHelperPanel.scheduleTriggerDisplayName": "On a schedule",
|
"nodeCreator.triggerHelperPanel.scheduleTriggerDisplayName": "On a schedule",
|
||||||
"nodeCreator.triggerHelperPanel.scheduleTriggerDescription": "Runs the flow every day, hour, or custom interval",
|
"nodeCreator.triggerHelperPanel.scheduleTriggerDescription": "Runs the flow every day, hour, or custom interval",
|
||||||
"nodeCreator.triggerHelperPanel.webhookTriggerDisplayName": "On webhook call",
|
"nodeCreator.triggerHelperPanel.webhookTriggerDisplayName": "On webhook call",
|
||||||
"nodeCreator.triggerHelperPanel.webhookTriggerDescription": "Runs the flow when another app sends a webhook",
|
"nodeCreator.triggerHelperPanel.webhookTriggerDescription": "Runs the flow on receiving an HTTP request",
|
||||||
"nodeCreator.triggerHelperPanel.formTriggerDisplayName": "On form submission",
|
"nodeCreator.triggerHelperPanel.formTriggerDisplayName": "On form submission",
|
||||||
"nodeCreator.triggerHelperPanel.formTriggerDescription": "Runs the flow when an n8n generated webform is submitted",
|
"nodeCreator.triggerHelperPanel.formTriggerDescription": "Runs the flow when an n8n generated webform is submitted",
|
||||||
"nodeCreator.triggerHelperPanel.manualTriggerDisplayName": "Manually",
|
"nodeCreator.triggerHelperPanel.manualTriggerDisplayName": "Trigger manually",
|
||||||
"nodeCreator.triggerHelperPanel.manualTriggerDescription": "Runs the flow on clicking a button in n8n",
|
"nodeCreator.triggerHelperPanel.manualTriggerDescription": "Runs the flow on clicking a button in n8n. Good for getting started quickly",
|
||||||
|
"nodeCreator.triggerHelperPanel.manualChatTriggerDisplayName": "On chat message",
|
||||||
|
"nodeCreator.triggerHelperPanel.manualChatTriggerDescription": "Runs the flow when a user sends a chat message. For use with AI nodes",
|
||||||
|
"nodeCreator.triggerHelperPanel.manualTriggerTag": "Recommended",
|
||||||
"nodeCreator.triggerHelperPanel.whatHappensNext": "What happens next?",
|
"nodeCreator.triggerHelperPanel.whatHappensNext": "What happens next?",
|
||||||
"nodeCreator.triggerHelperPanel.selectATrigger": "What triggers this workflow?",
|
"nodeCreator.triggerHelperPanel.selectATrigger": "What triggers this workflow?",
|
||||||
"nodeCreator.triggerHelperPanel.selectATriggerDescription": "A trigger is a step that starts your workflow",
|
"nodeCreator.triggerHelperPanel.selectATriggerDescription": "A trigger is a step that starts your workflow",
|
||||||
|
@ -1072,7 +1079,8 @@
|
||||||
"nodeCreator.aiPanel.newTag": "New",
|
"nodeCreator.aiPanel.newTag": "New",
|
||||||
"nodeCreator.aiPanel.langchainAiNodes": "Advanced AI",
|
"nodeCreator.aiPanel.langchainAiNodes": "Advanced AI",
|
||||||
"nodeCreator.aiPanel.title": "When should this workflow run?",
|
"nodeCreator.aiPanel.title": "When should this workflow run?",
|
||||||
"nodeCreator.aiPanel.infoBox": "Check out our <a href=\"{link}\" target=\"_blank\">templates</a> for workflow examples and inspiration.",
|
"nodeCreator.aiPanel.linkItem.description": "See what's possible and get started 5x faster",
|
||||||
|
"nodeCreator.aiPanel.linkItem.title": "AI Templates",
|
||||||
"nodeCreator.aiPanel.scheduleTriggerDisplayName": "On a schedule",
|
"nodeCreator.aiPanel.scheduleTriggerDisplayName": "On a schedule",
|
||||||
"nodeCreator.aiPanel.scheduleTriggerDescription": "Runs the flow every day, hour, or custom interval",
|
"nodeCreator.aiPanel.scheduleTriggerDescription": "Runs the flow every day, hour, or custom interval",
|
||||||
"nodeCreator.aiPanel.webhookTriggerDisplayName": "On webhook call",
|
"nodeCreator.aiPanel.webhookTriggerDisplayName": "On webhook call",
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
scaleReset,
|
scaleReset,
|
||||||
scaleSmaller,
|
scaleSmaller,
|
||||||
} from '@/utils/canvasUtils';
|
} from '@/utils/canvasUtils';
|
||||||
import { START_NODE_TYPE } from '@/constants';
|
import { MANUAL_TRIGGER_NODE_TYPE, START_NODE_TYPE } from '@/constants';
|
||||||
import type {
|
import type {
|
||||||
BeforeStartEventParams,
|
BeforeStartEventParams,
|
||||||
BrowserJsPlumbInstance,
|
BrowserJsPlumbInstance,
|
||||||
|
@ -61,6 +61,9 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||||
(node) => node.type === START_NODE_TYPE || nodeTypesStore.isTriggerNode(node.type),
|
(node) => node.type === START_NODE_TYPE || nodeTypesStore.isTriggerNode(node.type),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
const aiNodes = computed<INodeUi[]>(() =>
|
||||||
|
nodes.value.filter((node) => node.type.includes('langchain')),
|
||||||
|
);
|
||||||
const isDemo = ref<boolean>(false);
|
const isDemo = ref<boolean>(false);
|
||||||
const nodeViewScale = ref<number>(1);
|
const nodeViewScale = ref<number>(1);
|
||||||
const canvasAddButtonPosition = ref<XYPosition>([1, 1]);
|
const canvasAddButtonPosition = ref<XYPosition>([1, 1]);
|
||||||
|
@ -91,6 +94,23 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAutoAddManualTriggerNode = (): INodeUi | null => {
|
||||||
|
const manualTriggerNode = nodeTypesStore.getNodeType(MANUAL_TRIGGER_NODE_TYPE);
|
||||||
|
|
||||||
|
if (!manualTriggerNode) {
|
||||||
|
console.error('Could not find the manual trigger node');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: uuid(),
|
||||||
|
name: manualTriggerNode.defaults.name?.toString() ?? manualTriggerNode.displayName,
|
||||||
|
type: MANUAL_TRIGGER_NODE_TYPE,
|
||||||
|
parameters: {},
|
||||||
|
position: canvasAddButtonPosition.value,
|
||||||
|
typeVersion: 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const getNodesWithPlaceholderNode = (): INodeUi[] =>
|
const getNodesWithPlaceholderNode = (): INodeUi[] =>
|
||||||
triggerNodes.value.length > 0 ? nodes.value : [getPlaceholderTriggerNodeUI(), ...nodes.value];
|
triggerNodes.value.length > 0 ? nodes.value : [getPlaceholderTriggerNodeUI(), ...nodes.value];
|
||||||
|
|
||||||
|
@ -298,6 +318,7 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||||
newNodeInsertPosition,
|
newNodeInsertPosition,
|
||||||
jsPlumbInstance,
|
jsPlumbInstance,
|
||||||
isLoading: loadingService.isLoading,
|
isLoading: loadingService.isLoading,
|
||||||
|
aiNodes,
|
||||||
startLoading: loadingService.startLoading,
|
startLoading: loadingService.startLoading,
|
||||||
setLoadingText: loadingService.setLoadingText,
|
setLoadingText: loadingService.setLoadingText,
|
||||||
stopLoading: loadingService.stopLoading,
|
stopLoading: loadingService.stopLoading,
|
||||||
|
@ -311,5 +332,6 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||||
zoomToFit,
|
zoomToFit,
|
||||||
wheelScroll,
|
wheelScroll,
|
||||||
initInstance,
|
initInstance,
|
||||||
|
getAutoAddManualTriggerNode,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -121,7 +121,7 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
||||||
* Constructs URLSearchParams object based on the default parameters for the template repository
|
* Constructs URLSearchParams object based on the default parameters for the template repository
|
||||||
* and provided additional parameters
|
* and provided additional parameters
|
||||||
*/
|
*/
|
||||||
websiteTemplateRepositoryParameters() {
|
websiteTemplateRepositoryParameters(roleOverride?: string) {
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
const userStore = useUsersStore();
|
const userStore = useUsersStore();
|
||||||
const workflowsStore = useWorkflowsStore();
|
const workflowsStore = useWorkflowsStore();
|
||||||
|
@ -133,6 +133,7 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
||||||
};
|
};
|
||||||
const userRole: string | undefined =
|
const userRole: string | undefined =
|
||||||
userStore.currentUserCloudInfo?.role ?? userStore.currentUser?.personalizationAnswers?.role;
|
userStore.currentUserCloudInfo?.role ?? userStore.currentUser?.personalizationAnswers?.role;
|
||||||
|
|
||||||
if (userRole) {
|
if (userRole) {
|
||||||
defaultParameters.utm_user_role = userRole;
|
defaultParameters.utm_user_role = userRole;
|
||||||
}
|
}
|
||||||
|
@ -156,10 +157,15 @@ export const useTemplatesStore = defineStore(STORES.TEMPLATES, {
|
||||||
* Construct the URL for the template category page on the website for a given category id
|
* Construct the URL for the template category page on the website for a given category id
|
||||||
*/
|
*/
|
||||||
getWebsiteCategoryURL() {
|
getWebsiteCategoryURL() {
|
||||||
return (id: string) => {
|
return (id?: string, roleOverride?: string) => {
|
||||||
return `${TEMPLATES_URLS.BASE_WEBSITE_URL}/?${this.websiteTemplateRepositoryParameters({
|
const payload: Record<string, string> = {};
|
||||||
categories: id,
|
if (id) {
|
||||||
}).toString()}`;
|
payload.categories = id;
|
||||||
|
}
|
||||||
|
if (roleOverride) {
|
||||||
|
payload.utm_user_role = roleOverride;
|
||||||
|
}
|
||||||
|
return `${TEMPLATES_URLS.BASE_WEBSITE_URL}/?${this.websiteTemplateRepositoryParameters(payload).toString()}`;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,7 @@ const MOCK_EXECUTION: Partial<IExecutionResponse> = {
|
||||||
startData: {},
|
startData: {},
|
||||||
resultData: {
|
resultData: {
|
||||||
runData: {
|
runData: {
|
||||||
'When clicking "Test workflow"': [
|
'When clicking ‘Test workflow’': [
|
||||||
{
|
{
|
||||||
startTime: 1706027170005,
|
startTime: 1706027170005,
|
||||||
executionTime: 0,
|
executionTime: 0,
|
||||||
|
@ -24,7 +24,7 @@ const MOCK_EXECUTION: Partial<IExecutionResponse> = {
|
||||||
{
|
{
|
||||||
startTime: 1706027170005,
|
startTime: 1706027170005,
|
||||||
executionTime: 1,
|
executionTime: 1,
|
||||||
source: [{ previousNode: 'When clicking "Test workflow"' }],
|
source: [{ previousNode: 'When clicking ‘Test workflow’' }],
|
||||||
executionStatus: 'success',
|
executionStatus: 'success',
|
||||||
data: {
|
data: {
|
||||||
main: [
|
main: [
|
||||||
|
@ -258,54 +258,54 @@ describe('pairedItemUtils', () => {
|
||||||
const actual = getPairedItemsMapping(MOCK_EXECUTION);
|
const actual = getPairedItemsMapping(MOCK_EXECUTION);
|
||||||
const expected = {
|
const expected = {
|
||||||
DebugHelper_r0_o0_i0: new Set([
|
DebugHelper_r0_o0_i0: new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'If_r0_o0_i0',
|
'If_r0_o0_i0',
|
||||||
'Edit Fields_r1_o0_i0',
|
'Edit Fields_r1_o0_i0',
|
||||||
'Edit Fields1_r1_o0_i0',
|
'Edit Fields1_r1_o0_i0',
|
||||||
]),
|
]),
|
||||||
DebugHelper_r0_o0_i1: new Set([
|
DebugHelper_r0_o0_i1: new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'If_r0_o1_i0',
|
'If_r0_o1_i0',
|
||||||
'Edit Fields_r0_o0_i0',
|
'Edit Fields_r0_o0_i0',
|
||||||
'Edit Fields1_r0_o0_i0',
|
'Edit Fields1_r0_o0_i0',
|
||||||
]),
|
]),
|
||||||
'Edit Fields1_r0_o0_i0': new Set([
|
'Edit Fields1_r0_o0_i0': new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'DebugHelper_r0_o0_i1',
|
'DebugHelper_r0_o0_i1',
|
||||||
'If_r0_o1_i0',
|
'If_r0_o1_i0',
|
||||||
'Edit Fields_r0_o0_i0',
|
'Edit Fields_r0_o0_i0',
|
||||||
]),
|
]),
|
||||||
'Edit Fields1_r1_o0_i0': new Set([
|
'Edit Fields1_r1_o0_i0': new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'DebugHelper_r0_o0_i0',
|
'DebugHelper_r0_o0_i0',
|
||||||
'If_r0_o0_i0',
|
'If_r0_o0_i0',
|
||||||
'Edit Fields_r1_o0_i0',
|
'Edit Fields_r1_o0_i0',
|
||||||
]),
|
]),
|
||||||
'Edit Fields_r0_o0_i0': new Set([
|
'Edit Fields_r0_o0_i0': new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'DebugHelper_r0_o0_i1',
|
'DebugHelper_r0_o0_i1',
|
||||||
'If_r0_o1_i0',
|
'If_r0_o1_i0',
|
||||||
'Edit Fields1_r0_o0_i0',
|
'Edit Fields1_r0_o0_i0',
|
||||||
]),
|
]),
|
||||||
'Edit Fields_r1_o0_i0': new Set([
|
'Edit Fields_r1_o0_i0': new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'DebugHelper_r0_o0_i0',
|
'DebugHelper_r0_o0_i0',
|
||||||
'If_r0_o0_i0',
|
'If_r0_o0_i0',
|
||||||
'Edit Fields1_r1_o0_i0',
|
'Edit Fields1_r1_o0_i0',
|
||||||
]),
|
]),
|
||||||
If_r0_o0_i0: new Set([
|
If_r0_o0_i0: new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'DebugHelper_r0_o0_i0',
|
'DebugHelper_r0_o0_i0',
|
||||||
'Edit Fields_r1_o0_i0',
|
'Edit Fields_r1_o0_i0',
|
||||||
'Edit Fields1_r1_o0_i0',
|
'Edit Fields1_r1_o0_i0',
|
||||||
]),
|
]),
|
||||||
If_r0_o1_i0: new Set([
|
If_r0_o1_i0: new Set([
|
||||||
'When clicking "Test workflow"_r0_o0_i0',
|
'When clicking ‘Test workflow’_r0_o0_i0',
|
||||||
'DebugHelper_r0_o0_i1',
|
'DebugHelper_r0_o0_i1',
|
||||||
'Edit Fields_r0_o0_i0',
|
'Edit Fields_r0_o0_i0',
|
||||||
'Edit Fields1_r0_o0_i0',
|
'Edit Fields1_r0_o0_i0',
|
||||||
]),
|
]),
|
||||||
'When clicking "Test workflow"_r0_o0_i0': new Set([
|
'When clicking ‘Test workflow’_r0_o0_i0': new Set([
|
||||||
'DebugHelper_r0_o0_i0',
|
'DebugHelper_r0_o0_i0',
|
||||||
'DebugHelper_r0_o0_i1',
|
'DebugHelper_r0_o0_i1',
|
||||||
'If_r0_o0_i0',
|
'If_r0_o0_i0',
|
||||||
|
|
|
@ -250,6 +250,7 @@ import {
|
||||||
UPDATE_WEBHOOK_ID_NODE_TYPES,
|
UPDATE_WEBHOOK_ID_NODE_TYPES,
|
||||||
TIME,
|
TIME,
|
||||||
AI_ASSISTANT_LOCAL_STORAGE_KEY,
|
AI_ASSISTANT_LOCAL_STORAGE_KEY,
|
||||||
|
CANVAS_AUTO_ADD_MANUAL_TRIGGER_EXPERIMENT,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
|
|
||||||
import useGlobalLinkActions from '@/composables/useGlobalLinkActions';
|
import useGlobalLinkActions from '@/composables/useGlobalLinkActions';
|
||||||
|
@ -395,6 +396,7 @@ import type { ProjectSharingData } from '@/features/projects/projects.types';
|
||||||
import { useAIStore } from '@/stores/ai.store';
|
import { useAIStore } from '@/stores/ai.store';
|
||||||
import { useStorage } from '@/composables/useStorage';
|
import { useStorage } from '@/composables/useStorage';
|
||||||
import { isJSPlumbEndpointElement } from '@/utils/typeGuards';
|
import { isJSPlumbEndpointElement } from '@/utils/typeGuards';
|
||||||
|
import { usePostHog } from '@/stores/posthog.store';
|
||||||
import { ProjectTypes } from '@/features/projects/projects.utils';
|
import { ProjectTypes } from '@/features/projects/projects.utils';
|
||||||
|
|
||||||
interface AddNodeOptions {
|
interface AddNodeOptions {
|
||||||
|
@ -944,6 +946,17 @@ export default defineComponent({
|
||||||
action: this.openSelectiveNodeCreator,
|
action: this.openSelectiveNodeCreator,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.registerCustomAction({
|
||||||
|
key: 'showNodeCreator',
|
||||||
|
action: () => {
|
||||||
|
this.ndvStore.activeNodeName = null;
|
||||||
|
|
||||||
|
void this.$nextTick(() => {
|
||||||
|
this.showTriggerCreator(NODE_CREATOR_OPEN_SOURCES.TAB);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
this.readOnlyEnvRouteCheck();
|
this.readOnlyEnvRouteCheck();
|
||||||
this.canvasStore.isDemo = this.isDemo;
|
this.canvasStore.isDemo = this.isDemo;
|
||||||
},
|
},
|
||||||
|
@ -1177,12 +1190,6 @@ export default defineComponent({
|
||||||
? this.$locale.baseText('nodeView.addOrEnableTriggerNode')
|
? this.$locale.baseText('nodeView.addOrEnableTriggerNode')
|
||||||
: this.$locale.baseText('nodeView.addATriggerNodeFirst');
|
: this.$locale.baseText('nodeView.addATriggerNodeFirst');
|
||||||
|
|
||||||
this.registerCustomAction({
|
|
||||||
key: 'showNodeCreator',
|
|
||||||
action: () =>
|
|
||||||
this.showTriggerCreator(NODE_CREATOR_OPEN_SOURCES.NO_TRIGGER_EXECUTION_TOOLTIP),
|
|
||||||
});
|
|
||||||
|
|
||||||
const notice = this.showMessage({
|
const notice = this.showMessage({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: this.$locale.baseText('nodeView.cantExecuteNoTrigger'),
|
title: this.$locale.baseText('nodeView.cantExecuteNoTrigger'),
|
||||||
|
@ -1257,9 +1264,15 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
showTriggerCreator(source: NodeCreatorOpenSource) {
|
showTriggerCreator(source: NodeCreatorOpenSource) {
|
||||||
if (this.createNodeActive) return;
|
if (this.createNodeActive) return;
|
||||||
|
|
||||||
|
this.ndvStore.activeNodeName = null;
|
||||||
this.nodeCreatorStore.setSelectedView(TRIGGER_NODE_CREATOR_VIEW);
|
this.nodeCreatorStore.setSelectedView(TRIGGER_NODE_CREATOR_VIEW);
|
||||||
this.nodeCreatorStore.setShowScrim(true);
|
this.nodeCreatorStore.setShowScrim(true);
|
||||||
this.onToggleNodeCreator({ source, createNodeActive: true });
|
this.onToggleNodeCreator({
|
||||||
|
source,
|
||||||
|
createNodeActive: true,
|
||||||
|
nodeCreatorView: TRIGGER_NODE_CREATOR_VIEW,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
async openExecution(executionId: string) {
|
async openExecution(executionId: string) {
|
||||||
this.canvasStore.startLoading();
|
this.canvasStore.startLoading();
|
||||||
|
@ -3659,6 +3672,7 @@ export default defineComponent({
|
||||||
this.workflowsStore.workflow.scopes = scopes;
|
this.workflowsStore.workflow.scopes = scopes;
|
||||||
},
|
},
|
||||||
async newWorkflow(): Promise<void> {
|
async newWorkflow(): Promise<void> {
|
||||||
|
const { getVariant } = usePostHog();
|
||||||
this.canvasStore.startLoading();
|
this.canvasStore.startLoading();
|
||||||
this.resetWorkspace();
|
this.resetWorkspace();
|
||||||
this.workflowData = await this.workflowsStore.getNewWorkflowData(
|
this.workflowData = await this.workflowsStore.getNewWorkflowData(
|
||||||
|
@ -3670,15 +3684,24 @@ export default defineComponent({
|
||||||
|
|
||||||
this.uiStore.stateIsDirty = false;
|
this.uiStore.stateIsDirty = false;
|
||||||
this.canvasStore.setZoomLevel(1, [0, 0]);
|
this.canvasStore.setZoomLevel(1, [0, 0]);
|
||||||
await this.tryToAddWelcomeSticky();
|
this.canvasStore.zoomToFit();
|
||||||
this.uiStore.nodeViewInitialized = true;
|
this.uiStore.nodeViewInitialized = true;
|
||||||
this.historyStore.reset();
|
this.historyStore.reset();
|
||||||
this.executionsStore.activeExecution = null;
|
this.executionsStore.activeExecution = null;
|
||||||
this.makeNewWorkflowShareable();
|
this.makeNewWorkflowShareable();
|
||||||
this.canvasStore.stopLoading();
|
this.canvasStore.stopLoading();
|
||||||
},
|
|
||||||
async tryToAddWelcomeSticky(): Promise<void> {
|
// Pre-populate the canvas with the manual trigger node if the experiment is enabled and the user is in the variant group
|
||||||
this.canvasStore.zoomToFit();
|
if (
|
||||||
|
getVariant(CANVAS_AUTO_ADD_MANUAL_TRIGGER_EXPERIMENT.name) ===
|
||||||
|
CANVAS_AUTO_ADD_MANUAL_TRIGGER_EXPERIMENT.variant
|
||||||
|
) {
|
||||||
|
const manualTriggerNode = this.canvasStore.getAutoAddManualTriggerNode();
|
||||||
|
if (manualTriggerNode) {
|
||||||
|
await this.addNodes([manualTriggerNode]);
|
||||||
|
this.uiStore.lastSelectedNode = manualTriggerNode.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async initView(): Promise<void> {
|
async initView(): Promise<void> {
|
||||||
if (this.$route.params.action === 'workflowSave') {
|
if (this.$route.params.action === 'workflowSave') {
|
||||||
|
@ -5375,4 +5398,3 @@ export default defineComponent({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
, IRun, IPushDataExecutionFinished
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "59f5ae0f-52f7-4bc8-b325-29d2b0d810f8",
|
"id": "59f5ae0f-52f7-4bc8-b325-29d2b0d810f8",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -217,7 +217,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "fb826323-2e48-4f11-bb0e-e12de32e22ee",
|
"id": "fb826323-2e48-4f11-bb0e-e12de32e22ee",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [180, 160]
|
"position": [180, 160]
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "fcc3e9dc-90c9-4b26-9b44-e661e0ebf658",
|
"id": "fcc3e9dc-90c9-4b26-9b44-e661e0ebf658",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -305,7 +305,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,7 +16,7 @@ export class ManualTrigger implements INodeType {
|
||||||
eventTriggerDescription: '',
|
eventTriggerDescription: '',
|
||||||
maxNodes: 1,
|
maxNodes: 1,
|
||||||
defaults: {
|
defaults: {
|
||||||
name: 'When clicking "Test workflow"',
|
name: 'When clicking ‘Test workflow’',
|
||||||
color: '#909298',
|
color: '#909298',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export class ManualTrigger implements INodeType {
|
||||||
properties: [
|
properties: [
|
||||||
{
|
{
|
||||||
displayName:
|
displayName:
|
||||||
'This node is where a manual workflow execution starts. To make one, go back to the canvas and click test workflow’',
|
'This node is where the workflow execution starts (when you click the ‘test’ button on the canvas).<br><br> <a data-action="showNodeCreator">Explore other ways to trigger your workflow</a> (e.g on a schedule, or a webhook)',
|
||||||
name: 'notice',
|
name: 'notice',
|
||||||
type: 'notice',
|
type: 'notice',
|
||||||
default: '',
|
default: '',
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "94003e55-6c4e-492f-802a-49f4fb5b5f4b",
|
"id": "94003e55-6c4e-492f-802a-49f4fb5b5f4b",
|
||||||
"name": "When clicking \"Test Workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -485,7 +485,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test Workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "1301e15e-7a64-44bf-bc4b-d60e7b8c629a",
|
"id": "1301e15e-7a64-44bf-bc4b-d60e7b8c629a",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [
|
"position": [
|
||||||
|
@ -273,7 +273,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -667,7 +667,7 @@ describe('generateNodesGraph', () => {
|
||||||
{
|
{
|
||||||
parameters: {},
|
parameters: {},
|
||||||
id: 'fe69383c-e418-4f98-9c0e-924deafa7f93',
|
id: 'fe69383c-e418-4f98-9c0e-924deafa7f93',
|
||||||
name: 'When clicking "Test workflow"',
|
name: 'When clicking ‘Test workflow’',
|
||||||
type: 'n8n-nodes-base.manualTrigger',
|
type: 'n8n-nodes-base.manualTrigger',
|
||||||
typeVersion: 1,
|
typeVersion: 1,
|
||||||
position: [540, 220],
|
position: [540, 220],
|
||||||
|
@ -692,7 +692,7 @@ describe('generateNodesGraph', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
connections: {
|
connections: {
|
||||||
'When clicking "Test workflow"': {
|
'When clicking ‘Test workflow’': {
|
||||||
main: [
|
main: [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -758,7 +758,7 @@ describe('generateNodesGraph', () => {
|
||||||
is_pinned: false,
|
is_pinned: false,
|
||||||
},
|
},
|
||||||
nameIndices: {
|
nameIndices: {
|
||||||
'When clicking "Test workflow"': '0',
|
'When clicking ‘Test workflow’': '0',
|
||||||
Chain: '1',
|
Chain: '1',
|
||||||
Model: '2',
|
Model: '2',
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"startData": {},
|
"startData": {},
|
||||||
"resultData": {
|
"resultData": {
|
||||||
"runData": {
|
"runData": {
|
||||||
"When clicking \"Test workflow\"": [
|
"When clicking ‘Test workflow’": [
|
||||||
{
|
{
|
||||||
"startTime": 1707471743600,
|
"startTime": 1707471743600,
|
||||||
"executionTime": 1,
|
"executionTime": 1,
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
"executionTime": 1,
|
"executionTime": 1,
|
||||||
"source": [
|
"source": [
|
||||||
{
|
{
|
||||||
"previousNode": "When clicking \"Test workflow\""
|
"previousNode": "When clicking ‘Test workflow’"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"executionStatus": "success",
|
"executionStatus": "success",
|
||||||
|
@ -956,7 +956,7 @@
|
||||||
"source": {
|
"source": {
|
||||||
"main": [
|
"main": [
|
||||||
{
|
{
|
||||||
"previousNode": "When clicking \"Test workflow\""
|
"previousNode": "When clicking ‘Test workflow’"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -999,7 +999,7 @@
|
||||||
"source": {
|
"source": {
|
||||||
"main": [
|
"main": [
|
||||||
{
|
{
|
||||||
"previousNode": "When clicking \"Test workflow\""
|
"previousNode": "When clicking ‘Test workflow’"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
"id": "b5122d27-4bb5-4100-a69b-03b1dcac76c7",
|
"id": "b5122d27-4bb5-4100-a69b-03b1dcac76c7",
|
||||||
"name": "When clicking \"Test workflow\"",
|
"name": "When clicking ‘Test workflow’",
|
||||||
"type": "n8n-nodes-base.manualTrigger",
|
"type": "n8n-nodes-base.manualTrigger",
|
||||||
"typeVersion": 1,
|
"typeVersion": 1,
|
||||||
"position": [740, 1680]
|
"position": [740, 1680]
|
||||||
|
@ -561,7 +561,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"connections": {
|
"connections": {
|
||||||
"When clicking \"Test workflow\"": {
|
"When clicking ‘Test workflow’": {
|
||||||
"main": [
|
"main": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue