feat(editor): Unify regular and trigger node creator panels (#5315)
* WIP: Merge TriggerHelperPanel with MainPanel * WIP: Implement switching between views * Remove logging * WIP: Rework search * Fix category toggling and search results display * Fix node item description * Sort actions based on the root view * Adjust personalisation modal, make trigger canvas node round * Linting fixes * Fix filtering of API options * Fix types and no result state * Cleanup * Linting fixes * Adjust mode prop for node creator tracking * Fix merging of core nodes and filtering of single placeholder actions * Lint fixes * Implement actions override, fix node creator view item spacing and increase click radius of trigger node icon * Fix keyboard view navigation * WIP: E2E Tests * Address product review * Minor fixes & cleanup * Fix tests * Some more test fixes * Add specs to check actions and panels * Update personalisation survey snapshot
This commit is contained in:
@@ -14,16 +14,14 @@ import {
|
||||
STORES,
|
||||
MANUAL_TRIGGER_NODE_TYPE,
|
||||
CORE_NODES_CATEGORY,
|
||||
CALENDLY_TRIGGER_NODE_TYPE,
|
||||
TRIGGER_NODE_FILTER,
|
||||
WEBHOOK_NODE_TYPE,
|
||||
STICKY_NODE_TYPE,
|
||||
} from '@/constants';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes';
|
||||
import { useWorkflowsStore } from './workflows';
|
||||
import { CUSTOM_API_CALL_KEY, ALL_NODE_FILTER } from '@/constants';
|
||||
import { INodeCreatorState, INodeFilterType, IUpdateInformation } from '@/Interface';
|
||||
import { i18n } from '@/plugins/i18n';
|
||||
import { BaseTextKey, i18n } from '@/plugins/i18n';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { Telemetry } from '@/plugins/telemetry';
|
||||
|
||||
@@ -42,7 +40,7 @@ const customNodeActionsParsers: {
|
||||
(categoryItem): INodeActionTypeDescription => ({
|
||||
...getNodeTypeBase(
|
||||
nodeTypeDescription,
|
||||
i18n.baseText('nodeCreator.actionsCategory.recommended'),
|
||||
i18n.baseText('nodeCreator.actionsCategory.triggers'),
|
||||
),
|
||||
actionKey: categoryItem.value as string,
|
||||
displayName: i18n.baseText('nodeCreator.actionsCategory.onEvent', {
|
||||
@@ -81,7 +79,9 @@ function getNodeTypeBase(nodeTypeDescription: INodeTypeDescription, category: st
|
||||
iconUrl: nodeTypeDescription.iconUrl,
|
||||
icon: nodeTypeDescription.icon,
|
||||
version: [1],
|
||||
defaults: {},
|
||||
defaults: {
|
||||
...nodeTypeDescription.defaults,
|
||||
},
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
properties: [],
|
||||
@@ -104,10 +104,7 @@ function operationsCategory(
|
||||
);
|
||||
|
||||
const items = filteredOutItems.map((item: INodePropertyOptions) => ({
|
||||
...getNodeTypeBase(
|
||||
nodeTypeDescription,
|
||||
i18n.baseText('nodeCreator.actionsCategory.operations'),
|
||||
),
|
||||
...getNodeTypeBase(nodeTypeDescription, i18n.baseText('nodeCreator.actionsCategory.actions')),
|
||||
actionKey: item.value as string,
|
||||
displayName: item.action ?? startCase(item.name),
|
||||
description: item.description ?? '',
|
||||
@@ -123,9 +120,7 @@ function operationsCategory(
|
||||
return items;
|
||||
}
|
||||
|
||||
function recommendedCategory(
|
||||
nodeTypeDescription: INodeTypeDescription,
|
||||
): INodeActionTypeDescription[] {
|
||||
function triggersCategory(nodeTypeDescription: INodeTypeDescription): INodeActionTypeDescription[] {
|
||||
const matchingKeys = ['event', 'events', 'trigger on'];
|
||||
const isTrigger = nodeTypeDescription.displayName?.toLowerCase().includes('trigger');
|
||||
const matchedProperty = nodeTypeDescription.properties.find((property) =>
|
||||
@@ -141,7 +136,7 @@ function recommendedCategory(
|
||||
{
|
||||
...getNodeTypeBase(
|
||||
nodeTypeDescription,
|
||||
i18n.baseText('nodeCreator.actionsCategory.recommended'),
|
||||
i18n.baseText('nodeCreator.actionsCategory.triggers'),
|
||||
),
|
||||
actionKey: PLACEHOLDER_RECOMMENDED_ACTION_KEY,
|
||||
displayName: i18n.baseText('nodeCreator.actionsCategory.onNewEvent', {
|
||||
@@ -166,7 +161,7 @@ function recommendedCategory(
|
||||
filteredOutItems.map((categoryItem: INodePropertyOptions) => ({
|
||||
...getNodeTypeBase(
|
||||
nodeTypeDescription,
|
||||
i18n.baseText('nodeCreator.actionsCategory.recommended'),
|
||||
i18n.baseText('nodeCreator.actionsCategory.triggers'),
|
||||
),
|
||||
actionKey: categoryItem.value as string,
|
||||
displayName:
|
||||
@@ -247,19 +242,26 @@ function resourceCategories(
|
||||
export const useNodeCreatorStore = defineStore(STORES.NODE_CREATOR, {
|
||||
state: (): INodeCreatorState => ({
|
||||
itemsFilter: '',
|
||||
showTabs: true,
|
||||
showScrim: false,
|
||||
selectedType: ALL_NODE_FILTER,
|
||||
selectedView: TRIGGER_NODE_FILTER,
|
||||
rootViewHistory: [],
|
||||
}),
|
||||
actions: {
|
||||
setShowTabs(isVisible: boolean) {
|
||||
this.showTabs = isVisible;
|
||||
},
|
||||
setShowScrim(isVisible: boolean) {
|
||||
this.showScrim = isVisible;
|
||||
},
|
||||
setSelectedType(selectedNodeType: INodeFilterType) {
|
||||
this.selectedType = selectedNodeType;
|
||||
setSelectedView(selectedNodeType: INodeFilterType) {
|
||||
this.selectedView = selectedNodeType;
|
||||
if (!this.rootViewHistory.includes(selectedNodeType)) {
|
||||
this.rootViewHistory.push(selectedNodeType);
|
||||
}
|
||||
},
|
||||
closeCurrentView() {
|
||||
this.rootViewHistory.pop();
|
||||
this.selectedView = this.rootViewHistory[this.rootViewHistory.length - 1];
|
||||
},
|
||||
resetRootViewHistory() {
|
||||
this.rootViewHistory = [];
|
||||
},
|
||||
setFilter(search: string) {
|
||||
this.itemsFilter = search;
|
||||
@@ -295,16 +297,11 @@ export const useNodeCreatorStore = defineStore(STORES.NODE_CREATOR, {
|
||||
visibleNodesWithActions(): INodeTypeDescription[] {
|
||||
const nodes = deepCopy(useNodeTypesStore().visibleNodeTypes);
|
||||
const nodesWithActions = nodes.map((node) => {
|
||||
const isCoreNode = node.codex?.categories?.includes(CORE_NODES_CATEGORY);
|
||||
// Core nodes shouldn't support actions
|
||||
node.actions = [];
|
||||
if (isCoreNode) return node;
|
||||
|
||||
node.actions.push(
|
||||
...recommendedCategory(node),
|
||||
node.actions = [
|
||||
...triggersCategory(node),
|
||||
...operationsCategory(node),
|
||||
...resourceCategories(node),
|
||||
);
|
||||
];
|
||||
|
||||
return node;
|
||||
});
|
||||
@@ -322,20 +319,15 @@ export const useNodeCreatorStore = defineStore(STORES.NODE_CREATOR, {
|
||||
})
|
||||
.reduce((acc: Record<string, INodeTypeDescription>, node: INodeTypeDescription) => {
|
||||
const clonedNode = deepCopy(node);
|
||||
const isCoreNode = node.codex?.categories?.includes(CORE_NODES_CATEGORY);
|
||||
const actions = node.actions || [];
|
||||
// Do not merge core nodes
|
||||
const normalizedName = isCoreNode
|
||||
? node.name
|
||||
: node.name.toLowerCase().replace('trigger', '');
|
||||
const normalizedName = node.name.toLowerCase().replace('trigger', '');
|
||||
const existingNode = acc[normalizedName];
|
||||
|
||||
if (existingNode) existingNode.actions?.push(...actions);
|
||||
else acc[normalizedName] = clonedNode;
|
||||
|
||||
if (!isCoreNode) {
|
||||
acc[normalizedName].displayName = node.displayName.replace('Trigger', '');
|
||||
}
|
||||
acc[normalizedName].displayName = node.displayName.replace('Trigger', '');
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
@@ -355,7 +347,7 @@ export const useNodeCreatorStore = defineStore(STORES.NODE_CREATOR, {
|
||||
const { workflowTriggerNodes } = useWorkflowsStore();
|
||||
const isTrigger = useNodeTypesStore().isTriggerNode(nodeType);
|
||||
const workflowContainsTrigger = workflowTriggerNodes.length > 0;
|
||||
const isTriggerPanel = useNodeCreatorStore().selectedType === TRIGGER_NODE_FILTER;
|
||||
const isTriggerPanel = useNodeCreatorStore().selectedView === TRIGGER_NODE_FILTER;
|
||||
const isStickyNode = nodeType === STICKY_NODE_TYPE;
|
||||
|
||||
const nodeTypes =
|
||||
|
||||
Reference in New Issue
Block a user