From dae01f3abef57fcb62af1e2e15d807d612ab4252 Mon Sep 17 00:00:00 2001 From: OlegIvaniv Date: Tue, 18 Oct 2022 14:23:22 +0200 Subject: [PATCH] feat(editor, core, cli): implement new workflow experience (#4358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(ExecuteWorkflowTrigger node): Implement ExecuteWorkflowTrigger node (#4108) * feat(ExecuteWorkflowTrigger node): Implement ExecuteWorkflowTrigger node * feat(editor): Do not show duplicate button if canvas contains `maxNodes` amount of nodes * feat(ManualTrigger node): Implement ManualTrigger node (#4110) * feat(ManualTrigger node): Implement ManualTrigger node * :memo: Remove generics doc items from ManualTrigger node * feat(editor-ui): Trigger tab redesign (#4150) * :construction: Begin with TriggerPanel implementation, add Other Trigger Nodes subcategory * :construction: Extracted categorized categories/subcategory/nodes rendering into its own component — CategorizedItems, removed SubcategoryPanel, added translations * :sparkles: Implement MainPanel background scrim * :recycle: Move `categoriesWithNodes`, 'visibleNodeTypes` and 'categorizedItems` to store, implemented dynamic categories count based on `selectedType` * :bug: Fix SlideTransition for all the NodeCreato panels * :lipstick: Fix cursos for CategoryItem and NodeItem * :bug: Make sure ALL_NODE_FILTER is always set when MainPanel is mounted * :art: Address PR comments * label: Use Array type for CategorizedItems props * :label: Add proper types for Vue props * 🎨 Use standard component registration for CategorizedItems inside TriggerHelperPanel * 🎨 Use kebab case for main-panel and icon component * :label: Improve types * feat(editor-ui): Redesign search input inside node creator panel (#4204) * :construction: Begin with TriggerPanel implementation, add Other Trigger Nodes subcategory * :construction: Extracted categorized categories/subcategory/nodes rendering into its own component — CategorizedItems, removed SubcategoryPanel, added translations * :sparkles: Implement MainPanel background scrim * :recycle: Move `categoriesWithNodes`, 'visibleNodeTypes` and 'categorizedItems` to store, implemented dynamic categories count based on `selectedType` * :bug: Fix SlideTransition for all the NodeCreato panels * :lipstick: Fix cursos for CategoryItem and NodeItem * :bug: Make sure ALL_NODE_FILTER is always set when MainPanel is mounted * :art: Address PR comments * label: Use Array type for CategorizedItems props * :label: Add proper types for Vue props * 🎨 Use standard component registration for CategorizedItems inside TriggerHelperPanel * :sparkles: Redesign search input and unify usage of categorized items * :label: Use lowercase "Boolean" as `isSearchVisible` computed return type * :fire: Remove useless emit * :sparkles: Implement no result view based on subcategory, minor fixes * :art: Remove unused properties * feat(node-email): Change EmailReadImap display name and name (#4239) * feat(editor-ui): Implement "Choose a Triger" action and related behaviour (#4226) * :sparkles: Implement "Choose a Triger" action and related behaviour * :mute: Lint fix * :recycle: Remove PlaceholderTrigger node, add a button instead * :art: Merge onMouseEnter and onMouseLeave to a single function * :bulb: Add comment * :fire: Remove PlaceholderNode registration * :art: Rename TriggerPlaceholderButton to CanvasAddButton * :sparkles: Add method to unregister custom action and rework CanvasAddButton centering logic * :art: Run `setRecenteredCanvasAddButtonPosition` on `CanvasAddButton` mount * fix(editor): Fix selecting of node from node-creator panel by clicking * :twisted_rightwards_arrows: Merge fixes * fix(editor): Show execute workflow trigger instead of workflow trigger in the trigger helper panel * feat(editor): Fix node creator panel slide transition (#4261) * fix(editor): Fix node creator panel slide-in/slide-out transitions * :art: Fix naming * :art: Use kebab-case for transition component name * feat(editor): Disable execution and show notice when user tries to run workflow without enabled triggers * fix(editor): Address first batch of new WF experience review (#4279) * fix(editor): Fix first batch of review items * bug(editor): Fix nodeview canvas add button centering * :mute: Fix linter errors * bug(ManualTrigger Node): Fix manual trigger node execution * fix(editor): Do not show canvas add button in execution or demo mode and prevent clicking if creator is open * fix(editor): do not show pin data tooltip for manual trigger node * fix(editor): do not use nodeViewOffset on zoomToFit * :lipstick: Add margin for last node creator item and set font-weight to 700 for category title * :sparkles: Position welcome note next to the added trigger node * :bug: Remve always true welcome note * feat(editor): Minor UI and UX tweaks (#4328) * :lipstick: Make top viewport buttons less prominent * :sparkles: Allow user to switch to all tabs if it contains filter results, move nodecreator state props to its own module * :mute: Fix linting errors * :mute: Fix linting errors * :mute: Fix linting errors * chore(build): Ping Turbo version to 1.5.5 * :lipstick: Minor traigger panel and node view style changes * :speech_balloon: Update display name of execute workflow trigger * feat(core, editor): Update subworkflow execution logic (#4269) * :sparkles: Implement `findWorkflowStart` * :zap: Extend `WorkflowOperationError` * :zap: Add `WorkflowOperationError` to toast * :blue_book: Extend interface * :sparkles: Add `subworkflowExecutionError` to store * :sparkles: Create `SubworkflowOperationError` * :zap: Render subworkflow error as node error * :truck: Move subworkflow start validation to `cli` * :zap: Reset subworkflow execution error state * :fire: Remove unused import * :zap: Adjust CLI commands * :fire: Remove unneeded check * :fire: Remove stray log * :zap: Simplify syntax * :zap: Sort in case both Start and EWT present * :recycle: Address Omar's feedback * :fire: Remove unneeded lint exception * :pencil2: Fix copy * :shirt: Fix lint * fix: moved find start node function to catchable place Co-authored-by: Omar Ajoue * :lipstick: Change ExecuteWorkflow node to primary * :sparkles: Allow user to navigate to all tab if it contains search results * :bug: Fixed canvas control button while in demo, disable workflow activation for non-activavle nodes and revert zoomToFit bottom offset * :fix: Do not chow request text if there's results * :speech_balloon: Update noResults text Co-authored-by: Iván Ovejero Co-authored-by: Omar Ajoue --- package-lock.json | 12 +- packages/cli/commands/execute.ts | 35 +- packages/cli/commands/executeBatch.ts | 23 +- .../cli/src/WorkflowExecuteAdditionalData.ts | 20 +- packages/cli/src/WorkflowRunnerProcess.ts | 9 +- packages/cli/src/utils.ts | 30 + .../editor-ui/public/static/webhook-icon.svg | 9 + packages/editor-ui/src/Interface.ts | 22 + .../src/components/MainHeader/MainHeader.vue | 2 +- .../components/MainHeader/WorkflowDetails.vue | 1 + packages/editor-ui/src/components/Node.vue | 20 +- .../src/components/Node/NodeCreation.vue | 29 +- .../Node/NodeCreator/CategorizedItems.vue | 526 ++++++++++++++++++ .../Node/NodeCreator/CategoryItem.vue | 42 +- .../Node/NodeCreator/CreatorItem.vue | 27 +- .../Node/NodeCreator/ItemIterator.vue | 69 ++- .../components/Node/NodeCreator/MainPanel.vue | 337 ++--------- .../components/Node/NodeCreator/NoResults.vue | 73 ++- .../Node/NodeCreator/NodeCreator.vue | 94 ++-- .../components/Node/NodeCreator/NodeItem.vue | 48 +- .../components/Node/NodeCreator/SearchBar.vue | 98 ++-- .../Node/NodeCreator/SubcategoryItem.vue | 44 +- .../Node/NodeCreator/SubcategoryPanel.vue | 102 ---- .../Node/NodeCreator/TriggerHelperPanel.vue | 196 +++++++ .../Node/NodeCreator/TypeSelector.vue | 64 +++ .../components/Node/NodeCreator/helpers.ts | 142 +---- .../src/components/NodeExecuteButton.vue | 9 +- .../editor-ui/src/components/OutputPanel.vue | 4 +- packages/editor-ui/src/components/RunData.vue | 12 +- .../editor-ui/src/components/SaveButton.vue | 5 + packages/editor-ui/src/components/helpers.ts | 7 +- .../components/mixins/globalLinkActions.ts | 3 + .../src/components/mixins/nodeBase.ts | 32 +- .../src/components/mixins/pushConnection.ts | 36 +- .../src/components/mixins/workflowRun.ts | 2 + .../transitions/SlideTransition.vue | 5 +- packages/editor-ui/src/constants.ts | 16 + packages/editor-ui/src/modules/nodeCreator.ts | 39 ++ packages/editor-ui/src/modules/nodeTypes.ts | 16 +- .../editor-ui/src/modules/nodeTypesHelpers.ts | 150 +++++ packages/editor-ui/src/modules/ui.ts | 7 +- .../editor-ui/src/n8n-theme-variables.scss | 1 + .../src/plugins/i18n/locales/en.json | 28 +- packages/editor-ui/src/plugins/icons.ts | 6 + packages/editor-ui/src/store.ts | 10 + .../editor-ui/src/views/CanvasAddButton.vue | 95 ++++ packages/editor-ui/src/views/NodeView.vue | 341 +++++++++--- packages/editor-ui/src/views/canvasHelpers.ts | 66 ++- packages/nodes-base/nodes/Cron/Cron.node.ts | 4 +- .../EmailReadImap/EmailReadImap.node.json | 5 +- .../nodes/EmailReadImap/EmailReadImap.node.ts | 4 +- .../nodes/ErrorTrigger/ErrorTrigger.node.json | 5 +- .../ExecuteWorkflow/ExecuteWorkflow.node.ts | 2 +- .../ExecuteWorkflowTrigger.node.json | 21 + .../ExecuteWorkflowTrigger.node.ts | 36 ++ .../nodes/Interval/Interval.node.json | 5 +- .../LocalFileTrigger.node.json | 5 +- .../ManualTrigger/ManualTrigger.node.json | 16 + .../nodes/ManualTrigger/ManualTrigger.node.ts | 40 ++ .../nodes/N8nTrigger/N8nTrigger.node.json | 5 +- .../nodes/SseTrigger/SseTrigger.node.json | 5 +- .../WorkflowTrigger/WorkflowTrigger.node.json | 5 +- packages/nodes-base/package.json | 2 + packages/workflow/src/Workflow.ts | 19 +- packages/workflow/src/WorkflowErrors.ts | 21 +- 65 files changed, 2195 insertions(+), 969 deletions(-) create mode 100644 packages/cli/src/utils.ts create mode 100644 packages/editor-ui/public/static/webhook-icon.svg create mode 100644 packages/editor-ui/src/components/Node/NodeCreator/CategorizedItems.vue delete mode 100644 packages/editor-ui/src/components/Node/NodeCreator/SubcategoryPanel.vue create mode 100644 packages/editor-ui/src/components/Node/NodeCreator/TriggerHelperPanel.vue create mode 100644 packages/editor-ui/src/components/Node/NodeCreator/TypeSelector.vue create mode 100644 packages/editor-ui/src/modules/nodeCreator.ts create mode 100644 packages/editor-ui/src/modules/nodeTypesHelpers.ts create mode 100644 packages/editor-ui/src/views/CanvasAddButton.vue create mode 100644 packages/nodes-base/nodes/ExecuteWorkflowTrigger/ExecuteWorkflowTrigger.node.json create mode 100644 packages/nodes-base/nodes/ExecuteWorkflowTrigger/ExecuteWorkflowTrigger.node.ts create mode 100644 packages/nodes-base/nodes/ManualTrigger/ManualTrigger.node.json create mode 100644 packages/nodes-base/nodes/ManualTrigger/ManualTrigger.node.ts diff --git a/package-lock.json b/package-lock.json index 8ca12dd97b..35d4ed9d18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "n8n", - "version": "0.198.0", + "version": "0.198.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "n8n", - "version": "0.198.0", + "version": "0.198.2", "hasInstallScript": true, "workspaces": [ "packages/*", @@ -43375,7 +43375,7 @@ }, "packages/cli": { "name": "n8n", - "version": "0.198.0", + "version": "0.198.2", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@oclif/command": "^1.5.18", @@ -43422,7 +43422,7 @@ "lodash.unset": "^4.5.2", "mysql2": "~2.3.0", "n8n-core": "~0.138.0", - "n8n-editor-ui": "~0.164.0", + "n8n-editor-ui": "~0.164.2", "n8n-nodes-base": "~0.196.0", "n8n-workflow": "~0.120.0", "nodemailer": "^6.7.1", @@ -45822,7 +45822,7 @@ }, "packages/editor-ui": { "name": "n8n-editor-ui", - "version": "0.164.0", + "version": "0.164.2", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@codemirror/autocomplete": "^6.1.0", @@ -72169,7 +72169,7 @@ "lodash.unset": "^4.5.2", "mysql2": "~2.3.0", "n8n-core": "~0.138.0", - "n8n-editor-ui": "~0.164.0", + "n8n-editor-ui": "~0.164.2", "n8n-nodes-base": "~0.196.0", "n8n-workflow": "~0.120.0", "nodemailer": "^6.7.1", diff --git a/packages/cli/commands/execute.ts b/packages/cli/commands/execute.ts index 1651488da7..772dd0e544 100644 --- a/packages/cli/commands/execute.ts +++ b/packages/cli/commands/execute.ts @@ -4,7 +4,7 @@ import { promises as fs } from 'fs'; import { Command, flags } from '@oclif/command'; import { BinaryDataManager, UserSettings, PLACEHOLDER_EMPTY_WORKFLOW_ID } from 'n8n-core'; -import { INode, LoggerProxy } from 'n8n-workflow'; +import { LoggerProxy } from 'n8n-workflow'; import { ActiveExecutions, @@ -25,6 +25,7 @@ import { import { getLogger } from '../src/Logger'; import config from '../config'; import { getInstanceOwner } from '../src/UserManagement/UserManagementHelper'; +import { findCliWorkflowStart } from '../src/utils'; export class Execute extends Command { static description = '\nExecutes a given workflow'; @@ -116,6 +117,10 @@ export class Execute extends Command { } } + if (!workflowData) { + throw new Error('Failed to retrieve workflow data for requested workflow'); + } + // Make sure the settings exist await UserSettings.prepareUserSettings(); @@ -144,33 +149,14 @@ export class Execute extends Command { workflowId = undefined; } - // Check if the workflow contains the required "Start" node - // "requiredNodeTypes" are also defined in editor-ui/views/NodeView.vue - const requiredNodeTypes = ['n8n-nodes-base.start']; - let startNode: INode | undefined; - // eslint-disable-next-line no-restricted-syntax, @typescript-eslint/no-non-null-assertion - for (const node of workflowData!.nodes) { - if (requiredNodeTypes.includes(node.type)) { - startNode = node; - break; - } - } - - if (startNode === undefined) { - // If the workflow does not contain a start-node we can not know what - // should be executed and with which data to start. - console.info(`The workflow does not contain a "Start" node. So it can not be executed.`); - // eslint-disable-next-line consistent-return - return Promise.resolve(); - } - try { + const startingNode = findCliWorkflowStart(workflowData.nodes); + const user = await getInstanceOwner(); const runData: IWorkflowExecutionDataProcess = { executionMode: 'cli', - startNodes: [startNode.name], - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - workflowData: workflowData!, + startNodes: [startingNode.name], + workflowData, userId: user.id, }; @@ -207,6 +193,7 @@ export class Execute extends Command { logger.error('\nExecution error:'); logger.info('===================================='); logger.error(e.message); + if (e.description) logger.error(e.description); logger.error(e.stack); this.exit(1); } diff --git a/packages/cli/commands/executeBatch.ts b/packages/cli/commands/executeBatch.ts index d2887eb470..3f4ffd9236 100644 --- a/packages/cli/commands/executeBatch.ts +++ b/packages/cli/commands/executeBatch.ts @@ -39,6 +39,7 @@ import { import config from '../config'; import { User } from '../src/databases/entities/User'; import { getInstanceOwner } from '../src/UserManagement/UserManagementHelper'; +import { findCliWorkflowStart } from '../src/utils'; export class ExecuteBatch extends Command { static description = '\nExecutes multiple workflows once'; @@ -613,16 +614,6 @@ export class ExecuteBatch extends Command { coveredNodes: {}, }; - const requiredNodeTypes = ['n8n-nodes-base.start']; - let startNode: INode | undefined; - // eslint-disable-next-line no-restricted-syntax - for (const node of workflowData.nodes) { - if (requiredNodeTypes.includes(node.type)) { - startNode = node; - break; - } - } - // We have a cool feature here. // On each node, on the Settings tab in the node editor you can change // the `Notes` field to add special cases for comparison and snapshots. @@ -659,14 +650,6 @@ export class ExecuteBatch extends Command { }); return new Promise(async (resolve) => { - if (startNode === undefined) { - // If the workflow does not contain a start-node we can not know what - // should be executed and with which data to start. - executionResult.error = 'Workflow cannot be started as it does not contain a "Start" node.'; - executionResult.executionStatus = 'warning'; - resolve(executionResult); - } - let gotCancel = false; // Timeouts execution after 5 minutes. @@ -678,9 +661,11 @@ export class ExecuteBatch extends Command { }, ExecuteBatch.executionTimeout); try { + const startingNode = findCliWorkflowStart(workflowData.nodes); + const runData: IWorkflowExecutionDataProcess = { executionMode: 'cli', - startNodes: [startNode!.name], + startNodes: [startingNode.name], workflowData, userId: ExecuteBatch.instanceOwner.id, }; diff --git a/packages/cli/src/WorkflowExecuteAdditionalData.ts b/packages/cli/src/WorkflowExecuteAdditionalData.ts index 7f22086156..fc5ad0aad4 100644 --- a/packages/cli/src/WorkflowExecuteAdditionalData.ts +++ b/packages/cli/src/WorkflowExecuteAdditionalData.ts @@ -33,6 +33,7 @@ import { IWorkflowHooksOptionalParameters, IWorkflowSettings, LoggerProxy as Logger, + SubworkflowOperationError, Workflow, WorkflowExecuteMode, WorkflowHooks, @@ -67,6 +68,7 @@ import { } from './UserManagement/UserManagementHelper'; import { whereClause } from './WorkflowHelpers'; import { IWorkflowErrorData } from './Interfaces'; +import { findSubworkflowStart } from './utils'; const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType'); @@ -748,21 +750,7 @@ export async function getRunData( ): Promise { const mode = 'integrated'; - // Find Start-Node - const requiredNodeTypes = ['n8n-nodes-base.start']; - let startNode: INode | undefined; - // eslint-disable-next-line no-restricted-syntax - for (const node of workflowData.nodes) { - if (requiredNodeTypes.includes(node.type)) { - startNode = node; - break; - } - } - if (startNode === undefined) { - // If the workflow does not contain a start-node we can not know what - // should be executed and with what data to start. - throw new Error(`The workflow does not contain a "Start" node and can so not be executed.`); - } + const startingNode = findSubworkflowStart(workflowData.nodes); // Always start with empty data if no inputData got supplied inputData = inputData || [ @@ -774,7 +762,7 @@ export async function getRunData( // Initialize the incoming data const nodeExecutionStack: IExecuteData[] = []; nodeExecutionStack.push({ - node: startNode, + node: startingNode, data: { main: [inputData], }, diff --git a/packages/cli/src/WorkflowRunnerProcess.ts b/packages/cli/src/WorkflowRunnerProcess.ts index abf501b93d..5557dec170 100644 --- a/packages/cli/src/WorkflowRunnerProcess.ts +++ b/packages/cli/src/WorkflowRunnerProcess.ts @@ -361,11 +361,12 @@ export class WorkflowRunnerProcess { ) { // Execute all nodes + const pinDataKeys = this.data?.pinData ? Object.keys(this.data.pinData) : []; + const noPinData = pinDataKeys.length === 0; + const isPinned = (nodeName: string) => pinDataKeys.includes(nodeName); + let startNode; - if ( - this.data.startNodes?.length === 1 && - Object.keys(this.data.pinData ?? {}).includes(this.data.startNodes[0]) - ) { + if (this.data.startNodes?.length === 1 && (noPinData || isPinned(this.data.startNodes[0]))) { startNode = this.workflow.getNode(this.data.startNodes[0]) ?? undefined; } diff --git a/packages/cli/src/utils.ts b/packages/cli/src/utils.ts new file mode 100644 index 0000000000..d026bd3190 --- /dev/null +++ b/packages/cli/src/utils.ts @@ -0,0 +1,30 @@ +import { CliWorkflowOperationError, SubworkflowOperationError } from 'n8n-workflow'; +import type { INode } from 'n8n-workflow'; + +function findWorkflowStart(executionMode: 'integrated' | 'cli') { + return function (nodes: INode[]) { + const executeWorkflowTriggerNode = nodes.find( + (node) => node.type === 'n8n-nodes-base.executeWorkflowTrigger', + ); + + if (executeWorkflowTriggerNode) return executeWorkflowTriggerNode; + + const startNode = nodes.find((node) => node.type === 'n8n-nodes-base.start'); + + if (startNode) return startNode; + + const title = 'Missing node to start execution'; + const description = + "Please make sure the workflow you're calling contains an Execute Workflow Trigger node"; + + if (executionMode === 'integrated') { + throw new SubworkflowOperationError(title, description); + } + + throw new CliWorkflowOperationError(title, description); + }; +} + +export const findSubworkflowStart = findWorkflowStart('integrated'); + +export const findCliWorkflowStart = findWorkflowStart('cli'); diff --git a/packages/editor-ui/public/static/webhook-icon.svg b/packages/editor-ui/public/static/webhook-icon.svg new file mode 100644 index 0000000000..87c4107180 --- /dev/null +++ b/packages/editor-ui/public/static/webhook-icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index b2d8839d75..437b32f58b 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -269,6 +269,11 @@ export interface IWorkflowTemplate { }; } +export interface INewWorkflowData { + name: string; + onboardingFlowEnabled: boolean; +} + // Almost identical to cli.Interfaces.ts export interface IWorkflowDb { id: string; @@ -756,6 +761,13 @@ export type WorkflowTitleStatus = 'EXECUTING' | 'IDLE' | 'ERROR'; export interface ISubcategoryItemProps { subcategory: string; description: string; + icon?: string; + defaults?: INodeParameters; + iconData?: { + type: string; + icon?: string; + fileBuffer?: string; + }; } export interface INodeItemProps { @@ -876,6 +888,7 @@ export interface IRootState { instanceId: string; nodeMetadata: {[nodeName: string]: INodeMetadata}; isNpmAvailable: boolean; + subworkflowExecutionError: Error | null; } export interface ICommunityPackageMap { @@ -981,6 +994,15 @@ export type IFakeDoor = { export type IFakeDoorLocation = 'settings' | 'credentialsModal'; +export type INodeFilterType = "Regular" | "Trigger" | "All"; + +export interface INodeCreatorState { + itemsFilter: string; + showTabs: boolean; + showScrim: boolean; + selectedType: INodeFilterType; +} + export interface ISettingsState { settings: IN8nUISettings; promptsData: IN8nPrompts; diff --git a/packages/editor-ui/src/components/MainHeader/MainHeader.vue b/packages/editor-ui/src/components/MainHeader/MainHeader.vue index d82828f01a..da70f58d40 100644 --- a/packages/editor-ui/src/components/MainHeader/MainHeader.vue +++ b/packages/editor-ui/src/components/MainHeader/MainHeader.vue @@ -56,7 +56,7 @@ export default mixins( diff --git a/packages/editor-ui/src/components/Node/NodeCreator/CategorizedItems.vue b/packages/editor-ui/src/components/Node/NodeCreator/CategorizedItems.vue new file mode 100644 index 0000000000..8887d79597 --- /dev/null +++ b/packages/editor-ui/src/components/Node/NodeCreator/CategorizedItems.vue @@ -0,0 +1,526 @@ + + + + + diff --git a/packages/editor-ui/src/components/Node/NodeCreator/CategoryItem.vue b/packages/editor-ui/src/components/Node/NodeCreator/CategoryItem.vue index 4acee002dd..1e824808da 100644 --- a/packages/editor-ui/src/components/Node/NodeCreator/CategoryItem.vue +++ b/packages/editor-ui/src/components/Node/NodeCreator/CategoryItem.vue @@ -1,7 +1,7 @@