2019-06-23 03:35:23 -07:00
< template >
2022-12-14 01:04:10 -08:00
< div :class ="$style['content']" >
2022-10-26 01:02:56 -07:00
< div
2023-01-30 09:20:50 -08:00
class = "node-view-root do-not-select"
2022-12-14 01:04:10 -08:00
id = "node-view-root"
data - test - id = "node-view-root"
@ dragover = "onDragOver"
@ drop = "onDrop"
2022-10-26 01:02:56 -07:00
>
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
< div
2022-12-14 01:04:10 -08:00
class = "node-view-wrapper"
: class = "workflowClasses"
@ touchstart = "mouseDown"
@ touchend = "mouseUp"
@ touchmove = "mouseMoveNodeWorkflow"
@ mousedown = "mouseDown"
v - touch : tap = "touchTap"
@ mouseup = "mouseUp"
@ wheel = "canvasStore.wheelScroll"
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
>
2022-12-23 04:37:32 -08:00
< div
id = "node-view-background"
class = "node-view-background"
: style = "backgroundStyle"
data - test - id = "node-view-background"
/ >
< div
id = "node-view"
class = "node-view"
: style = "workflowStyle"
ref = "nodeView"
data - test - id = "node-view"
>
2022-12-14 01:04:10 -08:00
< canvas -add -button
: style = "canvasAddButtonStyle"
@ click = "showTriggerCreator('trigger_placeholder_button')"
v - show = "showCanvasAddButton"
: showTooltip = "!containsTrigger && showTriggerMissingTooltip"
: position = "canvasStore.canvasAddButtonPosition"
2023-01-30 09:20:50 -08:00
ref = "canvasAddButton"
2022-12-14 01:04:10 -08:00
@ hook : mounted = "canvasStore.setRecenteredCanvasAddButtonPosition"
data - test - id = "canvas-add-button"
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
/ >
2023-01-30 09:20:50 -08:00
< template v-for ="nodeData in nodes" >
2022-12-14 01:04:10 -08:00
< node
v - if = "nodeData.type !== STICKY_NODE_TYPE"
@ duplicateNode = "duplicateNode"
@ deselectAllNodes = "deselectAllNodes"
@ deselectNode = "nodeDeselectedByName"
@ nodeSelected = "nodeSelectedByName"
@ removeNode = "(name) => removeNode(name, true)"
@ runWorkflow = "onRunNode"
@ moved = "onNodeMoved"
@ run = "onNodeRun"
: key = "`${nodeData.id}_node`"
: name = "nodeData.name"
: isReadOnly = "isReadOnly"
: instance = "instance"
: isActive = "!!activeNode && activeNode.name === nodeData.name"
: hideActions = "pullConnActive"
: isProductionExecutionPreview = "isProductionExecutionPreview"
>
< template # custom -tooltip >
< span
v - text = "
$locale . baseText ( 'nodeView.placeholderNode.addTriggerNodeBeforeExecuting' )
"
/ >
< / template >
< / node >
< sticky
v - else
@ deselectAllNodes = "deselectAllNodes"
@ deselectNode = "nodeDeselectedByName"
@ nodeSelected = "nodeSelectedByName"
@ removeNode = "(name) => removeNode(name, true)"
: key = "`${nodeData.id}_sticky`"
: name = "nodeData.name"
: isReadOnly = "isReadOnly"
: instance = "instance"
: isActive = "!!activeNode && activeNode.name === nodeData.name"
: nodeViewScale = "nodeViewScale"
: gridSize = "GRID_SIZE"
: hideActions = "pullConnActive"
/ >
2023-01-30 09:20:50 -08:00
< / template >
feat(editor): Add Workflow Stickies (Notes) (#3154)
* N8N-3029 Add Node Type for Wokrflow Stickies/Notes
* N8N-3029 Update Content, Update Aliasses
* N8N-3030 Created N8N Sticky Component in Design System
* N8N-3030 Fixed Code spaccing Sticky Component
* N8N-3030 Fixed Code spaccing StickyStories Component
* N8N-3030 Fixed Code spaccing Markdown Component
* N8N-3030 Added Sticky Colors Pallete into Storybook, Update Color Variables for Sticky Component
* N8N-3030 Added Unfocus Event
* N8N-3030 Update Default Placeholder, Markdown Styles, Fixed Edit State, Added Text to EditState, Fixed Height of Area, Turned off Resize of textarea
* N8N-3030 Update Sticky Overflow, Update Hover States, Updated Markdown Overflow
* N8N-3030, N8N-3031 - Add Resize to Sticky, Created N8n-Resize component
* N8N-3031 Fixed Importing Components in Editor-ui
* N8N-3031 Fixed Resize Component, Fixed Gradient
* N8N-3030, N8N-3031 Update Note Description
* N8N-3032 Hotfix Building Storybook
* N8N-3032 - Select Behaviour, Changes in Resize Component, Emit on Width/Height/Top/Left Change
* N8N-3032 Update Resize Component to emmit left/top, Update Dynamic Resize on Selected Background
* N8N-3032 Updated / Dragging vs Resizing, prevent open Modal for stickies
* N8N-3032 Added ID props to n8n-sticky // dynamic id for multi resizing in NodeView
* N8N-3033 Add dynamic size Tooltip on Sticky
* N8N-3033 Updated Z-index for Sticky Component
* N8N-3033 Updated N8N-Resize Component, Fixed SelectedBackround for Sticky Component
* N8N-3033 Refactor
* N8N-3033 Focus/Defocus on TextArea
* N8N-3033 Fixed Resizing on NW Point
* N8N-3030 Save content in vuex on input change
* N8N-3033 Fixed Resizer, Save Width and Height in Vue
* N8N-3033 Hide Sticky Footer on small height/width
* N8N-3033 Fixed Resizer
* N8N-3033 Dynamic Z-index for Stickies
* N8N-3033 Dynamic Z-index for Stickies
* N8N-3033 Removed static z-index for select sticky class
* N8N-3034 Added Telemetry
* N8N-3030 Formatter
* N8N-3030 Format code
* N8N-3030 Fixed Selecting Stickies
* N8N-3033 Fixed Notifications
* N8N-3030 Added new paddings for Default Stickies
* N8N-3033 Prevent Scrolling NodeView when Sticky is in Edit mode and Mouse is Over the TextArea
* N8N-3030 Prevent double clicking to switch state of Sticky component in Edit Mode
* N8N-3033 Fixed Z-index of Stickies
* N8N-3033 Prevent delete node when in EditMode
* N8N-3030 Prevent Delete Button to delete the Sticky while in Edit Mode
* N8N-3030 Change EditMode (emit) on keyboard shortucts, update Markdown Links & Images, Added new props
* N8N-3030 Sticky Component - No padding when hiding footer text
* N8N-3033 Fix Resizing enter into Edit Mode
* N8N-3033 Selecting different nodes - exit the edit mode
* N8N-3033 Auto Select Text in text-area by default - Sticky Component
* N8N-3033 Prevent Default behaviour for CTRL + X, CTRL + A when Sticky is Active && inEditMode
* N8N-3033 Refactor Resizer, Refactor Sticky, Update zIndex inEditMode
* N8N-3033 Updated Default Text // Node-base, Storybook
* N8N-3033 Add Resizing in EditMode - Components update
* N8N-3033 Fixed Footer - Show/Hide on Resize in EditMode
* N8N-3033 Fix ActiveSticky on Init
* N8N-3033 Refactor Sticky in Vuex, Fixed Init Sticky Tweaks, Prevent Modal Openning, Save on Keyboard shortcuts
* Stickies - Update Note node with new props
* N8N-3030 Updated Default Note text, Update the Markdown Link
* N8N-3030 CMD-C does not copy the text fix
* N8N-3030 Fix Max Zoom / Zoom out shortcuts disabled in editState
* N8N-3030 Z-index fixed during Edit Mode typing
* N8N-3030 Prevent Autoselect Text in Stickies if the text is not default
* N8N-3030 Fixed ReadOnly Bugs / Prevent showing Tooltip, Resizing
* N8N-3030 Added Sticky Creator Button
* N8N-3030 Update Icon / Sticky Creator Button
* N8N-3033 Update Sticky Icon / StickyCreator Button
* update package lock
* 🔩 update note props
* 🚿 clean props
* 🔧 linting
* :wrench: fix spacing
* remove resize component
* remove resize component
* ✂ clean up sticky
* revert back to height width
* revert back to height/width
* replace zindex property
* replace default text property
* use i18n to translate
* update package lock
* move resize
* clean up how height/width are set
* fix resize for sticky to support left/top
* clean up resize
* fix lasso/highlight bug
* remove unused props
* fix zoom to fit
* fix padding for demo view
* fix readonly
* remove iseditable, use active state
* clean up keyboard events
* chang button size, no edit on insert
* scale resizing correctly
* make active on resize
* fix select on resize/move
* use outline icon
* allow for multiple line breaks
* fix multi line bug
* fix edit mode outline
* keep edit open as one resizes
* respect multiple spaces
* fix scrolling bug
* clean up hover impl
* clean up references to note
* disable for rename
* fix drifting while drag
* fix mouse cursor on resize
* fix sticky min height
* refactor resize into component
* fix pulling too far bug
* fix delete/cut all bug
* fix padding bottom
* fix active change on resize
* add transition to button
* Fix sticky markdown click
* add solid fa icon
* update node graph, telemetry event
* add snapping
* change alt text
* update package lock
* fix bug in button hover
* add back transition
* clean up resize
* add grid size as param
* remove breaks
* clean up markdown
* lint fixes
* fix spacing
* clean up markdown colors
* clean up classes in resize
* clean up resize
* update sticky story
* fix spacing
* clean up classes
* revert change
* revert change
* revert change
* clean up sticky component
* remove unused component
* remove unnessary data
* remove unnessary data
* clean up actions
* clean up sticky size
* clean up unnessary border style
* fix bug
* replace sticky note name
* update description
* remove support for multi spaces
* update tracking name
* update telemetry reqs
* fix enter bug
* update alt text
* update sticky notes doc url
* fix readonly bug
* update class name
* update quote marks
Co-authored-by: SchnapsterDog <olivertrajceski@yahoo.com>
2022-04-25 03:38:37 -07:00
< / div >
2019-06-23 03:35:23 -07:00
< / div >
2022-12-14 01:04:10 -08:00
< node -details -view
: readOnly = "isReadOnly"
: renaming = "renamingActive"
: isProductionExecutionPreview = "isProductionExecutionPreview"
@ valueChanged = "valueChanged"
@ stopExecution = "stopExecution"
/ >
< node -creation
v - if = "!isReadOnly"
: create - node - active = "createNodeActive"
: node - view - scale = "nodeViewScale"
@ toggleNodeCreator = "onToggleNodeCreator"
@ addNode = "onAddNode"
/ >
< canvas -controls / >
< div class = "workflow-execute-wrapper" v-if ="!isReadOnly" >
< span
@ mouseenter = "showTriggerMissingToltip(true)"
@ mouseleave = "showTriggerMissingToltip(false)"
@ click = "onRunContainerClick"
>
< n8n -button
@ click . stop = "onRunWorkflow"
: loading = "workflowRunning"
: label = "runButtonText"
: title = "$locale.baseText('nodeView.executesTheWorkflowFromATriggerNode')"
size = "large"
icon = "play-circle"
type = "primary"
: disabled = "isExecutionDisabled"
2022-12-20 01:33:20 -08:00
data - test - id = "execute-workflow-button"
2022-12-14 01:04:10 -08:00
/ >
< / span >
< n8n -icon -button
v - if = "workflowRunning === true && !executionWaitingForWebhook"
icon = "stop"
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
size = "large"
2022-12-14 01:04:10 -08:00
class = "stop-execution"
type = "secondary"
: title = "
stopExecutionInProgress
? $locale . baseText ( 'nodeView.stoppingCurrentExecution' )
: $locale . baseText ( 'nodeView.stopCurrentExecution' )
"
: loading = "stopExecutionInProgress"
@ click . stop = "stopExecution"
2023-02-16 02:41:25 -08:00
data - test - id = "stop-execution-button"
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
/ >
2022-09-29 03:33:16 -07:00
2022-12-14 01:04:10 -08:00
< n8n -icon -button
v - if = "workflowRunning === true && executionWaitingForWebhook === true"
class = "stop-execution"
icon = "stop"
size = "large"
: title = "$locale.baseText('nodeView.stopWaitingForWebhookCall')"
type = "secondary"
@ click . stop = "stopWaitingForWebhook"
2023-02-16 02:41:25 -08:00
data - test - id = "stop-execution-waiting-for-webhook-button"
2022-12-14 01:04:10 -08:00
/ >
2022-09-29 03:33:16 -07:00
2022-12-14 01:04:10 -08:00
< n8n -icon -button
v - if = "!isReadOnly && workflowExecution && !workflowRunning && !allTriggersDisabled"
: title = "$locale.baseText('nodeView.deletesTheCurrentExecutionData')"
icon = "trash"
size = "large"
@ click . stop = "clearExecutionData"
2023-02-16 02:41:25 -08:00
data - test - id = "clear-execution-data-button"
2022-12-14 01:04:10 -08:00
/ >
< / div >
2019-06-23 03:35:23 -07:00
< / div >
< / div >
< / template >
< script lang = "ts" >
2023-01-30 09:20:50 -08:00
import Vue , { ComponentInstance } from 'vue' ;
2022-11-07 00:53:27 -08:00
import { mapStores } from 'pinia' ;
2023-01-30 09:20:50 -08:00
import {
2022-12-14 01:04:10 -08:00
Endpoint ,
2023-01-30 09:20:50 -08:00
Connection ,
EVENT _CONNECTION ,
ConnectionEstablishedParams ,
EVENT _CONNECTION _DETACHED ,
EVENT _CONNECTION _MOVED ,
INTERCEPT _BEFORE _DROP ,
BeforeDropParams ,
ConnectionDetachedParams ,
ConnectionMovedParams ,
} from '@jsplumb/core' ;
2022-09-23 07:14:28 -07:00
import type { MessageBoxInputData } from 'element-ui/types/message-box' ;
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
2022-07-27 07:28:13 -07:00
import {
FIRST _ONBOARDING _PROMPT _TIMEOUT ,
2022-10-26 01:02:56 -07:00
MAIN _HEADER _TABS ,
2022-07-27 07:28:13 -07:00
MODAL _CANCEL ,
MODAL _CLOSE ,
MODAL _CONFIRMED ,
NODE _OUTPUT _DEFAULT _KEY ,
ONBOARDING _CALL _SIGNUP _MODAL _KEY ,
ONBOARDING _PROMPT _TIMEBOX ,
PLACEHOLDER _EMPTY _WORKFLOW _ID ,
QUICKSTART _NOTE _NAME ,
START _NODE _TYPE ,
STICKY _NODE _TYPE ,
VIEWS ,
WEBHOOK _NODE _TYPE ,
2022-12-14 01:04:10 -08:00
TRIGGER _NODE _FILTER ,
EnterpriseEditionFeature ,
2023-02-21 00:35:35 -08:00
ASSUMPTION _EXPERIMENT ,
2023-02-17 06:08:26 -08:00
REGULAR _NODE _FILTER ,
MANUAL _TRIGGER _NODE _TYPE ,
2022-07-27 07:28:13 -07:00
} from '@/constants' ;
2022-11-23 04:41:53 -08:00
import { copyPaste } from '@/mixins/copyPaste' ;
import { externalHooks } from '@/mixins/externalHooks' ;
import { genericHelpers } from '@/mixins/genericHelpers' ;
import { mouseSelect } from '@/mixins/mouseSelect' ;
import { moveNodeWorkflow } from '@/mixins/moveNodeWorkflow' ;
import { restApi } from '@/mixins/restApi' ;
feat(editor): Node creator actions (#4696)
* WIP: Node Actions List UI
* WIP: Recommended Actions and preseting of fields
* WIP: Resource category
* :art: Moved actions categorisation to the server
* :label: Add missing INodeAction type
* :sparkles: Improve SSR categorisation, fix adding of mixed actions
* :recycle: Refactor CategorizedItems to composition api, style fixes
* WIP: Adding multiple nodes
* :recycle: Refactor rest of the NodeCreator component to composition API, conver globalLinkActions to composable
* :sparkles: Allow actions dragging, fix search and refactor passing of actions to categorized items
* :lipstick: Fix node actions title
* Migrate to the pinia store, add posthog feature and various fixes
* :bug: Fix filtering of trigger actions when not merged
* fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root
* :bug: Design review fixes
* :bug: Fix disabling of merged actions
* Fix trigger root filtering
* :sparkles: Allow for custom node actions parser, introduce hubspot parser
* :bug: Fix initial node params validation, fix position of second added node
* :bug: Introduce operations category, removed canvas node names overrride, fix API actions display and prevent dragging of action nodes
* :sparkles: Prevent NDV auto-open feature flag
* :bug: Inject recommened action for trigger nodes without actions
* Refactored NodeCreatorNode to Storybook, change filtering of merged nodes for the trigger helper panel, minor fixes
* Improve rendering of app nodes and animation
* Cleanup, any only enable accordion transition on triggerhelperpanel
* Hide node creator scrollbars in Firefox
* Minor styles fixes
* Do not copy the array in rendering method
* Removed unused props
* Fix memory leak
* Fix categorisation of regular nodes with a single resource
* Implement telemetry calls for node actions
* Move categorization to FE
* Fix client side actions categorisation
* Skip custom action show
* Only load tooltip for NodeIcon if necessary
* Fix lodash startCase import
* Remove lodash.startcase
* Cleanup
* Fix node creator autofocus on "tab"
* Prevent posthog getFeatureFlag from crashing
* Debugging preview env search issues
* Remove logs
* Make sure the pre-filled params are update not overwritten
* Get rid of transition in itemiterator
* WIP: Rough version of NodeActions keyboard navigation, replace nodeCreator composable with Pinia store module
* Rewrite to add support for ActionItem to ItemIterator and make CategorizedItems accept items props
* Fix category item counter & cleanup
* Add APIHint to actions search no-result, clean up NodeCreatorNode
* Improve node actions no results message
* Remove logging, fix filtering of recommended placeholder category
* Remove unused NodeActions component and node merging feature falg
* Do not show regular nodes without actions
* Make sure to add manual trigger when adding http node via actions hint
* Fixed api hint footer line height
* Prevent pointer-events od NodeIcon img and remove "this" from template
* Address PR points
* Fix e2e specs
* Make sure canvas ia loaded
* Make sure canvas ia loaded before opening nodeCreator in e2e spec
* Fix flaky workflows tags e2e getter
* Imrpove node creator click outside UX, add manual node to regular nodes added from trigger panel
* Add manual trigger node if dragging regular from trigger panel
2022-12-09 01:56:36 -08:00
import useGlobalLinkActions from '@/composables/useGlobalLinkActions' ;
2022-11-23 04:41:53 -08:00
import { showMessage } from '@/mixins/showMessage' ;
import { titleChange } from '@/mixins/titleChange' ;
import { newVersions } from '@/mixins/newVersions' ;
import { workflowHelpers } from '@/mixins/workflowHelpers' ;
import { workflowRun } from '@/mixins/workflowRun' ;
2019-06-23 03:35:23 -07:00
2022-05-23 08:56:15 -07:00
import NodeDetailsView from '@/components/NodeDetailsView.vue' ;
2019-06-23 03:35:23 -07:00
import Node from '@/components/Node.vue' ;
import NodeSettings from '@/components/NodeSettings.vue' ;
feat(editor): Add Workflow Stickies (Notes) (#3154)
* N8N-3029 Add Node Type for Wokrflow Stickies/Notes
* N8N-3029 Update Content, Update Aliasses
* N8N-3030 Created N8N Sticky Component in Design System
* N8N-3030 Fixed Code spaccing Sticky Component
* N8N-3030 Fixed Code spaccing StickyStories Component
* N8N-3030 Fixed Code spaccing Markdown Component
* N8N-3030 Added Sticky Colors Pallete into Storybook, Update Color Variables for Sticky Component
* N8N-3030 Added Unfocus Event
* N8N-3030 Update Default Placeholder, Markdown Styles, Fixed Edit State, Added Text to EditState, Fixed Height of Area, Turned off Resize of textarea
* N8N-3030 Update Sticky Overflow, Update Hover States, Updated Markdown Overflow
* N8N-3030, N8N-3031 - Add Resize to Sticky, Created N8n-Resize component
* N8N-3031 Fixed Importing Components in Editor-ui
* N8N-3031 Fixed Resize Component, Fixed Gradient
* N8N-3030, N8N-3031 Update Note Description
* N8N-3032 Hotfix Building Storybook
* N8N-3032 - Select Behaviour, Changes in Resize Component, Emit on Width/Height/Top/Left Change
* N8N-3032 Update Resize Component to emmit left/top, Update Dynamic Resize on Selected Background
* N8N-3032 Updated / Dragging vs Resizing, prevent open Modal for stickies
* N8N-3032 Added ID props to n8n-sticky // dynamic id for multi resizing in NodeView
* N8N-3033 Add dynamic size Tooltip on Sticky
* N8N-3033 Updated Z-index for Sticky Component
* N8N-3033 Updated N8N-Resize Component, Fixed SelectedBackround for Sticky Component
* N8N-3033 Refactor
* N8N-3033 Focus/Defocus on TextArea
* N8N-3033 Fixed Resizing on NW Point
* N8N-3030 Save content in vuex on input change
* N8N-3033 Fixed Resizer, Save Width and Height in Vue
* N8N-3033 Hide Sticky Footer on small height/width
* N8N-3033 Fixed Resizer
* N8N-3033 Dynamic Z-index for Stickies
* N8N-3033 Dynamic Z-index for Stickies
* N8N-3033 Removed static z-index for select sticky class
* N8N-3034 Added Telemetry
* N8N-3030 Formatter
* N8N-3030 Format code
* N8N-3030 Fixed Selecting Stickies
* N8N-3033 Fixed Notifications
* N8N-3030 Added new paddings for Default Stickies
* N8N-3033 Prevent Scrolling NodeView when Sticky is in Edit mode and Mouse is Over the TextArea
* N8N-3030 Prevent double clicking to switch state of Sticky component in Edit Mode
* N8N-3033 Fixed Z-index of Stickies
* N8N-3033 Prevent delete node when in EditMode
* N8N-3030 Prevent Delete Button to delete the Sticky while in Edit Mode
* N8N-3030 Change EditMode (emit) on keyboard shortucts, update Markdown Links & Images, Added new props
* N8N-3030 Sticky Component - No padding when hiding footer text
* N8N-3033 Fix Resizing enter into Edit Mode
* N8N-3033 Selecting different nodes - exit the edit mode
* N8N-3033 Auto Select Text in text-area by default - Sticky Component
* N8N-3033 Prevent Default behaviour for CTRL + X, CTRL + A when Sticky is Active && inEditMode
* N8N-3033 Refactor Resizer, Refactor Sticky, Update zIndex inEditMode
* N8N-3033 Updated Default Text // Node-base, Storybook
* N8N-3033 Add Resizing in EditMode - Components update
* N8N-3033 Fixed Footer - Show/Hide on Resize in EditMode
* N8N-3033 Fix ActiveSticky on Init
* N8N-3033 Refactor Sticky in Vuex, Fixed Init Sticky Tweaks, Prevent Modal Openning, Save on Keyboard shortcuts
* Stickies - Update Note node with new props
* N8N-3030 Updated Default Note text, Update the Markdown Link
* N8N-3030 CMD-C does not copy the text fix
* N8N-3030 Fix Max Zoom / Zoom out shortcuts disabled in editState
* N8N-3030 Z-index fixed during Edit Mode typing
* N8N-3030 Prevent Autoselect Text in Stickies if the text is not default
* N8N-3030 Fixed ReadOnly Bugs / Prevent showing Tooltip, Resizing
* N8N-3030 Added Sticky Creator Button
* N8N-3030 Update Icon / Sticky Creator Button
* N8N-3033 Update Sticky Icon / StickyCreator Button
* update package lock
* 🔩 update note props
* 🚿 clean props
* 🔧 linting
* :wrench: fix spacing
* remove resize component
* remove resize component
* ✂ clean up sticky
* revert back to height width
* revert back to height/width
* replace zindex property
* replace default text property
* use i18n to translate
* update package lock
* move resize
* clean up how height/width are set
* fix resize for sticky to support left/top
* clean up resize
* fix lasso/highlight bug
* remove unused props
* fix zoom to fit
* fix padding for demo view
* fix readonly
* remove iseditable, use active state
* clean up keyboard events
* chang button size, no edit on insert
* scale resizing correctly
* make active on resize
* fix select on resize/move
* use outline icon
* allow for multiple line breaks
* fix multi line bug
* fix edit mode outline
* keep edit open as one resizes
* respect multiple spaces
* fix scrolling bug
* clean up hover impl
* clean up references to note
* disable for rename
* fix drifting while drag
* fix mouse cursor on resize
* fix sticky min height
* refactor resize into component
* fix pulling too far bug
* fix delete/cut all bug
* fix padding bottom
* fix active change on resize
* add transition to button
* Fix sticky markdown click
* add solid fa icon
* update node graph, telemetry event
* add snapping
* change alt text
* update package lock
* fix bug in button hover
* add back transition
* clean up resize
* add grid size as param
* remove breaks
* clean up markdown
* lint fixes
* fix spacing
* clean up markdown colors
* clean up classes in resize
* clean up resize
* update sticky story
* fix spacing
* clean up classes
* revert change
* revert change
* revert change
* clean up sticky component
* remove unused component
* remove unnessary data
* remove unnessary data
* clean up actions
* clean up sticky size
* clean up unnessary border style
* fix bug
* replace sticky note name
* update description
* remove support for multi spaces
* update tracking name
* update telemetry reqs
* fix enter bug
* update alt text
* update sticky notes doc url
* fix readonly bug
* update class name
* update quote marks
Co-authored-by: SchnapsterDog <olivertrajceski@yahoo.com>
2022-04-25 03:38:37 -07:00
import Sticky from '@/components/Sticky.vue' ;
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
import CanvasAddButton from './CanvasAddButton.vue' ;
2019-06-23 03:35:23 -07:00
import mixins from 'vue-typed-mixins' ;
2022-08-03 04:06:53 -07:00
import { v4 as uuid } from 'uuid' ;
2019-06-23 03:35:23 -07:00
import {
2022-10-18 04:33:31 -07:00
deepCopy ,
2019-06-23 03:35:23 -07:00
IConnection ,
IConnections ,
IDataObject ,
INode ,
INodeConnections ,
2022-07-22 03:19:45 -07:00
INodeCredentialsDetails ,
2019-06-23 03:35:23 -07:00
INodeIssues ,
INodeTypeDescription ,
2021-09-21 10:38:24 -07:00
INodeTypeNameVersion ,
2022-07-22 03:19:45 -07:00
IPinData ,
2021-02-09 14:32:40 -08:00
IRun ,
2021-11-19 01:17:13 -08:00
ITaskData ,
2022-07-09 23:53:04 -07:00
ITelemetryTrackProperties ,
IWorkflowBase ,
2022-07-22 03:19:45 -07:00
NodeHelpers ,
TelemetryHelpers ,
Workflow ,
2019-06-23 03:35:23 -07:00
} from 'n8n-workflow' ;
import {
2021-10-13 15:21:00 -07:00
ICredentialsResponse ,
2019-06-23 03:35:23 -07:00
IExecutionResponse ,
IWorkflowDb ,
IWorkflowData ,
INodeUi ,
IUpdateInformation ,
IWorkflowDataUpdate ,
2021-11-19 01:17:13 -08:00
XYPosition ,
2021-02-09 14:32:40 -08:00
IPushDataExecutionFinished ,
2021-05-29 11:31:21 -07:00
ITag ,
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
INewWorkflowData ,
2021-06-22 10:33:07 -07:00
IWorkflowTemplate ,
2021-09-22 00:23:37 -07:00
IExecutionsSummary ,
2022-08-03 04:06:53 -07:00
IWorkflowToShare ,
2022-11-04 06:04:31 -07:00
IUser ,
INodeUpdatePropertiesInformation ,
2022-10-11 01:06:33 -07:00
} from '@/Interface' ;
2022-11-09 01:01:50 -08:00
2022-11-23 04:41:53 -08:00
import { debounceHelper } from '@/mixins/debounce' ;
2022-11-04 06:04:31 -07:00
import { useUIStore } from '@/stores/ui' ;
import { useSettingsStore } from '@/stores/settings' ;
import { useUsersStore } from '@/stores/users' ;
2022-11-09 00:31:23 -08:00
import { Route , RawLocation } from 'vue-router' ;
2022-11-15 04:25:04 -08:00
import { nodeViewEventBus } from '@/event-bus/node-view-event-bus' ;
2022-11-04 06:04:31 -07:00
import { useWorkflowsStore } from '@/stores/workflows' ;
import { useRootStore } from '@/stores/n8nRootStore' ;
import { useNDVStore } from '@/stores/ndv' ;
import { useTemplatesStore } from '@/stores/templates' ;
import { useNodeTypesStore } from '@/stores/nodeTypes' ;
2022-11-09 01:01:50 -08:00
import { useCredentialsStore } from '@/stores/credentials' ;
import { useTagsStore } from '@/stores/tags' ;
import { useNodeCreatorStore } from '@/stores/nodeCreator' ;
import { dataPinningEventBus } from '@/event-bus/data-pinning-event-bus' ;
2022-11-07 00:53:27 -08:00
import { useCanvasStore } from '@/stores/canvas' ;
2022-12-14 01:04:10 -08:00
import useWorkflowsEEStore from '@/stores/workflows.ee' ;
2022-11-24 01:52:56 -08:00
import * as NodeViewUtils from '@/utils/nodeViewUtils' ;
2022-12-09 06:07:37 -08:00
import { getAccountAge , getConnectionInfo , getNodeViewTab } from '@/utils' ;
import { useHistoryStore } from '@/stores/history' ;
2022-12-14 01:04:10 -08:00
import {
AddConnectionCommand ,
AddNodeCommand ,
MoveNodeCommand ,
RemoveConnectionCommand ,
RemoveNodeCommand ,
RenameNodeCommand ,
2023-01-30 09:20:50 -08:00
historyBus ,
2022-12-14 01:04:10 -08:00
} from '@/models/history' ;
2023-01-30 09:20:50 -08:00
import {
EVENT _ENDPOINT _MOUSEOVER ,
EVENT _ENDPOINT _MOUSEOUT ,
EVENT _DRAG _MOVE ,
EVENT _CONNECTION _DRAG ,
EVENT _CONNECTION _ABORT ,
EVENT _CONNECTION _MOUSEOUT ,
EVENT _CONNECTION _MOUSEOVER ,
BrowserJsPlumbInstance ,
ready ,
} from '@jsplumb/browser-ui' ;
import { N8nPlusEndpoint } from '@/plugins/endpoints/N8nPlusEndpointType' ;
2023-02-21 00:35:35 -08:00
import { usePostHogStore } from '@/stores/posthog' ;
2021-06-22 10:33:07 -07:00
2022-04-19 03:28:31 -07:00
interface AddNodeOptions {
position ? : XYPosition ;
dragAndDrop ? : boolean ;
}
2022-11-07 00:53:27 -08:00
const NodeCreator = ( ) => import ( '@/components/Node/NodeCreator/NodeCreator.vue' ) ;
const NodeCreation = ( ) => import ( '@/components/Node/NodeCreation.vue' ) ;
const CanvasControls = ( ) => import ( '@/components/CanvasControls.vue' ) ;
2022-07-26 03:41:34 -07:00
2019-06-23 03:35:23 -07:00
export default mixins (
copyPaste ,
2021-01-19 14:48:30 -08:00
externalHooks ,
2019-06-23 03:35:23 -07:00
genericHelpers ,
mouseSelect ,
moveNodeWorkflow ,
restApi ,
showMessage ,
2020-08-25 11:38:09 -07:00
titleChange ,
2019-06-23 03:35:23 -07:00
workflowHelpers ,
workflowRun ,
2021-07-22 01:22:17 -07:00
newVersions ,
2022-09-21 06:44:45 -07:00
debounceHelper ,
2022-12-14 01:04:10 -08:00
) . extend ( {
name : 'NodeView' ,
components : {
NodeDetailsView ,
Node ,
NodeCreator ,
NodeSettings ,
Sticky ,
CanvasAddButton ,
NodeCreation ,
CanvasControls ,
} ,
setup ( ) {
const { registerCustomAction , unregisterCustomAction } = useGlobalLinkActions ( ) ;
return {
registerCustomAction ,
unregisterCustomAction ,
} ;
} ,
errorCaptured : ( err , vm , info ) => {
console . error ( 'errorCaptured' ) ; // eslint-disable-line no-console
console . error ( err ) ; // eslint-disable-line no-console
} ,
watch : {
// Listen to route changes and load the workflow accordingly
$route ( to : Route , from : Route ) {
const currentTab = getNodeViewTab ( to ) ;
const nodeViewNotInitialized = ! this . uiStore . nodeViewInitialized ;
let workflowChanged =
from . params . name !== to . params . name &&
// Both 'new' and __EMPTY__ are new workflow names, so ignore them when detecting if wf changed
! ( from . params . name === 'new' && this . currentWorkflow === PLACEHOLDER _EMPTY _WORKFLOW _ID ) &&
// Also ignore if workflow id changes when saving new workflow
to . params . action !== 'workflowSave' ;
const isOpeningTemplate = to . name === VIEWS . TEMPLATE _IMPORT ;
// When entering this tab:
if ( currentTab === MAIN _HEADER _TABS . WORKFLOW || isOpeningTemplate ) {
if ( workflowChanged || nodeViewNotInitialized || isOpeningTemplate ) {
this . startLoading ( ) ;
if ( nodeViewNotInitialized ) {
const previousDirtyState = this . uiStore . stateIsDirty ;
this . resetWorkspace ( ) ;
this . uiStore . stateIsDirty = previousDirtyState ;
2022-10-26 01:02:56 -07:00
}
2022-12-14 01:04:10 -08:00
this . loadCredentials ( ) ;
this . initView ( ) . then ( ( ) => {
this . stopLoading ( ) ;
if ( this . blankRedirect ) {
this . blankRedirect = false ;
}
} ) ;
2022-10-26 01:02:56 -07:00
}
2022-12-14 01:04:10 -08:00
}
// Also, when landing on executions tab, check if workflow data is changed
if ( currentTab === MAIN _HEADER _TABS . EXECUTIONS ) {
workflowChanged =
from . params . name !== to . params . name &&
! ( to . params . name === 'new' && from . params . name === undefined ) ;
if ( workflowChanged ) {
// This will trigger node view to update next time workflow tab is opened
this . uiStore . nodeViewInitialized = false ;
2020-10-25 04:47:49 -07:00
}
2022-12-14 01:04:10 -08:00
}
} ,
activeNode ( ) {
// When a node gets set as active deactivate the create-menu
this . createNodeActive = false ;
} ,
containsTrigger ( containsTrigger ) {
// Re-center CanvasAddButton if there's no triggers
if ( containsTrigger === false )
this . canvasStore . setRecenteredCanvasAddButtonPosition ( this . getNodeViewOffsetPosition ) ;
} ,
nodeViewScale ( newScale ) {
const element = this . $refs . nodeView as HTMLDivElement ;
if ( element ) {
element . style . transform = ` scale( ${ newScale } ) ` ;
}
} ,
} ,
async beforeRouteLeave ( to , from , next ) {
2023-02-01 07:50:35 -08:00
if ( getNodeViewTab ( to ) === MAIN _HEADER _TABS . EXECUTIONS || from . name === VIEWS . TEMPLATE _IMPORT ) {
next ( ) ;
return ;
}
if ( this . uiStore . stateIsDirty ) {
const confirmModal = await this . confirmModal (
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.message' ) ,
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.headline' ) ,
'warning' ,
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.confirmButtonText' ) ,
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.cancelButtonText' ) ,
true ,
) ;
if ( confirmModal === MODAL _CONFIRMED ) {
2023-02-02 00:05:14 -08:00
// Make sure workflow id is empty when leaving the editor
this . workflowsStore . setWorkflowId ( PLACEHOLDER _EMPTY _WORKFLOW _ID ) ;
2023-02-01 07:50:35 -08:00
const saved = await this . saveCurrentWorkflow ( { } , false ) ;
if ( saved ) {
await this . settingsStore . fetchPromptsData ( ) ;
}
this . uiStore . stateIsDirty = false ;
2022-12-14 01:04:10 -08:00
2023-02-01 07:50:35 -08:00
if ( from . name === VIEWS . NEW _WORKFLOW ) {
// Replace the current route with the new workflow route
// before navigating to the new route when saving new workflow.
this . $router . replace (
{ name : VIEWS . WORKFLOW , params : { name : this . currentWorkflow } } ,
( ) => {
// We can't use next() here since vue-router
// would prevent the navigation with an error
this . $router . push ( to as RawLocation ) ;
} ,
) ;
} else {
2022-10-26 01:02:56 -07:00
next ( ) ;
}
2023-02-01 07:50:35 -08:00
} else if ( confirmModal === MODAL _CANCEL ) {
2023-02-02 00:05:14 -08:00
this . workflowsStore . setWorkflowId ( PLACEHOLDER _EMPTY _WORKFLOW _ID ) ;
2023-02-01 07:50:35 -08:00
await this . resetWorkspace ( ) ;
this . uiStore . stateIsDirty = false ;
2020-10-25 04:47:49 -07:00
next ( ) ;
}
2022-12-14 01:04:10 -08:00
} else {
next ( ) ;
}
} ,
computed : {
... mapStores (
useCanvasStore ,
useTagsStore ,
useCredentialsStore ,
useNodeCreatorStore ,
useNodeTypesStore ,
useNDVStore ,
useRootStore ,
useSettingsStore ,
useTemplatesStore ,
useUIStore ,
useWorkflowsStore ,
useUsersStore ,
useNodeCreatorStore ,
useWorkflowsEEStore ,
useHistoryStore ,
) ,
nativelyNumberSuffixedDefaults ( ) : string [ ] {
return this . rootStore . nativelyNumberSuffixedDefaults ;
2020-10-25 04:47:49 -07:00
} ,
2022-12-14 01:04:10 -08:00
currentUser ( ) : IUser | null {
return this . usersStore . currentUser ;
} ,
defaultLocale ( ) : string {
return this . rootStore . defaultLocale ;
} ,
isEnglishLocale ( ) : boolean {
return this . defaultLocale === 'en' ;
} ,
activeNode ( ) : INodeUi | null {
return this . ndvStore . activeNode ;
} ,
executionWaitingForWebhook ( ) : boolean {
return this . workflowsStore . executionWaitingForWebhook ;
} ,
isDemo ( ) : boolean {
return this . $route . name === VIEWS . DEMO ;
} ,
showCanvasAddButton ( ) : boolean {
2023-01-16 01:11:15 -08:00
return this . loadingService === null && ! this . containsTrigger && ! this . isDemo ;
2022-12-14 01:04:10 -08:00
} ,
lastSelectedNode ( ) : INodeUi | null {
return this . uiStore . getLastSelectedNode ;
} ,
nodes ( ) : INodeUi [ ] {
return this . workflowsStore . allNodes ;
} ,
runButtonText ( ) : string {
if ( ! this . workflowRunning ) {
return this . $locale . baseText ( 'nodeView.runButtonText.executeWorkflow' ) ;
}
if ( this . executionWaitingForWebhook ) {
return this . $locale . baseText ( 'nodeView.runButtonText.waitingForTriggerEvent' ) ;
}
return this . $locale . baseText ( 'nodeView.runButtonText.executingWorkflow' ) ;
} ,
workflowStyle ( ) : object {
const offsetPosition = this . uiStore . nodeViewOffsetPosition ;
2019-06-23 03:35:23 -07:00
return {
2022-12-14 01:04:10 -08:00
left : offsetPosition [ 0 ] + 'px' ,
top : offsetPosition [ 1 ] + 'px' ,
2019-06-23 03:35:23 -07:00
} ;
} ,
2022-12-14 01:04:10 -08:00
canvasAddButtonStyle ( ) : object {
return {
'pointer-events' : this . createNodeActive ? 'none' : 'all' ,
} ;
} ,
backgroundStyle ( ) : object {
return NodeViewUtils . getBackgroundStyles (
this . nodeViewScale ,
this . uiStore . nodeViewOffsetPosition ,
this . isExecutionPreview ,
) ;
} ,
workflowClasses ( ) {
const returnClasses = [ ] ;
if ( this . ctrlKeyPressed ) {
if ( this . uiStore . nodeViewMoveInProgress === true ) {
returnClasses . push ( 'move-in-process' ) ;
} else {
returnClasses . push ( 'move-active' ) ;
}
}
if ( this . selectActive || this . ctrlKeyPressed ) {
// Makes sure that nothing gets selected while select or move is active
returnClasses . push ( 'do-not-select' ) ;
}
return returnClasses ;
} ,
workflowExecution ( ) : IExecutionResponse | null {
return this . workflowsStore . getWorkflowExecution ;
} ,
workflowRunning ( ) : boolean {
return this . uiStore . isActionActive ( 'workflowRunning' ) ;
} ,
currentWorkflow ( ) : string {
return this . $route . params . name || this . workflowsStore . workflowId ;
} ,
workflowName ( ) : string {
return this . workflowsStore . workflowName ;
} ,
allTriggersDisabled ( ) : boolean {
const disabledTriggerNodes = this . triggerNodes . filter ( ( node ) => node . disabled ) ;
return disabledTriggerNodes . length === this . triggerNodes . length ;
} ,
triggerNodes ( ) : INodeUi [ ] {
return this . nodes . filter (
( node ) => node . type === START _NODE _TYPE || this . nodeTypesStore . isTriggerNode ( node . type ) ,
) ;
} ,
containsTrigger ( ) : boolean {
return this . triggerNodes . length > 0 ;
} ,
isExecutionDisabled ( ) : boolean {
return ! this . containsTrigger || this . allTriggersDisabled ;
} ,
getNodeViewOffsetPosition ( ) : XYPosition {
return this . uiStore . nodeViewOffsetPosition ;
} ,
nodeViewScale ( ) : number {
return this . canvasStore . nodeViewScale ;
} ,
2023-01-30 09:20:50 -08:00
instance ( ) : BrowserJsPlumbInstance {
2022-12-14 01:04:10 -08:00
return this . canvasStore . jsPlumbInstance ;
} ,
} ,
data ( ) {
return {
GRID _SIZE : NodeViewUtils . GRID _SIZE ,
STICKY _NODE _TYPE ,
createNodeActive : false ,
lastSelectedConnection : null as null | Connection ,
lastClickPosition : [ 450 , 450 ] as XYPosition ,
ctrlKeyPressed : false ,
stopExecutionInProgress : false ,
blankRedirect : false ,
credentialsUpdated : false ,
newNodeInsertPosition : null as XYPosition | null ,
pullConnActiveNodeName : null as string | null ,
pullConnActive : false ,
dropPrevented : false ,
renamingActive : false ,
showStickyButton : false ,
isExecutionPreview : false ,
showTriggerMissingTooltip : false ,
workflowData : null as INewWorkflowData | null ,
2023-01-30 09:20:50 -08:00
activeConnection : null as null | Connection ,
2022-12-14 01:04:10 -08:00
isProductionExecutionPreview : false ,
2023-01-30 09:20:50 -08:00
enterTimer : undefined as undefined | ReturnType < typeof setTimeout > ,
exitTimer : undefined as undefined | ReturnType < typeof setTimeout > ,
2022-12-14 01:04:10 -08:00
// jsplumb automatically deletes all loose connections which is in turn recorded
// in undo history as a user action.
// This should prevent automatically removed connections from populating undo stack
suspendRecordingDetachedConnections : false ,
} ;
} ,
beforeDestroy ( ) {
this . resetWorkspace ( ) ;
// Make sure the event listeners get removed again else we
// could add up with them registred multiple times
document . removeEventListener ( 'keydown' , this . keyDown ) ;
document . removeEventListener ( 'keyup' , this . keyUp ) ;
this . unregisterCustomAction ( 'showNodeCreator' ) ;
} ,
methods : {
showTriggerMissingToltip ( isVisible : boolean ) {
this . showTriggerMissingTooltip = isVisible ;
} ,
onRunNode ( nodeName : string , source : string ) {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
const telemetryPayload = {
node _type : node ? node . type : null ,
workflow _id : this . workflowsStore . workflowId ,
source : 'canvas' ,
} ;
this . $telemetry . track ( 'User clicked execute node button' , telemetryPayload ) ;
this . $externalHooks ( ) . run ( 'nodeView.onRunNode' , telemetryPayload ) ;
this . runWorkflow ( nodeName , source ) ;
} ,
async onRunWorkflow ( ) {
this . getWorkflowDataToSave ( ) . then ( ( workflowData ) => {
2022-08-19 06:35:39 -07:00
const telemetryPayload = {
2022-11-04 06:04:31 -07:00
workflow _id : this . workflowsStore . workflowId ,
2022-12-14 01:04:10 -08:00
node _graph _string : JSON . stringify (
TelemetryHelpers . generateNodesGraph ( workflowData as IWorkflowBase , this . getNodeTypes ( ) )
. nodeGraph ,
) ,
2022-08-19 06:35:39 -07:00
} ;
2022-12-14 01:04:10 -08:00
this . $telemetry . track ( 'User clicked execute workflow button' , telemetryPayload ) ;
this . $externalHooks ( ) . run ( 'nodeView.onRunWorkflow' , telemetryPayload ) ;
} ) ;
2022-07-09 23:53:04 -07:00
2022-12-14 01:04:10 -08:00
await this . runWorkflow ( ) ;
} ,
onRunContainerClick ( ) {
if ( this . containsTrigger && ! this . allTriggersDisabled ) return ;
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
2022-12-14 01:04:10 -08:00
const message =
this . containsTrigger && this . allTriggersDisabled
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
? this . $locale . baseText ( 'nodeView.addOrEnableTriggerNode' )
: this . $locale . baseText ( 'nodeView.addATriggerNodeFirst' ) ;
2022-12-14 01:04:10 -08:00
this . registerCustomAction ( 'showNodeCreator' , ( ) =>
this . showTriggerCreator ( 'no_trigger_execution_tooltip' ) ,
) ;
const notice = this . $showMessage ( {
type : 'info' ,
title : this . $locale . baseText ( 'nodeView.cantExecuteNoTrigger' ) ,
message ,
duration : 3000 ,
onClick : ( ) =>
setTimeout ( ( ) => {
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
// Close the creator panel if user clicked on the link
2022-12-14 01:04:10 -08:00
if ( this . createNodeActive ) notice . close ( ) ;
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
} , 0 ) ,
2022-12-14 01:04:10 -08:00
} ) ;
} ,
clearExecutionData ( ) {
this . workflowsStore . workflowExecutionData = null ;
this . updateNodesExecutionIssues ( ) ;
} ,
translateName ( type : string , originalName : string ) {
return this . $locale . headerText ( {
key : ` headers. ${ this . $locale . shortNodeType ( type ) } .displayName ` ,
fallback : originalName ,
} ) ;
} ,
getUniqueNodeName ( {
originalName ,
additionalUsedNames = [ ] ,
type = '' ,
} : {
originalName : string ;
additionalUsedNames ? : string [ ] ;
type ? : string ;
} ) {
const allNodeNamesOnCanvas = this . workflowsStore . allNodes . map ( ( n : INodeUi ) => n . name ) ;
originalName = this . isEnglishLocale ? originalName : this . translateName ( type , originalName ) ;
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
if (
! allNodeNamesOnCanvas . includes ( originalName ) &&
! additionalUsedNames . includes ( originalName )
) {
return originalName ; // already unique
}
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
let natives : string [ ] = this . nativelyNumberSuffixedDefaults ;
natives = this . isEnglishLocale
? natives
: natives . map ( ( name ) => {
const type = name . toLowerCase ( ) . replace ( '_' , '' ) ;
return this . translateName ( type , name ) ;
} ) ;
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
const found = natives . find ( ( n ) => originalName . startsWith ( n ) ) ;
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
let ignore , baseName , nameIndex , uniqueName ;
let index = 1 ;
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
if ( found ) {
// name natively ends with number
nameIndex = originalName . split ( found ) . pop ( ) ;
if ( nameIndex ) {
index = parseInt ( nameIndex , 10 ) ;
}
baseName = uniqueName = found ;
} else {
const nameMatch = originalName . match ( /(.*\D+)(\d*)/ ) ;
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
if ( nameMatch === null ) {
// name is only a number
index = parseInt ( originalName , 10 ) ;
baseName = '' ;
uniqueName = baseName + index ;
} else {
// name is string or string/number combination
[ ignore , baseName , nameIndex ] = nameMatch ;
if ( nameIndex !== '' ) {
index = parseInt ( nameIndex , 10 ) ;
2021-12-02 08:51:50 -08:00
}
2022-12-14 01:04:10 -08:00
uniqueName = baseName ;
2021-12-02 08:51:50 -08:00
}
2022-12-14 01:04:10 -08:00
}
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
while (
allNodeNamesOnCanvas . includes ( uniqueName ) ||
additionalUsedNames . includes ( uniqueName )
) {
uniqueName = baseName + index ++ ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
return uniqueName ;
} ,
async onSaveKeyboardShortcut ( ) {
const saved = await this . saveCurrentWorkflow ( ) ;
if ( saved ) await this . settingsStore . fetchPromptsData ( ) ;
} ,
showTriggerCreator ( source : string ) {
if ( this . createNodeActive ) return ;
2023-02-17 06:08:26 -08:00
this . nodeCreatorStore . setSelectedView ( TRIGGER _NODE _FILTER ) ;
2022-12-14 01:04:10 -08:00
this . nodeCreatorStore . setShowScrim ( true ) ;
this . onToggleNodeCreator ( { source , createNodeActive : true } ) ;
} ,
async openExecution ( executionId : string ) {
this . startLoading ( ) ;
this . resetWorkspace ( ) ;
let data : IExecutionResponse | undefined ;
try {
data = await this . restApi ( ) . getExecution ( executionId ) ;
} catch ( error ) {
this . $showError ( error , this . $locale . baseText ( 'nodeView.showError.openExecution.title' ) ) ;
return ;
}
if ( data === undefined ) {
throw new Error ( ` Execution with id " ${ executionId } " could not be found! ` ) ;
}
this . workflowsStore . setWorkflowName ( {
newName : data . workflowData . name ,
setStateDirty : false ,
} ) ;
this . workflowsStore . setWorkflowId ( PLACEHOLDER _EMPTY _WORKFLOW _ID ) ;
this . workflowsStore . setWorkflowExecutionData ( data ) ;
if ( data . workflowData . pinData ) {
this . workflowsStore . setWorkflowPinData ( data . workflowData . pinData ) ;
}
await this . addNodes (
deepCopy ( data . workflowData . nodes ) ,
deepCopy ( data . workflowData . connections ) ,
) ;
this . $nextTick ( ( ) => {
this . canvasStore . zoomToFit ( ) ;
this . uiStore . stateIsDirty = false ;
} ) ;
this . $externalHooks ( ) . run ( 'execution.open' , {
workflowId : data . workflowData . id ,
workflowName : data . workflowData . name ,
executionId ,
} ) ;
this . $telemetry . track ( 'User opened read-only execution' , {
workflow _id : data . workflowData . id ,
execution _mode : data . mode ,
execution _finished : data . finished ,
} ) ;
if ( ! data . finished && data . data ? . resultData ? . error ) {
// Check if any node contains an error
let nodeErrorFound = false ;
if ( data . data . resultData . runData ) {
const runData = data . data . resultData . runData ;
errorCheck : for ( const nodeName of Object . keys ( runData ) ) {
for ( const taskData of runData [ nodeName ] ) {
if ( taskData . error ) {
nodeErrorFound = true ;
break errorCheck ;
2021-07-10 02:34:41 -07:00
}
}
}
2022-02-11 00:18:39 -08:00
}
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
if ( ! nodeErrorFound && data . data . resultData . error . stack ) {
// Display some more information for now in console to make debugging easier
// TODO: Improve this in the future by displaying in UI
console . error ( ` Execution ${ executionId } error: ` ) ; // eslint-disable-line no-console
console . error ( data . data . resultData . error . stack ) ; // eslint-disable-line no-console
2022-07-20 08:50:39 -07:00
}
2022-12-14 01:04:10 -08:00
}
if ( ( data as IExecutionsSummary ) . waitTill ) {
this . $showMessage ( {
title : this . $locale . baseText ( 'nodeView.thisExecutionHasntFinishedYet' ) ,
message : ` <a data-action="reload"> ${ this . $locale . baseText (
'nodeView.refresh' ,
) } < / a > $ { this . $locale . baseText (
'nodeView.toSeeTheLatestStatus' ,
) } . < br / > < a href = "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/" target = "_blank" > $ { this . $locale . baseText (
'nodeView.moreInfo' ,
) } < / a > ` ,
type : 'warning' ,
duration : 0 ,
2022-02-11 00:18:39 -08:00
} ) ;
2022-12-14 01:04:10 -08:00
}
this . stopLoading ( ) ;
} ,
async importWorkflowExact ( data : { workflow : IWorkflowDataUpdate } ) {
if ( ! data . workflow . nodes || ! data . workflow . connections ) {
throw new Error ( 'Invalid workflow object' ) ;
}
this . resetWorkspace ( ) ;
data . workflow . nodes = NodeViewUtils . getFixedNodesList ( data . workflow . nodes ) ;
2022-10-26 01:02:56 -07:00
2022-12-14 01:04:10 -08:00
await this . addNodes ( data . workflow . nodes as INodeUi [ ] , data . workflow . connections ) ;
2021-06-22 10:33:07 -07:00
2022-12-14 01:04:10 -08:00
if ( data . workflow . pinData ) {
this . workflowsStore . setWorkflowPinData ( data . workflow . pinData ) ;
}
2021-06-22 10:33:07 -07:00
2022-12-14 01:04:10 -08:00
this . $nextTick ( ( ) => {
this . canvasStore . zoomToFit ( ) ;
} ) ;
} ,
async openWorkflowTemplate ( templateId : string ) {
this . startLoading ( ) ;
this . setLoadingText ( this . $locale . baseText ( 'nodeView.loadingTemplate' ) ) ;
this . resetWorkspace ( ) ;
2021-06-22 10:33:07 -07:00
2022-12-14 01:04:10 -08:00
this . workflowsStore . currentWorkflowExecutions = [ ] ;
this . workflowsStore . activeWorkflowExecution = null ;
2021-06-22 10:33:07 -07:00
2022-12-14 01:04:10 -08:00
let data : IWorkflowTemplate | undefined ;
try {
this . $externalHooks ( ) . run ( 'template.requested' , { templateId } ) ;
data = await this . templatesStore . getWorkflowTemplate ( templateId ) ;
2019-06-23 03:35:23 -07:00
2022-10-24 11:17:25 -07:00
if ( ! data ) {
2021-11-10 10:41:40 -08:00
throw new Error (
2022-12-14 01:04:10 -08:00
this . $locale . baseText ( 'nodeView.workflowTemplateWithIdCouldNotBeFound' , {
interpolate : { templateId } ,
} ) ,
2021-11-10 10:41:40 -08:00
) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
} catch ( error ) {
this . $showError ( error , this . $locale . baseText ( 'nodeView.couldntImportWorkflow' ) ) ;
this . $router . replace ( { name : VIEWS . NEW _WORKFLOW } ) ;
return ;
}
2022-11-15 04:25:04 -08:00
2022-12-14 01:04:10 -08:00
data . workflow . nodes = NodeViewUtils . getFixedNodesList ( data . workflow . nodes ) as INodeUi [ ] ;
2022-10-31 02:35:24 -07:00
2022-12-14 01:04:10 -08:00
this . blankRedirect = true ;
this . $router . replace ( { name : VIEWS . NEW _WORKFLOW , query : { templateId } } ) ;
2022-11-17 05:19:40 -08:00
2022-12-14 01:04:10 -08:00
await this . addNodes ( data . workflow . nodes , data . workflow . connections ) ;
this . workflowData = ( await this . workflowsStore . getNewWorkflowData ( data . name ) ) || { } ;
this . $nextTick ( ( ) => {
this . canvasStore . zoomToFit ( ) ;
this . uiStore . stateIsDirty = true ;
} ) ;
2022-11-17 05:19:40 -08:00
2022-12-14 01:04:10 -08:00
this . $externalHooks ( ) . run ( 'template.open' , {
templateId ,
templateName : data . name ,
workflow : data . workflow ,
} ) ;
this . stopLoading ( ) ;
} ,
2023-01-25 02:45:30 -08:00
async openWorkflow ( workflow : IWorkflowDb ) {
2022-12-14 01:04:10 -08:00
this . startLoading ( ) ;
2022-12-22 03:40:33 -08:00
const selectedExecution = this . workflowsStore . activeWorkflowExecution ;
2022-12-14 01:04:10 -08:00
this . resetWorkspace ( ) ;
2022-11-15 04:25:04 -08:00
2023-01-25 02:45:30 -08:00
this . workflowsStore . addWorkflow ( workflow ) ;
this . workflowsStore . setActive ( workflow . active || false ) ;
this . workflowsStore . setWorkflowId ( workflow . id ) ;
this . workflowsStore . setWorkflowName ( { newName : workflow . name , setStateDirty : false } ) ;
this . workflowsStore . setWorkflowSettings ( workflow . settings || { } ) ;
this . workflowsStore . setWorkflowPinData ( workflow . pinData || { } ) ;
this . workflowsStore . setWorkflowVersionId ( workflow . versionId ) ;
2022-11-04 06:04:31 -07:00
2023-01-25 02:45:30 -08:00
if ( workflow . ownedBy ) {
2022-12-14 01:04:10 -08:00
this . workflowsEEStore . setWorkflowOwnedBy ( {
2023-01-25 02:45:30 -08:00
workflowId : workflow . id ,
ownedBy : workflow . ownedBy ,
2022-12-14 01:04:10 -08:00
} ) ;
}
2022-11-04 06:04:31 -07:00
2023-01-25 02:45:30 -08:00
if ( workflow . sharedWith ) {
2022-12-14 01:04:10 -08:00
this . workflowsEEStore . setWorkflowSharedWith ( {
2023-01-25 02:45:30 -08:00
workflowId : workflow . id ,
sharedWith : workflow . sharedWith ,
2022-12-14 01:04:10 -08:00
} ) ;
}
2019-06-23 03:35:23 -07:00
2023-01-25 02:45:30 -08:00
if ( workflow . usedCredentials ) {
this . workflowsStore . setUsedCredentials ( workflow . usedCredentials ) ;
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2023-01-25 02:45:30 -08:00
const tags = ( workflow . tags || [ ] ) as ITag [ ] ;
2022-12-14 01:04:10 -08:00
const tagIds = tags . map ( ( tag ) => tag . id ) ;
this . workflowsStore . setWorkflowTagIds ( tagIds || [ ] ) ;
this . tagsStore . upsertTags ( tags ) ;
2021-06-29 01:47:28 -07:00
2023-01-25 02:45:30 -08:00
await this . addNodes ( workflow . nodes , workflow . connections ) ;
2021-06-29 01:47:28 -07:00
2022-12-14 01:04:10 -08:00
if ( ! this . credentialsUpdated ) {
this . uiStore . stateIsDirty = false ;
}
this . canvasStore . zoomToFit ( ) ;
2023-01-25 02:45:30 -08:00
this . $externalHooks ( ) . run ( 'workflow.open' , {
workflowId : workflow . id ,
workflowName : workflow . name ,
} ) ;
if ( selectedExecution ? . workflowId !== workflow . id ) {
2022-12-22 03:40:33 -08:00
this . workflowsStore . activeWorkflowExecution = null ;
this . workflowsStore . currentWorkflowExecutions = [ ] ;
} else {
this . workflowsStore . activeWorkflowExecution = selectedExecution ;
}
2022-12-14 01:04:10 -08:00
this . stopLoading ( ) ;
} ,
touchTap ( e : MouseEvent | TouchEvent ) {
if ( this . isTouchDevice ) {
this . mouseDown ( e ) ;
}
} ,
mouseDown ( e : MouseEvent | TouchEvent ) {
// Save the location of the mouse click
this . lastClickPosition = this . getMousePositionWithinNodeView ( e ) ;
2021-06-29 01:47:28 -07:00
2022-12-14 01:04:10 -08:00
this . mouseDownMouseSelect ( e as MouseEvent ) ;
this . mouseDownMoveWorkflow ( e as MouseEvent ) ;
// Hide the node-creator
this . createNodeActive = false ;
} ,
mouseUp ( e : MouseEvent ) {
this . mouseUpMouseSelect ( e ) ;
this . mouseUpMoveWorkflow ( e ) ;
} ,
keyUp ( e : KeyboardEvent ) {
if ( e . key === this . controlKeyCode ) {
this . ctrlKeyPressed = false ;
}
} ,
async keyDown ( e : KeyboardEvent ) {
// @ts-ignore
const path = e . path || ( e . composedPath && e . composedPath ( ) ) ;
// Check if the keys got emitted from a message box or from something
// else which should ignore the default keybindings
for ( const element of path ) {
if (
element . className &&
typeof element . className === 'string' &&
element . className . includes ( 'ignore-key-press' )
) {
2021-06-29 01:47:28 -07:00
return ;
}
2022-12-14 01:04:10 -08:00
}
// el-dialog or el-message-box element is open
if ( window . document . body . classList . contains ( 'el-popup-parent--hidden' ) ) {
return ;
}
2021-06-29 01:47:28 -07:00
2022-12-14 01:04:10 -08:00
if ( e . key === 'Escape' ) {
this . createNodeActive = false ;
2021-06-29 01:47:28 -07:00
if ( this . activeNode ) {
2022-12-14 01:04:10 -08:00
this . $externalHooks ( ) . run ( 'dataDisplay.nodeEditingFinished' ) ;
this . ndvStore . activeNodeName = null ;
2021-05-29 11:31:21 -07:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// node modal is open
if ( this . activeNode ) {
return ;
}
2021-06-29 01:47:28 -07:00
2022-12-14 01:04:10 -08:00
if ( e . key === 'd' ) {
this . callDebounced ( 'deactivateSelectedNode' , { debounceTime : 350 } ) ;
} else if ( e . key === 'Delete' || e . key === 'Backspace' ) {
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
this . callDebounced ( 'deleteSelectedNodes' , { debounceTime : 500 } ) ;
} else if ( e . key === 'Tab' ) {
this . onToggleNodeCreator ( {
source : 'tab' ,
createNodeActive : ! this . createNodeActive && ! this . isReadOnly ,
} ) ;
} else if ( e . key === this . controlKeyCode ) {
this . ctrlKeyPressed = true ;
} else if ( e . key === 'F2' && ! this . isReadOnly ) {
const lastSelectedNode = this . lastSelectedNode ;
if ( lastSelectedNode !== null && lastSelectedNode . type !== STICKY _NODE _TYPE ) {
this . callDebounced ( 'renameNodePrompt' , { debounceTime : 1500 } , lastSelectedNode . name ) ;
}
} else if ( e . key === 'a' && this . isCtrlKeyPressed ( e ) === true ) {
// Select all nodes
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
this . callDebounced ( 'selectAllNodes' , { debounceTime : 1000 } ) ;
} else if ( e . key === 'c' && this . isCtrlKeyPressed ( e ) ) {
this . callDebounced ( 'copySelectedNodes' , { debounceTime : 1000 } ) ;
} else if ( e . key === 'x' && this . isCtrlKeyPressed ( e ) ) {
// Cut nodes
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
this . callDebounced ( 'cutSelectedNodes' , { debounceTime : 1000 } ) ;
} else if ( e . key === 'n' && this . isCtrlKeyPressed ( e ) && e . altKey ) {
// Create a new workflow
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
if ( this . isDemo ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( this . $router . currentRoute . name === VIEWS . NEW _WORKFLOW ) {
this . $root . $emit ( 'newWorkflow' ) ;
} else {
this . $router . push ( { name : VIEWS . NEW _WORKFLOW } ) ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . $showMessage ( {
title : this . $locale . baseText ( 'nodeView.showMessage.keyDown.title' ) ,
type : 'success' ,
} ) ;
} else if ( e . key === 's' && this . isCtrlKeyPressed ( e ) ) {
// Save workflow
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( this . isReadOnly ) {
return ;
}
2020-07-20 07:57:58 -07:00
2022-12-14 01:04:10 -08:00
this . callDebounced ( 'onSaveKeyboardShortcut' , { debounceTime : 1000 } ) ;
} else if ( e . key === 'Enter' ) {
// Activate the last selected node
const lastSelectedNode = this . lastSelectedNode ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( lastSelectedNode !== null ) {
if ( lastSelectedNode . type === STICKY _NODE _TYPE && this . isReadOnly ) {
2019-06-23 03:35:23 -07:00
return ;
}
2022-12-14 01:04:10 -08:00
this . ndvStore . activeNodeName = lastSelectedNode . name ;
}
} else if ( e . key === 'ArrowRight' && e . shiftKey ) {
// Select all downstream nodes
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
this . callDebounced ( 'selectDownstreamNodes' , { debounceTime : 1000 } ) ;
} else if ( e . key === 'ArrowRight' ) {
// Set child node active
const lastSelectedNode = this . lastSelectedNode ;
if ( lastSelectedNode === null ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const connections = this . workflowsStore . outgoingConnectionsByNodeName (
lastSelectedNode . name ,
) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( connections . main === undefined || connections . main . length === 0 ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . callDebounced (
'nodeSelectedByName' ,
{ debounceTime : 100 } ,
connections . main [ 0 ] [ 0 ] . node ,
false ,
true ,
) ;
} else if ( e . key === 'ArrowLeft' && e . shiftKey ) {
// Select all downstream nodes
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
this . callDebounced ( 'selectUpstreamNodes' , { debounceTime : 1000 } ) ;
} else if ( e . key === 'ArrowLeft' ) {
// Set parent node active
const lastSelectedNode = this . lastSelectedNode ;
if ( lastSelectedNode === null ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const workflow = this . getCurrentWorkflow ( ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! workflow . connectionsByDestinationNode . hasOwnProperty ( lastSelectedNode . name ) ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const connections = workflow . connectionsByDestinationNode [ lastSelectedNode . name ] ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( connections . main === undefined || connections . main . length === 0 ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . callDebounced (
'nodeSelectedByName' ,
{ debounceTime : 100 } ,
connections . main [ 0 ] [ 0 ] . node ,
false ,
true ,
) ;
} else if ( [ 'ArrowUp' , 'ArrowDown' ] . includes ( e . key ) ) {
// Set sibling node as active
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Check first if it has a parent node
const lastSelectedNode = this . lastSelectedNode ;
if ( lastSelectedNode === null ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const workflow = this . getCurrentWorkflow ( ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! workflow . connectionsByDestinationNode . hasOwnProperty ( lastSelectedNode . name ) ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const connections = workflow . connectionsByDestinationNode [ lastSelectedNode . name ] ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! Array . isArray ( connections . main ) || ! connections . main . length ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const parentNode = connections . main [ 0 ] [ 0 ] . node ;
const connectionsParent = this . workflowsStore . outgoingConnectionsByNodeName ( parentNode ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! Array . isArray ( connectionsParent . main ) || ! connectionsParent . main . length ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Get all the sibling nodes and their x positions to know which one to set active
let siblingNode : INodeUi | null ;
let lastCheckedNodePosition = e . key === 'ArrowUp' ? - 99999999 : 99999999 ;
let nextSelectNode : string | null = null ;
for ( const ouputConnections of connectionsParent . main ) {
for ( const ouputConnection of ouputConnections ) {
if ( ouputConnection . node === lastSelectedNode . name ) {
// Ignore current node
continue ;
}
siblingNode = this . workflowsStore . getNodeByName ( ouputConnection . node ) ;
if ( siblingNode ) {
if ( e . key === 'ArrowUp' ) {
// Get the next node on the left
if (
siblingNode . position [ 1 ] <= lastSelectedNode . position [ 1 ] &&
siblingNode . position [ 1 ] > lastCheckedNodePosition
) {
nextSelectNode = siblingNode . name ;
lastCheckedNodePosition = siblingNode . position [ 1 ] ;
}
} else {
// Get the next node on the right
if (
siblingNode . position [ 1 ] >= lastSelectedNode . position [ 1 ] &&
siblingNode . position [ 1 ] < lastCheckedNodePosition
) {
nextSelectNode = siblingNode . name ;
lastCheckedNodePosition = siblingNode . position [ 1 ] ;
2019-06-23 03:35:23 -07:00
}
}
}
}
}
2022-12-14 01:04:10 -08:00
if ( nextSelectNode !== null ) {
this . callDebounced (
'nodeSelectedByName' ,
{ debounceTime : 100 } ,
nextSelectNode ,
false ,
true ,
) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
}
} ,
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
deactivateSelectedNode ( ) {
if ( ! this . editAllowedCheck ( ) ) {
return ;
}
this . disableNodes ( this . uiStore . getSelectedNodes , true ) ;
} ,
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
deleteSelectedNodes ( ) {
// Copy "selectedNodes" as the nodes get deleted out of selection
// when they get deleted and if we would use original it would mess
// with the index and would so not delete all nodes
const nodesToDelete : string [ ] = this . uiStore . getSelectedNodes . map ( ( node : INodeUi ) => {
return node . name ;
} ) ;
this . historyStore . startRecordingUndo ( ) ;
nodesToDelete . forEach ( ( nodeName : string ) => {
this . removeNode ( nodeName , true , false ) ;
} ) ;
setTimeout ( ( ) => {
this . historyStore . stopRecordingUndo ( ) ;
} , 200 ) ;
} ,
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
selectAllNodes ( ) {
this . nodes . forEach ( ( node ) => {
this . nodeSelectedByName ( node . name ) ;
} ) ;
} ,
2019-07-17 09:44:05 -07:00
2022-12-14 01:04:10 -08:00
selectUpstreamNodes ( ) {
const lastSelectedNode = this . lastSelectedNode ;
if ( lastSelectedNode === null ) {
return ;
}
2019-07-17 09:44:05 -07:00
2022-12-14 01:04:10 -08:00
this . deselectAllNodes ( ) ;
2019-07-17 09:44:05 -07:00
2022-12-14 01:04:10 -08:00
// Get all upstream nodes and select them
const workflow = this . getCurrentWorkflow ( ) ;
for ( const nodeName of workflow . getParentNodes ( lastSelectedNode . name ) ) {
this . nodeSelectedByName ( nodeName ) ;
}
2019-07-17 09:44:05 -07:00
2022-12-14 01:04:10 -08:00
// At the end select the previously selected node again
this . nodeSelectedByName ( lastSelectedNode . name ) ;
} ,
selectDownstreamNodes ( ) {
const lastSelectedNode = this . lastSelectedNode ;
if ( lastSelectedNode === null ) {
return ;
}
2019-07-17 09:44:05 -07:00
2022-12-14 01:04:10 -08:00
this . deselectAllNodes ( ) ;
2019-07-17 09:44:05 -07:00
2022-12-14 01:04:10 -08:00
// Get all downstream nodes and select them
const workflow = this . getCurrentWorkflow ( ) ;
for ( const nodeName of workflow . getChildNodes ( lastSelectedNode . name ) ) {
this . nodeSelectedByName ( nodeName ) ;
}
2019-07-17 09:44:05 -07:00
2022-12-14 01:04:10 -08:00
// At the end select the previously selected node again
this . nodeSelectedByName ( lastSelectedNode . name ) ;
} ,
2022-11-09 01:01:50 -08:00
2022-12-14 01:04:10 -08:00
pushDownstreamNodes ( sourceNodeName : string , margin : number , recordHistory = false ) {
const sourceNode = this . workflowsStore . nodesByName [ sourceNodeName ] ;
const workflow = this . getCurrentWorkflow ( ) ;
const childNodes = workflow . getChildNodes ( sourceNodeName ) ;
for ( const nodeName of childNodes ) {
const node = this . workflowsStore . nodesByName [ nodeName ] as INodeUi ;
const oldPosition = node . position ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
if ( node . position [ 0 ] < sourceNode . position [ 0 ] ) {
continue ;
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
const updateInformation : INodeUpdatePropertiesInformation = {
name : nodeName ,
properties : {
position : [ node . position [ 0 ] + margin , node . position [ 1 ] ] ,
} ,
} ;
2022-12-09 06:07:37 -08:00
2022-12-14 01:04:10 -08:00
this . workflowsStore . updateNodeProperties ( updateInformation ) ;
this . onNodeMoved ( node ) ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
if (
( recordHistory && oldPosition [ 0 ] !== node . position [ 0 ] ) ||
oldPosition [ 1 ] !== node . position [ 1 ]
) {
this . historyStore . pushCommandToUndo (
new MoveNodeCommand ( nodeName , oldPosition , node . position , this ) ,
recordHistory ,
) ;
:sparkles: Add Templates (#2720)
* Templates Bugs / Fixed Various Bugs / Multiply Api Request, Carousel Gradient, Core Nodes Filters ...
* Updated MainSidebar Paddings
* N8N-Templates Bugfixing - Remove Unnecesairy Icon (Shape), Refatctor infiniteScrollEnabled Prop + updated infiniterScroll functinality
* N8N-2853 Fixed Carousel Arrows Bug after Cleaning the SearchBar
* fix telemetry init
* fix search tracking issues
* N8N-2853 Created FilterTemplateNode Constant Array, Filter PlayButton and WebhookRespond from Nodes, Added Box for showing more nodes inside TemplateList, Updated NewWorkflowButton to primary, Fixed Markdown issue with Code
* N8N-2853 Removed Placeholder if Workflows Or Collections are not found, Updated the Logic
* fix telemetry events
* clean up session id
* update user inserted event
* N8N-2853 Fixed Categories to Moving if the names are long
* Add todos
* Update Routes on loading
* fix spacing
* Update Border Color
* Update Border Readius
* fix filter fn
* fix constant, console error
* N8N-2853 PR Fixes, Refactoring, Removing unnecesairy code ..
* N8N-2853 PR Fixes - Editor-ui Fixes, Refactoring, Removing Dead Code ...
* N8N-2853 Refactor Card to LongCard
* clean up spacing, replace css var
* clean up spacing
* set categories as optional in node
* replace vars
* refactor store
* remove unnesssary import
* fix error
* fix templates view to start
* add to cache
* fix coll view data
* fix categories
* fix category event
* fix collections carousel
* fix initial load and search
* fix infinite load
* fix query param
* fix scrolling issues
* fix scroll to top
* fix search
* fix collections search
* fix navigation bug
* rename view
* update package lock
* rename workflow view
* rename coll view
* update routes
* add wrapper component
* set session id
* fix search tracking
* fix session tracking
* remove deleted mutation
* remove check for unsupported nodes
* refactor filters
* lazy load template
* clean up types
* refactor infinte scroll
* fix end of search
* Fix spacing
* fix coll loading
* fix types
* fix coll view list
* fix navigation
* rename types
* rename state
* fix search responsiveness
* fix coll view spacing
* fix search view spacing
* clean up views
* set background color
* center page not vert
* fix workflow view
* remove import
* fix background color
* fix background
* clean props
* clean up imports
* refactor button
* update background color
* fix spacing issue
* rename event
* update telemetry event
* update endpoints, add loading view, check for endpoint health
* remove conolse log
* N8N-2853 Fixed Menu Items Padding
* replace endpoints
* fix type issues
* fix categories
* N8N-2853 Fixed ParameterInput Placeholder after ElementUI Upgrade
* update createdAt
* :zap: Fix placeholder in creds config modal
* :pencil2: Adjust docstring to `credText` placeholder version
* N8N-2853 Optimized
* N8N-2853 Optimized code
* :zap: Add deployment type to FE settings
* :zap: Add deployment type to interfaces
* N8N-2853 Removed Animated prop from components
* :zap: Add deployment type to store module
* :sparkles: Create hiring banner
* :zap: Display hiring banner
* :rewind: Undo unrelated change
* N8N-2853 Refactor TemplateFilters
* :zap: Fix indentation
* N8N-2853 Reorder items / TemplateList
* :shirt: Fix lint
* N8N-2853 Refactor TemplateFilters Component
* N8N-2853 Reorder TemplateList
* refactor template card
* update timeout
* fix removelistener
* fix spacing
* split enabled from offline
* add spacing to go back
* N8N-2853 Fixed Screens for Tablet & Mobile
* N8N-2853 Update Stores Order
* remove image componet
* remove placeholder changes
* N8N-2853 Fixed Chinnese Placeholders for El Select Component that comes from the Library Upgrade
* N8N-2853 Fixed Vue Agile Console Warnings
* N8N-2853 Update Collection Route
* :pencil2: Update jobs URL
* :truck: Move logging to root component
* :zap: Refactor `deploymentType` to `isInternalUser`
* :zap: Improve syntax
* fix cut bug in readonly view
* N8N-3012 Fixed Details section in templates with lots of description, Fixed Mardown Block with overflox-x
* N8N-3012 Increased Font-size, Spacing and Line-height of the Categories Items
* N8N-3012 Fixed Vue-agile client width error on resize
* only delay redirect for root path
* N8N-3012 Fixed Carousel Arrows that Disappear
* N8N-3012 Make Loading Screen same color as Templates
* N8N-3012 Markdown renders inline block as block code
* add offline warning
* hide log from workflow iframe
* update text
* make search button larger
* N8N-3012 Categories / Tags extended all the way in details section
* load data in cred modals
* remove deleted message
* add external hook
* remove import
* update env variable description
* fix markdown width issue
* disable telemetry for demo, add session id to template pages
* fix telemetery bugs
* N8N-3012 Not found Collections/Wokrkflow
* N8N-3012 Checkboxes change order when categories are changed
* N8N-3012 Refactor SortedCategories inside TemplateFilters component
* fix firefox bug
* add telemetry requirements
* add error check
* N8N-3012 Update GoBackButton to check if Route History is present
* N8N-3012 Fixed WF Nodes Icons
* hide workflow screenshots
* remove unnessary mixins
* rename prop
* fix design a bit
* rename data
* clear workspace on destroy
* fix copy paste bug
* fix disabled state
* N8N-3012 Fixed Saving/Leave without saving Modal
* fix telemetry issue
* fix telemetry issues, error bug
* fix error notification
* disable workflow menu items on templates
* fix i18n elementui issue
* Remove Emit - NodeType from HoverableNodeIcon component
* TechnicalFixes: NavigateTo passed down as function should be helper
* TechnicalFixes: Update NavigateTo function
* TechnicalFixes: Add FilterCoreNodes directly as function
* check for empty connecitions
* fix titles
* respect new lines
* increase categories to be sliced
* rename prop
* onUseWorkflow
* refactor click event
* fix bug, refactor
* fix loading story
* add default
* fix styles at right level of abstraction
* add wrapper with width
* remove loading blocks component
* add story
* rename prop
* fix spacing
* refactor tag, add story
* move margin to container
* fix tag redirect, remove unnessary check
* make version optional
* rename view
* move from workflows to templates store
* remove unnessary change
* remove unnessary css
* rename component
* refactor collection card
* add boolean to prevent shrink
* clean up carousel
* fix redirection bug on save
* remove listeners to fix multiple listeners bug
* remove unnessary types
* clean up boolean set
* fix node select bug
* rename component
* remove unnessary class
* fix redirection bug
* remove unnessary error
* fix typo
* fix blockquotes, pre
* refactor markdown rendering
* remove console log
* escape markdown
* fix safari bug
* load active workflows to fix modal bug
* :arrow_up: Update package-lock.json file
* :zap: Add n8n version as header
Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2022-02-28 01:57:44 -08:00
}
2022-12-14 01:04:10 -08:00
}
} ,
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
cutSelectedNodes ( ) {
const deleteCopiedNodes = ! this . isReadOnly ;
this . copySelectedNodes ( deleteCopiedNodes ) ;
if ( deleteCopiedNodes ) {
this . deleteSelectedNodes ( ) ;
}
} ,
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
copySelectedNodes ( isCut : boolean ) {
this . getSelectedNodesToSave ( ) . then ( ( data ) => {
const workflowToCopy : IWorkflowToShare = {
meta : {
instanceId : this . rootStore . instanceId ,
} ,
... data ,
} ;
2022-12-12 02:59:16 -08:00
2022-12-14 01:04:10 -08:00
this . removeForeignCredentialsFromWorkflow (
workflowToCopy ,
this . credentialsStore . allCredentials ,
) ;
2022-12-12 02:59:16 -08:00
2022-12-14 01:04:10 -08:00
const nodeData = JSON . stringify ( workflowToCopy , null , 2 ) ;
this . copyToClipboard ( nodeData ) ;
if ( data . nodes . length > 0 ) {
if ( ! isCut ) {
this . $showMessage ( {
title : 'Copied!' ,
message : '' ,
type : 'success' ,
2021-10-18 20:57:49 -07:00
} ) ;
}
2022-12-14 01:04:10 -08:00
this . $telemetry . track ( 'User copied nodes' , {
node _types : data . nodes . map ( ( node ) => node . type ) ,
workflow _id : this . workflowsStore . workflowId ,
} ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
} ) ;
} ,
async stopExecution ( ) {
const executionId = this . workflowsStore . activeExecutionId ;
if ( executionId === null ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
try {
this . stopExecutionInProgress = true ;
await this . restApi ( ) . stopCurrentExecution ( executionId ) ;
this . $showMessage ( {
title : this . $locale . baseText ( 'nodeView.showMessage.stopExecutionTry.title' ) ,
type : 'success' ,
} ) ;
} catch ( error ) {
// Execution stop might fail when the execution has already finished. Let's treat this here.
const execution = await this . restApi ( ) . getExecution ( executionId ) ;
2023-01-11 01:52:32 -08:00
if ( execution === undefined ) {
// execution finished but was not saved (e.g. due to low connectivity)
this . workflowsStore . finishActiveExecution ( {
executionId ,
data : { finished : true , stoppedAt : new Date ( ) } ,
} ) ;
this . workflowsStore . executingNode = null ;
this . uiStore . removeActiveAction ( 'workflowRunning' ) ;
this . $titleSet ( this . workflowsStore . workflowName , 'IDLE' ) ;
this . $showMessage ( {
title : this . $locale . baseText ( 'nodeView.showMessage.stopExecutionCatch.unsaved.title' ) ,
message : this . $locale . baseText (
'nodeView.showMessage.stopExecutionCatch.unsaved.message' ,
) ,
type : 'success' ,
} ) ;
} else if ( execution ? . finished ) {
// execution finished before it could be stopped
2022-12-14 01:04:10 -08:00
const executedData = {
data : execution . data ,
finished : execution . finished ,
mode : execution . mode ,
startedAt : execution . startedAt ,
stoppedAt : execution . stoppedAt ,
} as IRun ;
const pushData = {
data : executedData ,
executionId ,
retryOf : execution . retryOf ,
} as IPushDataExecutionFinished ;
this . workflowsStore . finishActiveExecution ( pushData ) ;
this . $titleSet ( execution . workflowData . name , 'IDLE' ) ;
this . workflowsStore . executingNode = null ;
this . workflowsStore . setWorkflowExecutionData ( executedData as IExecutionResponse ) ;
this . uiStore . removeActiveAction ( 'workflowRunning' ) ;
2019-06-23 03:35:23 -07:00
this . $showMessage ( {
2022-12-14 01:04:10 -08:00
title : this . $locale . baseText ( 'nodeView.showMessage.stopExecutionCatch.title' ) ,
message : this . $locale . baseText ( 'nodeView.showMessage.stopExecutionCatch.message' ) ,
2019-06-23 03:35:23 -07:00
type : 'success' ,
} ) ;
2022-12-14 01:04:10 -08:00
} else {
this . $showError ( error , this . $locale . baseText ( 'nodeView.showError.stopExecution.title' ) ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
}
this . stopExecutionInProgress = false ;
2022-07-09 23:53:04 -07:00
2022-12-14 01:04:10 -08:00
this . getWorkflowDataToSave ( ) . then ( ( workflowData ) => {
const trackProps = {
workflow _id : this . workflowsStore . workflowId ,
node _graph _string : JSON . stringify (
TelemetryHelpers . generateNodesGraph ( workflowData as IWorkflowBase , this . getNodeTypes ( ) )
. nodeGraph ,
) ,
} ;
2022-07-09 23:53:04 -07:00
2022-12-14 01:04:10 -08:00
this . $telemetry . track ( 'User clicked stop workflow execution' , trackProps ) ;
} ) ;
} ,
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
async stopWaitingForWebhook ( ) {
try {
await this . restApi ( ) . removeTestWebhook ( this . workflowsStore . workflowId ) ;
} catch ( error ) {
this . $showError (
error ,
this . $locale . baseText ( 'nodeView.showError.stopWaitingForWebhook.title' ) ,
) ;
return ;
}
} ,
/ * *
* This method gets called when data got pasted into the window
* /
async receivedCopyPasteData ( plainTextData : string ) : Promise < void > {
const currentTab = getNodeViewTab ( this . $route ) ;
if ( currentTab === MAIN _HEADER _TABS . WORKFLOW ) {
let workflowData : IWorkflowDataUpdate | undefined ;
if ( this . editAllowedCheck ( ) === false ) {
2019-06-23 03:35:23 -07:00
return ;
}
2022-12-14 01:04:10 -08:00
// Check if it is an URL which could contain workflow data
if ( plainTextData . match ( /^http[s]?:\/\/.*\.json$/i ) ) {
// Pasted data points to a possible workflow JSON file
if ( ! this . editAllowedCheck ( ) ) {
2019-06-23 03:35:23 -07:00
return ;
}
2022-12-14 01:04:10 -08:00
const importConfirm = await this . confirmMessage (
this . $locale . baseText ( 'nodeView.confirmMessage.receivedCopyPasteData.message' , {
interpolate : { plainTextData } ,
} ) ,
this . $locale . baseText ( 'nodeView.confirmMessage.receivedCopyPasteData.headline' ) ,
'warning' ,
this . $locale . baseText (
'nodeView.confirmMessage.receivedCopyPasteData.confirmButtonText' ,
) ,
this . $locale . baseText ( 'nodeView.confirmMessage.receivedCopyPasteData.cancelButtonText' ) ,
) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! importConfirm ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
workflowData = await this . getWorkflowDataFromUrl ( plainTextData ) ;
if ( workflowData === undefined ) {
return ;
}
} else {
// Pasted data is is possible workflow data
try {
// Check first if it is valid JSON
workflowData = JSON . parse ( plainTextData ) ;
2022-11-04 06:04:31 -07:00
2022-12-14 01:04:10 -08:00
if ( ! this . editAllowedCheck ( ) ) {
2019-06-23 03:35:23 -07:00
return ;
}
2022-12-14 01:04:10 -08:00
} catch ( e ) {
// Is no valid JSON so ignore
return ;
2019-06-23 03:35:23 -07:00
}
2022-11-04 06:04:31 -07:00
}
2019-06-23 03:35:23 -07:00
2023-01-30 09:20:50 -08:00
return this . importWorkflowData ( workflowData ! , 'paste' , false ) ;
2022-12-14 01:04:10 -08:00
}
} ,
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Returns the workflow data from a given URL. If no data gets found or
// data is invalid it returns undefined and displays an error message by itself.
async getWorkflowDataFromUrl ( url : string ) : Promise < IWorkflowDataUpdate | undefined > {
let workflowData : IWorkflowDataUpdate ;
this . startLoading ( ) ;
try {
workflowData = await this . restApi ( ) . getWorkflowFromUrl ( url ) ;
} catch ( error ) {
2019-06-23 03:35:23 -07:00
this . stopLoading ( ) ;
2022-12-14 01:04:10 -08:00
this . $showError (
error ,
this . $locale . baseText ( 'nodeView.showError.getWorkflowDataFromUrl.title' ) ,
) ;
return ;
}
this . stopLoading ( ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
return workflowData ;
} ,
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Imports the given workflow data into the current workflow
async importWorkflowData (
workflowData : IWorkflowToShare ,
source : string ,
2023-01-30 09:20:50 -08:00
importTags = true ,
2022-12-14 01:04:10 -08:00
) : Promise < void > {
// eslint-disable-line @typescript-eslint/default-param-last
// If it is JSON check if it looks on the first look like data we can use
if ( ! workflowData . hasOwnProperty ( 'nodes' ) || ! workflowData . hasOwnProperty ( 'connections' ) ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
try {
const nodeIdMap : { [ prev : string ] : string } = { } ;
if ( workflowData . nodes ) {
// set all new ids when pasting/importing workflows
workflowData . nodes . forEach ( ( node : INode ) => {
if ( node . id ) {
const newId = uuid ( ) ;
nodeIdMap [ newId ] = node . id ;
node . id = newId ;
} else {
node . id = uuid ( ) ;
}
} ) ;
}
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
const currInstanceId = this . rootStore . instanceId ;
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
const nodeGraph = JSON . stringify (
TelemetryHelpers . generateNodesGraph ( workflowData as IWorkflowBase , this . getNodeTypes ( ) , {
nodeIdMap ,
sourceInstanceId :
workflowData . meta && workflowData . meta . instanceId !== currInstanceId
? workflowData . meta . instanceId
: '' ,
} ) . nodeGraph ,
) ;
if ( source === 'paste' ) {
this . $telemetry . track ( 'User pasted nodes' , {
workflow _id : this . workflowsStore . workflowId ,
node _graph _string : nodeGraph ,
} ) ;
} else {
this . $telemetry . track ( 'User imported workflow' , {
source ,
workflow _id : this . workflowsStore . workflowId ,
node _graph _string : nodeGraph ,
} ) ;
}
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
// By default we automatically deselect all the currently
// selected nodes and select the new ones
this . deselectAllNodes ( ) ;
2019-07-17 07:05:01 -07:00
2022-12-14 01:04:10 -08:00
// Fix the node position as it could be totally offscreen
// and the pasted nodes would so not be directly visible to
// the user
this . updateNodePositions (
workflowData ,
NodeViewUtils . getNewNodePosition ( this . nodes , this . lastClickPosition ) ,
) ;
2019-07-17 07:05:01 -07:00
2022-12-14 01:04:10 -08:00
const data = await this . addNodesToWorkflow ( workflowData ) ;
2019-07-17 07:05:01 -07:00
2022-12-14 01:04:10 -08:00
setTimeout ( ( ) => {
data . nodes ! . forEach ( ( node : INodeUi ) => {
this . nodeSelectedByName ( node . name ) ;
2019-06-23 03:35:23 -07:00
} ) ;
2022-12-14 01:04:10 -08:00
} ) ;
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
if ( workflowData . pinData ) {
this . workflowsStore . setWorkflowPinData ( workflowData . pinData ) ;
}
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
const tagsEnabled = this . settingsStore . areTagsEnabled ;
if ( importTags && tagsEnabled && Array . isArray ( workflowData . tags ) ) {
const allTags = await this . tagsStore . fetchAll ( ) ;
const tagNames = new Set ( allTags . map ( ( tag ) => tag . name ) ) ;
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
const workflowTags = workflowData . tags as ITag [ ] ;
const notFound = workflowTags . filter ( ( tag ) => ! tagNames . has ( tag . name ) ) ;
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
const creatingTagPromises : Array < Promise < ITag > > = [ ] ;
for ( const tag of notFound ) {
const creationPromise = this . tagsStore . create ( tag . name ) . then ( ( tag : ITag ) => {
allTags . push ( tag ) ;
return tag ;
} ) ;
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
creatingTagPromises . push ( creationPromise ) ;
}
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
await Promise . all ( creatingTagPromises ) ;
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
const tagIds = workflowTags . reduce ( ( accu : string [ ] , imported : ITag ) => {
const tag = allTags . find ( ( tag ) => tag . name === imported . name ) ;
if ( tag ) {
accu . push ( tag . id ) ;
}
2022-06-02 03:39:42 -07:00
2022-12-14 01:04:10 -08:00
return accu ;
} , [ ] ) ;
2022-04-19 03:28:31 -07:00
2022-12-14 01:04:10 -08:00
this . workflowsStore . addWorkflowTagIds ( tagIds ) ;
2022-04-19 03:28:31 -07:00
}
2022-12-14 01:04:10 -08:00
} catch ( error ) {
this . $showError (
error ,
this . $locale . baseText ( 'nodeView.showError.importWorkflowData.title' ) ,
) ;
}
} ,
onDragOver ( event : DragEvent ) {
event . preventDefault ( ) ;
} ,
2022-04-19 03:28:31 -07:00
2022-12-14 01:04:10 -08:00
onDrop ( event : DragEvent ) {
if ( ! event . dataTransfer ) {
return ;
}
feat(editor): Node creator actions (#4696)
* WIP: Node Actions List UI
* WIP: Recommended Actions and preseting of fields
* WIP: Resource category
* :art: Moved actions categorisation to the server
* :label: Add missing INodeAction type
* :sparkles: Improve SSR categorisation, fix adding of mixed actions
* :recycle: Refactor CategorizedItems to composition api, style fixes
* WIP: Adding multiple nodes
* :recycle: Refactor rest of the NodeCreator component to composition API, conver globalLinkActions to composable
* :sparkles: Allow actions dragging, fix search and refactor passing of actions to categorized items
* :lipstick: Fix node actions title
* Migrate to the pinia store, add posthog feature and various fixes
* :bug: Fix filtering of trigger actions when not merged
* fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root
* :bug: Design review fixes
* :bug: Fix disabling of merged actions
* Fix trigger root filtering
* :sparkles: Allow for custom node actions parser, introduce hubspot parser
* :bug: Fix initial node params validation, fix position of second added node
* :bug: Introduce operations category, removed canvas node names overrride, fix API actions display and prevent dragging of action nodes
* :sparkles: Prevent NDV auto-open feature flag
* :bug: Inject recommened action for trigger nodes without actions
* Refactored NodeCreatorNode to Storybook, change filtering of merged nodes for the trigger helper panel, minor fixes
* Improve rendering of app nodes and animation
* Cleanup, any only enable accordion transition on triggerhelperpanel
* Hide node creator scrollbars in Firefox
* Minor styles fixes
* Do not copy the array in rendering method
* Removed unused props
* Fix memory leak
* Fix categorisation of regular nodes with a single resource
* Implement telemetry calls for node actions
* Move categorization to FE
* Fix client side actions categorisation
* Skip custom action show
* Only load tooltip for NodeIcon if necessary
* Fix lodash startCase import
* Remove lodash.startcase
* Cleanup
* Fix node creator autofocus on "tab"
* Prevent posthog getFeatureFlag from crashing
* Debugging preview env search issues
* Remove logs
* Make sure the pre-filled params are update not overwritten
* Get rid of transition in itemiterator
* WIP: Rough version of NodeActions keyboard navigation, replace nodeCreator composable with Pinia store module
* Rewrite to add support for ActionItem to ItemIterator and make CategorizedItems accept items props
* Fix category item counter & cleanup
* Add APIHint to actions search no-result, clean up NodeCreatorNode
* Improve node actions no results message
* Remove logging, fix filtering of recommended placeholder category
* Remove unused NodeActions component and node merging feature falg
* Do not show regular nodes without actions
* Make sure to add manual trigger when adding http node via actions hint
* Fixed api hint footer line height
* Prevent pointer-events od NodeIcon img and remove "this" from template
* Address PR points
* Fix e2e specs
* Make sure canvas ia loaded
* Make sure canvas ia loaded before opening nodeCreator in e2e spec
* Fix flaky workflows tags e2e getter
* Imrpove node creator click outside UX, add manual node to regular nodes added from trigger panel
* Add manual trigger node if dragging regular from trigger panel
2022-12-09 01:56:36 -08:00
2022-12-14 01:04:10 -08:00
const nodeTypeNames = event . dataTransfer . getData ( 'nodeTypeName' ) . split ( ',' ) ;
2022-04-19 03:28:31 -07:00
2022-12-14 01:04:10 -08:00
if ( nodeTypeNames ) {
const mousePosition = this . getMousePositionWithinNodeView ( event ) ;
feat(editor): Node creator actions (#4696)
* WIP: Node Actions List UI
* WIP: Recommended Actions and preseting of fields
* WIP: Resource category
* :art: Moved actions categorisation to the server
* :label: Add missing INodeAction type
* :sparkles: Improve SSR categorisation, fix adding of mixed actions
* :recycle: Refactor CategorizedItems to composition api, style fixes
* WIP: Adding multiple nodes
* :recycle: Refactor rest of the NodeCreator component to composition API, conver globalLinkActions to composable
* :sparkles: Allow actions dragging, fix search and refactor passing of actions to categorized items
* :lipstick: Fix node actions title
* Migrate to the pinia store, add posthog feature and various fixes
* :bug: Fix filtering of trigger actions when not merged
* fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root
* :bug: Design review fixes
* :bug: Fix disabling of merged actions
* Fix trigger root filtering
* :sparkles: Allow for custom node actions parser, introduce hubspot parser
* :bug: Fix initial node params validation, fix position of second added node
* :bug: Introduce operations category, removed canvas node names overrride, fix API actions display and prevent dragging of action nodes
* :sparkles: Prevent NDV auto-open feature flag
* :bug: Inject recommened action for trigger nodes without actions
* Refactored NodeCreatorNode to Storybook, change filtering of merged nodes for the trigger helper panel, minor fixes
* Improve rendering of app nodes and animation
* Cleanup, any only enable accordion transition on triggerhelperpanel
* Hide node creator scrollbars in Firefox
* Minor styles fixes
* Do not copy the array in rendering method
* Removed unused props
* Fix memory leak
* Fix categorisation of regular nodes with a single resource
* Implement telemetry calls for node actions
* Move categorization to FE
* Fix client side actions categorisation
* Skip custom action show
* Only load tooltip for NodeIcon if necessary
* Fix lodash startCase import
* Remove lodash.startcase
* Cleanup
* Fix node creator autofocus on "tab"
* Prevent posthog getFeatureFlag from crashing
* Debugging preview env search issues
* Remove logs
* Make sure the pre-filled params are update not overwritten
* Get rid of transition in itemiterator
* WIP: Rough version of NodeActions keyboard navigation, replace nodeCreator composable with Pinia store module
* Rewrite to add support for ActionItem to ItemIterator and make CategorizedItems accept items props
* Fix category item counter & cleanup
* Add APIHint to actions search no-result, clean up NodeCreatorNode
* Improve node actions no results message
* Remove logging, fix filtering of recommended placeholder category
* Remove unused NodeActions component and node merging feature falg
* Do not show regular nodes without actions
* Make sure to add manual trigger when adding http node via actions hint
* Fixed api hint footer line height
* Prevent pointer-events od NodeIcon img and remove "this" from template
* Address PR points
* Fix e2e specs
* Make sure canvas ia loaded
* Make sure canvas ia loaded before opening nodeCreator in e2e spec
* Fix flaky workflows tags e2e getter
* Imrpove node creator click outside UX, add manual node to regular nodes added from trigger panel
* Add manual trigger node if dragging regular from trigger panel
2022-12-09 01:56:36 -08:00
2022-12-14 01:04:10 -08:00
const nodesToAdd = nodeTypeNames . map ( ( nodeTypeName : string , index : number ) => {
return {
nodeTypeName ,
position : [
// If adding more than one node, offset the X position
mousePosition [ 0 ] -
NodeViewUtils . NODE _SIZE / 2 +
NodeViewUtils . NODE _SIZE * ( index * 2 ) ,
mousePosition [ 1 ] - NodeViewUtils . NODE _SIZE / 2 ,
] as XYPosition ,
dragAndDrop : true ,
} ;
} ) ;
feat(editor): Node creator actions (#4696)
* WIP: Node Actions List UI
* WIP: Recommended Actions and preseting of fields
* WIP: Resource category
* :art: Moved actions categorisation to the server
* :label: Add missing INodeAction type
* :sparkles: Improve SSR categorisation, fix adding of mixed actions
* :recycle: Refactor CategorizedItems to composition api, style fixes
* WIP: Adding multiple nodes
* :recycle: Refactor rest of the NodeCreator component to composition API, conver globalLinkActions to composable
* :sparkles: Allow actions dragging, fix search and refactor passing of actions to categorized items
* :lipstick: Fix node actions title
* Migrate to the pinia store, add posthog feature and various fixes
* :bug: Fix filtering of trigger actions when not merged
* fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root
* :bug: Design review fixes
* :bug: Fix disabling of merged actions
* Fix trigger root filtering
* :sparkles: Allow for custom node actions parser, introduce hubspot parser
* :bug: Fix initial node params validation, fix position of second added node
* :bug: Introduce operations category, removed canvas node names overrride, fix API actions display and prevent dragging of action nodes
* :sparkles: Prevent NDV auto-open feature flag
* :bug: Inject recommened action for trigger nodes without actions
* Refactored NodeCreatorNode to Storybook, change filtering of merged nodes for the trigger helper panel, minor fixes
* Improve rendering of app nodes and animation
* Cleanup, any only enable accordion transition on triggerhelperpanel
* Hide node creator scrollbars in Firefox
* Minor styles fixes
* Do not copy the array in rendering method
* Removed unused props
* Fix memory leak
* Fix categorisation of regular nodes with a single resource
* Implement telemetry calls for node actions
* Move categorization to FE
* Fix client side actions categorisation
* Skip custom action show
* Only load tooltip for NodeIcon if necessary
* Fix lodash startCase import
* Remove lodash.startcase
* Cleanup
* Fix node creator autofocus on "tab"
* Prevent posthog getFeatureFlag from crashing
* Debugging preview env search issues
* Remove logs
* Make sure the pre-filled params are update not overwritten
* Get rid of transition in itemiterator
* WIP: Rough version of NodeActions keyboard navigation, replace nodeCreator composable with Pinia store module
* Rewrite to add support for ActionItem to ItemIterator and make CategorizedItems accept items props
* Fix category item counter & cleanup
* Add APIHint to actions search no-result, clean up NodeCreatorNode
* Improve node actions no results message
* Remove logging, fix filtering of recommended placeholder category
* Remove unused NodeActions component and node merging feature falg
* Do not show regular nodes without actions
* Make sure to add manual trigger when adding http node via actions hint
* Fixed api hint footer line height
* Prevent pointer-events od NodeIcon img and remove "this" from template
* Address PR points
* Fix e2e specs
* Make sure canvas ia loaded
* Make sure canvas ia loaded before opening nodeCreator in e2e spec
* Fix flaky workflows tags e2e getter
* Imrpove node creator click outside UX, add manual node to regular nodes added from trigger panel
* Add manual trigger node if dragging regular from trigger panel
2022-12-09 01:56:36 -08:00
2022-12-14 01:04:10 -08:00
this . onAddNode ( nodesToAdd , true ) ;
this . createNodeActive = false ;
}
} ,
2022-04-19 03:28:31 -07:00
2022-12-14 01:04:10 -08:00
nodeDeselectedByName ( nodeName : string ) {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( node ) {
this . nodeDeselected ( node ) ;
}
} ,
2019-07-17 10:05:03 -07:00
2022-12-14 01:04:10 -08:00
nodeSelectedByName ( nodeName : string , setActive = false , deselectAllOthers ? : boolean ) {
if ( deselectAllOthers === true ) {
this . deselectAllNodes ( ) ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( node ) {
this . nodeSelected ( node ) ;
this . uiStore . lastSelectedNode = node . name ;
this . uiStore . lastSelectedNodeOutputIndex = null ;
this . lastSelectedConnection = null ;
this . newNodeInsertPosition = null ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( setActive ) {
this . ndvStore . activeNodeName = node . name ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
}
} ,
showMaxNodeTypeError ( nodeTypeData : INodeTypeDescription ) {
const maxNodes = nodeTypeData . maxNodes ;
this . $showMessage ( {
title : this . $locale . baseText ( 'nodeView.showMessage.showMaxNodeTypeError.title' ) ,
message : this . $locale . baseText ( 'nodeView.showMessage.showMaxNodeTypeError.message' , {
adjustToNumber : maxNodes ,
interpolate : { nodeTypeDataDisplayName : nodeTypeData . displayName } ,
} ) ,
type : 'error' ,
duration : 0 ,
} ) ;
} ,
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
async getNewNodeWithDefaultCredential ( nodeTypeData : INodeTypeDescription ) {
const newNodeData : INodeUi = {
id : uuid ( ) ,
name : nodeTypeData . defaults . name as string ,
type : nodeTypeData . name ,
typeVersion : Array . isArray ( nodeTypeData . version )
? nodeTypeData . version . slice ( - 1 ) [ 0 ]
: nodeTypeData . version ,
position : [ 0 , 0 ] ,
parameters : { } ,
} ;
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
const credentialPerType =
nodeTypeData . credentials &&
nodeTypeData . credentials
2022-12-23 07:32:06 -08:00
. map ( ( type ) => this . credentialsStore . getUsableCredentialByType ( type . name ) )
2022-12-14 01:04:10 -08:00
. flat ( ) ;
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
if ( credentialPerType && credentialPerType . length === 1 ) {
const defaultCredential = credentialPerType [ 0 ] ;
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
const selectedCredentials = this . credentialsStore . getCredentialById ( defaultCredential . id ) ;
const selected = { id : selectedCredentials . id , name : selectedCredentials . name } ;
const credentials = {
[ defaultCredential . type ] : selected ,
} ;
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
await this . loadNodesProperties (
[ newNodeData ] . map ( ( node ) => ( { name : node . type , version : node . typeVersion } ) ) ,
) ;
const nodeType = this . nodeTypesStore . getNodeType ( newNodeData . type , newNodeData . typeVersion ) ;
const nodeParameters = NodeHelpers . getNodeParameters (
nodeType ? . properties || [ ] ,
{ } ,
true ,
false ,
newNodeData ,
) ;
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
if ( nodeTypeData . credentials ) {
const authentication = nodeTypeData . credentials . find (
( type ) => type . name === defaultCredential . type ,
) ;
if ( authentication ? . displayOptions ? . hide ) {
return newNodeData ;
}
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
const authDisplayOptions = authentication ? . displayOptions ? . show ;
if ( ! authDisplayOptions ) {
newNodeData . credentials = credentials ;
return newNodeData ;
}
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
if (
Object . keys ( authDisplayOptions ) . length === 1 &&
authDisplayOptions [ 'authentication' ]
) {
// ignore complex case when there's multiple dependencies
newNodeData . credentials = credentials ;
let parameters : { [ key : string ] : string } = { } ;
for ( const displayOption of Object . keys ( authDisplayOptions ) ) {
if ( nodeParameters && ! nodeParameters [ displayOption ] ) {
parameters = { } ;
newNodeData . credentials = undefined ;
break ;
}
const optionValue = authDisplayOptions [ displayOption ] ? . [ 0 ] ;
if ( optionValue && typeof optionValue === 'string' ) {
parameters [ displayOption ] = optionValue ;
2022-10-17 04:39:42 -07:00
}
2022-12-14 01:04:10 -08:00
newNodeData . parameters = {
... newNodeData . parameters ,
... parameters ,
} ;
2022-10-17 04:39:42 -07:00
}
}
}
2022-12-14 01:04:10 -08:00
}
return newNodeData ;
} ,
2022-10-17 04:39:42 -07:00
2022-12-14 01:04:10 -08:00
async injectNode (
nodeTypeName : string ,
options : AddNodeOptions = { } ,
showDetail = true ,
trackHistory = false ,
2023-02-17 06:08:26 -08:00
isAutoAdd = false ,
2022-12-14 01:04:10 -08:00
) {
const nodeTypeData : INodeTypeDescription | null =
this . nodeTypesStore . getNodeType ( nodeTypeName ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( nodeTypeData === null ) {
this . $showMessage ( {
title : this . $locale . baseText ( 'nodeView.showMessage.addNodeButton.title' ) ,
message : this . $locale . baseText ( 'nodeView.showMessage.addNodeButton.message' , {
interpolate : { nodeTypeName } ,
} ) ,
type : 'error' ,
} ) ;
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if (
nodeTypeData . maxNodes !== undefined &&
this . getNodeTypeCount ( nodeTypeName ) >= nodeTypeData . maxNodes
) {
this . showMaxNodeTypeError ( nodeTypeData ) ;
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const newNodeData = await this . getNewNodeWithDefaultCredential ( nodeTypeData ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// when pulling new connection from node or injecting into a connection
const lastSelectedNode = this . lastSelectedNode ;
2022-04-19 03:28:31 -07:00
2022-12-14 01:04:10 -08:00
if ( options . position ) {
newNodeData . position = NodeViewUtils . getNewNodePosition (
this . canvasStore . getNodesWithPlaceholderNode ( ) ,
options . position ,
) ;
} else if ( lastSelectedNode ) {
const lastSelectedConnection = this . lastSelectedConnection ;
if ( lastSelectedConnection ) {
// set when injecting into a connection
const [ diffX ] = NodeViewUtils . getConnectorLengths ( lastSelectedConnection ) ;
if ( diffX <= NodeViewUtils . MAX _X _TO _PUSH _DOWNSTREAM _NODES ) {
this . pushDownstreamNodes (
lastSelectedNode . name ,
NodeViewUtils . PUSH _NODES _OFFSET ,
trackHistory ,
) ;
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
// set when pulling connections
if ( this . newNodeInsertPosition ) {
newNodeData . position = NodeViewUtils . getNewNodePosition ( this . nodes , [
this . newNodeInsertPosition [ 0 ] + NodeViewUtils . GRID _SIZE ,
this . newNodeInsertPosition [ 1 ] - NodeViewUtils . NODE _SIZE / 2 ,
] ) ;
this . newNodeInsertPosition = null ;
} else {
let yOffset = 0 ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
if ( lastSelectedConnection ) {
const sourceNodeType = this . nodeTypesStore . getNodeType (
lastSelectedNode . type ,
lastSelectedNode . typeVersion ,
2021-11-19 01:17:13 -08:00
) ;
2022-12-14 01:04:10 -08:00
const offsets = [
[ - 100 , 100 ] ,
[ - 140 , 0 , 140 ] ,
[ - 240 , - 100 , 100 , 240 ] ,
] ;
if ( sourceNodeType && sourceNodeType . outputs . length > 1 ) {
const offset = offsets [ sourceNodeType . outputs . length - 2 ] ;
const sourceOutputIndex = lastSelectedConnection . _ _meta
? lastSelectedConnection . _ _meta . sourceOutputIndex
: 0 ;
yOffset = offset [ sourceOutputIndex ] ;
}
2021-11-19 01:17:13 -08:00
}
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
2022-12-14 01:04:10 -08:00
// If a node is active then add the new node directly after the current one
newNodeData . position = NodeViewUtils . getNewNodePosition (
this . nodes ,
[
lastSelectedNode . position [ 0 ] + NodeViewUtils . PUSH _NODES _OFFSET ,
lastSelectedNode . position [ 1 ] + yOffset ,
] ,
[ 100 , 0 ] ,
) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
} else {
// If added node is a trigger and it's the first one added to the canvas
// we place it at canvasAddButtonPosition to replace the canvas add button
const position =
this . nodeTypesStore . isTriggerNode ( nodeTypeName ) && ! this . containsTrigger
? this . canvasStore . canvasAddButtonPosition
: // If no node is active find a free spot
( this . lastClickPosition as XYPosition ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
newNodeData . position = NodeViewUtils . getNewNodePosition ( this . nodes , position ) ;
}
2021-12-02 08:51:50 -08:00
2022-12-14 01:04:10 -08:00
// Check if node-name is unique else find one that is
newNodeData . name = this . getUniqueNodeName ( {
originalName : newNodeData . name ,
type : newNodeData . type ,
} ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( nodeTypeData . webhooks && nodeTypeData . webhooks . length ) {
newNodeData . webhookId = uuid ( ) ;
}
2020-11-04 04:04:40 -08:00
2022-12-14 01:04:10 -08:00
await this . addNodes ( [ newNodeData ] , undefined , trackHistory ) ;
2023-01-16 05:55:58 -08:00
this . workflowsStore . setNodePristine ( newNodeData . name , true ) ;
2022-07-09 23:53:04 -07:00
2022-12-14 01:04:10 -08:00
this . uiStore . stateIsDirty = true ;
2022-07-09 23:53:04 -07:00
2022-12-14 01:04:10 -08:00
if ( nodeTypeName === STICKY _NODE _TYPE ) {
this . $telemetry . trackNodesPanel ( 'nodeView.addSticky' , {
workflow _id : this . workflowsStore . workflowId ,
} ) ;
} else {
this . $externalHooks ( ) . run ( 'nodeView.addNodeButton' , { nodeTypeName } ) ;
const trackProperties : ITelemetryTrackProperties = {
node _type : nodeTypeName ,
2023-02-17 06:08:26 -08:00
is _auto _add : isAutoAdd ,
2022-12-14 01:04:10 -08:00
workflow _id : this . workflowsStore . workflowId ,
drag _and _drop : options . dragAndDrop ,
} ;
2021-05-05 17:46:33 -07:00
2022-12-14 01:04:10 -08:00
if ( lastSelectedNode ) {
trackProperties . input _node _type = lastSelectedNode . type ;
feat(editor): Node creator actions (#4696)
* WIP: Node Actions List UI
* WIP: Recommended Actions and preseting of fields
* WIP: Resource category
* :art: Moved actions categorisation to the server
* :label: Add missing INodeAction type
* :sparkles: Improve SSR categorisation, fix adding of mixed actions
* :recycle: Refactor CategorizedItems to composition api, style fixes
* WIP: Adding multiple nodes
* :recycle: Refactor rest of the NodeCreator component to composition API, conver globalLinkActions to composable
* :sparkles: Allow actions dragging, fix search and refactor passing of actions to categorized items
* :lipstick: Fix node actions title
* Migrate to the pinia store, add posthog feature and various fixes
* :bug: Fix filtering of trigger actions when not merged
* fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root
* :bug: Design review fixes
* :bug: Fix disabling of merged actions
* Fix trigger root filtering
* :sparkles: Allow for custom node actions parser, introduce hubspot parser
* :bug: Fix initial node params validation, fix position of second added node
* :bug: Introduce operations category, removed canvas node names overrride, fix API actions display and prevent dragging of action nodes
* :sparkles: Prevent NDV auto-open feature flag
* :bug: Inject recommened action for trigger nodes without actions
* Refactored NodeCreatorNode to Storybook, change filtering of merged nodes for the trigger helper panel, minor fixes
* Improve rendering of app nodes and animation
* Cleanup, any only enable accordion transition on triggerhelperpanel
* Hide node creator scrollbars in Firefox
* Minor styles fixes
* Do not copy the array in rendering method
* Removed unused props
* Fix memory leak
* Fix categorisation of regular nodes with a single resource
* Implement telemetry calls for node actions
* Move categorization to FE
* Fix client side actions categorisation
* Skip custom action show
* Only load tooltip for NodeIcon if necessary
* Fix lodash startCase import
* Remove lodash.startcase
* Cleanup
* Fix node creator autofocus on "tab"
* Prevent posthog getFeatureFlag from crashing
* Debugging preview env search issues
* Remove logs
* Make sure the pre-filled params are update not overwritten
* Get rid of transition in itemiterator
* WIP: Rough version of NodeActions keyboard navigation, replace nodeCreator composable with Pinia store module
* Rewrite to add support for ActionItem to ItemIterator and make CategorizedItems accept items props
* Fix category item counter & cleanup
* Add APIHint to actions search no-result, clean up NodeCreatorNode
* Improve node actions no results message
* Remove logging, fix filtering of recommended placeholder category
* Remove unused NodeActions component and node merging feature falg
* Do not show regular nodes without actions
* Make sure to add manual trigger when adding http node via actions hint
* Fixed api hint footer line height
* Prevent pointer-events od NodeIcon img and remove "this" from template
* Address PR points
* Fix e2e specs
* Make sure canvas ia loaded
* Make sure canvas ia loaded before opening nodeCreator in e2e spec
* Fix flaky workflows tags e2e getter
* Imrpove node creator click outside UX, add manual node to regular nodes added from trigger panel
* Add manual trigger node if dragging regular from trigger panel
2022-12-09 01:56:36 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . $telemetry . trackNodesPanel ( 'nodeView.addNodeButton' , trackProperties ) ;
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
// Automatically deselect all nodes and select the current one and also active
// current node. But only if it's added manually by the user (not by undo/redo mechanism)
if ( trackHistory ) {
this . deselectAllNodes ( ) ;
2023-01-10 00:39:37 -08:00
if ( showDetail ) {
2022-12-14 01:04:10 -08:00
setTimeout ( ( ) => {
this . nodeSelectedByName ( newNodeData . name , nodeTypeName !== STICKY _NODE _TYPE ) ;
} ) ;
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
return newNodeData ;
} ,
getConnection (
sourceNodeName : string ,
sourceNodeOutputIndex : number ,
targetNodeName : string ,
targetNodeOuputIndex : number ,
) : IConnection | undefined {
const nodeConnections = (
this . workflowsStore . outgoingConnectionsByNodeName ( sourceNodeName ) as INodeConnections
) . main ;
if ( nodeConnections ) {
const connections : IConnection [ ] | null = nodeConnections [ sourceNodeOutputIndex ] ;
if ( connections ) {
return connections . find (
( connection : IConnection ) =>
connection . node === targetNodeName && connection . index === targetNodeOuputIndex ,
) ;
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
return undefined ;
} ,
connectTwoNodes (
sourceNodeName : string ,
sourceNodeOutputIndex : number ,
targetNodeName : string ,
targetNodeOuputIndex : number ,
) {
2023-02-01 07:50:35 -08:00
this . uiStore . stateIsDirty = true ;
2022-12-14 01:04:10 -08:00
if (
this . getConnection (
sourceNodeName ,
sourceNodeOutputIndex ,
targetNodeName ,
targetNodeOuputIndex ,
)
) {
return ;
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
const connectionData = [
{
node : sourceNodeName ,
type : 'main' ,
index : sourceNodeOutputIndex ,
} ,
{
node : targetNodeName ,
type : 'main' ,
index : targetNodeOuputIndex ,
} ,
] as [ IConnection , IConnection ] ;
2023-02-09 07:04:26 -08:00
this . _ _addConnection ( connectionData ) ;
2022-12-14 01:04:10 -08:00
} ,
async addNode (
nodeTypeName : string ,
options : AddNodeOptions = { } ,
showDetail = true ,
trackHistory = false ,
2023-02-17 06:08:26 -08:00
isAutoAdd = false ,
2022-12-14 01:04:10 -08:00
) {
if ( ! this . editAllowedCheck ( ) ) {
return ;
}
2022-12-09 06:07:37 -08:00
2022-12-14 01:04:10 -08:00
const lastSelectedConnection = this . lastSelectedConnection ;
const lastSelectedNode = this . lastSelectedNode ;
const lastSelectedNodeOutputIndex = this . uiStore . lastSelectedNodeOutputIndex ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
this . historyStore . startRecordingUndo ( ) ;
2019-12-10 06:39:14 -08:00
2023-02-17 06:08:26 -08:00
const newNodeData = await this . injectNode (
nodeTypeName ,
options ,
showDetail ,
trackHistory ,
isAutoAdd ,
) ;
2022-12-14 01:04:10 -08:00
if ( ! newNodeData ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const outputIndex = lastSelectedNodeOutputIndex || 0 ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
// If a node is last selected then connect between the active and its child ones
if ( lastSelectedNode ) {
await Vue . nextTick ( ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( lastSelectedConnection && lastSelectedConnection . _ _meta ) {
this . _ _deleteJSPlumbConnection ( lastSelectedConnection , trackHistory ) ;
const targetNodeName = lastSelectedConnection . _ _meta . targetNodeName ;
const targetOutputIndex = lastSelectedConnection . _ _meta . targetOutputIndex ;
2023-02-01 07:50:35 -08:00
this . connectTwoNodes ( newNodeData . name , 0 , targetNodeName , targetOutputIndex ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
// Connect active node to the newly created one
2023-02-01 07:50:35 -08:00
this . connectTwoNodes ( lastSelectedNode . name , outputIndex , newNodeData . name , 0 ) ;
2022-12-14 01:04:10 -08:00
}
this . historyStore . stopRecordingUndo ( ) ;
} ,
initNodeView ( ) {
2023-01-30 09:20:50 -08:00
this . instance ? . importDefaults ( {
endpoint : {
type : 'Dot' ,
options : { radius : 5 } ,
} ,
paintStyle : NodeViewUtils . CONNECTOR _PAINT _STYLE _DEFAULT ,
hoverPaintStyle : NodeViewUtils . CONNECTOR _PAINT _STYLE _PRIMARY ,
connectionOverlays : NodeViewUtils . CONNECTOR _ARROW _OVERLAYS ,
2022-12-14 01:04:10 -08:00
} ) ;
2019-12-10 06:39:14 -08:00
2022-12-14 01:04:10 -08:00
const insertNodeAfterSelected = ( info : {
sourceId : string ;
index : number ;
eventSource : string ;
connection ? : Connection ;
} ) => {
// Get the node and set it as active that new nodes
// which get created get automatically connected
// to it.
const sourceNode = this . workflowsStore . getNodeById ( info . sourceId ) ;
if ( ! sourceNode ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . uiStore . lastSelectedNode = sourceNode . name ;
this . uiStore . lastSelectedNodeOutputIndex = info . index ;
this . newNodeInsertPosition = null ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( info . connection ) {
this . lastSelectedConnection = info . connection ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . onToggleNodeCreator ( { source : info . eventSource , createNodeActive : true } ) ;
} ;
2021-11-19 01:17:13 -08:00
2023-01-30 09:20:50 -08:00
this . instance . bind ( EVENT _CONNECTION _ABORT , ( connection : Connection ) => {
2022-12-14 01:04:10 -08:00
try {
if ( this . dropPrevented ) {
this . dropPrevented = false ;
return ;
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
if ( this . pullConnActiveNodeName ) {
2023-01-30 09:20:50 -08:00
const sourceNode = this . workflowsStore . getNodeById ( connection . parameters . nodeId ) ;
2022-12-14 01:04:10 -08:00
if ( sourceNode ) {
const sourceNodeName = sourceNode . name ;
2023-01-30 09:20:50 -08:00
const outputIndex = connection . parameters . index ;
2021-11-19 01:17:13 -08:00
2023-02-01 07:50:35 -08:00
this . connectTwoNodes ( sourceNodeName , outputIndex , this . pullConnActiveNodeName , 0 ) ;
2021-11-19 01:17:13 -08:00
this . pullConnActiveNodeName = null ;
2023-02-06 00:49:18 -08:00
this . dropPrevented = true ;
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
return ;
2020-05-24 05:06:22 -07:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
insertNodeAfterSelected ( {
2023-01-30 09:20:50 -08:00
sourceId : connection . parameters . nodeId ,
index : connection . parameters . index ,
2022-12-14 01:04:10 -08:00
eventSource : 'node_connection_drop' ,
} ) ;
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
}
} ) ;
2019-08-02 06:56:05 -07:00
2023-01-30 09:20:50 -08:00
this . instance . bind ( INTERCEPT _BEFORE _DROP , ( info : BeforeDropParams ) => {
2022-12-14 01:04:10 -08:00
try {
2023-01-30 09:20:50 -08:00
const sourceInfo = info . connection . endpoints [ 0 ] . parameters ;
const targetInfo = info . dropEndpoint . parameters ;
2019-08-02 06:56:05 -07:00
2022-12-14 01:04:10 -08:00
const sourceNodeName = this . workflowsStore . getNodeById ( sourceInfo . nodeId ) ? . name || '' ;
const targetNodeName = this . workflowsStore . getNodeById ( targetInfo . nodeId ) ? . name || '' ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
// check for duplicates
if (
this . getConnection ( sourceNodeName , sourceInfo . index , targetNodeName , targetInfo . index )
) {
this . dropPrevented = true ;
this . pullConnActiveNodeName = null ;
return false ;
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
return true ;
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
return true ;
}
} ) ;
2021-11-19 01:17:13 -08:00
2023-01-30 09:20:50 -08:00
this . instance . bind ( EVENT _CONNECTION , ( info : ConnectionEstablishedParams ) => {
2022-12-14 01:04:10 -08:00
try {
2023-01-30 09:20:50 -08:00
const sourceInfo = info . sourceEndpoint . parameters ;
const targetInfo = info . targetEndpoint . parameters ;
2022-12-14 01:04:10 -08:00
const sourceNodeName = this . workflowsStore . getNodeById ( sourceInfo . nodeId ) ? . name ;
const targetNodeName = this . workflowsStore . getNodeById ( targetInfo . nodeId ) ? . name ;
if ( sourceNodeName && targetNodeName ) {
info . connection . _ _meta = {
sourceNodeName ,
sourceOutputIndex : sourceInfo . index ,
targetNodeName ,
targetOutputIndex : targetInfo . index ,
} ;
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
NodeViewUtils . resetConnection ( info . connection ) ;
NodeViewUtils . moveBackInputLabelPosition ( info . targetEndpoint ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const connectionData : [ IConnection , IConnection ] = [
{
node : sourceNodeName ,
type : sourceInfo . type ,
index : sourceInfo . index ,
} ,
{
node : targetNodeName ,
type : targetInfo . type ,
index : targetInfo . index ,
} ,
] ;
2021-11-19 01:17:13 -08:00
2023-01-30 09:20:50 -08:00
this . dropPrevented = true ;
2023-02-06 00:49:18 -08:00
this . workflowsStore . addConnection ( { connection : connectionData } ) ;
this . uiStore . stateIsDirty = true ;
2022-12-14 01:04:10 -08:00
if ( ! this . suspendRecordingDetachedConnections ) {
2023-01-30 09:20:50 -08:00
this . historyStore . pushCommandToUndo ( new AddConnectionCommand ( connectionData ) ) ;
}
if ( ! this . isReadOnly ) {
NodeViewUtils . addConnectionActionsOverlay (
info . connection ,
( ) => {
this . activeConnection = null ;
this . _ _deleteJSPlumbConnection ( info . connection ) ;
} ,
( ) => {
insertNodeAfterSelected ( {
sourceId : info . sourceEndpoint . parameters . nodeId ,
index : sourceInfo . index ,
connection : info . connection ,
eventSource : 'node_connection_action' ,
} ) ;
} ,
) ;
2023-02-07 07:34:08 -08:00
setTimeout ( ( ) => {
NodeViewUtils . addConnectionTestData (
info . source ,
info . target ,
'canvas' in info . connection . connector
? ( info . connection . connector . canvas as HTMLElement )
: undefined ,
) ;
} , 0 ) ;
2022-12-14 01:04:10 -08:00
}
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
}
} ) ;
2021-11-19 01:17:13 -08:00
2023-01-30 09:20:50 -08:00
this . instance . bind ( EVENT _DRAG _MOVE , ( ) => {
this . instance ? . connections . forEach ( ( connection ) => {
NodeViewUtils . showOrHideItemsLabel ( connection ) ;
NodeViewUtils . showOrHideMidpointArrow ( connection ) ;
Object . values ( connection . overlays ) . forEach ( ( overlay ) => {
if ( ! overlay . canvas ) return ;
this . instance ? . repaint ( overlay . canvas ) ;
} ) ;
} ) ;
} ) ;
this . instance . bind ( EVENT _CONNECTION _MOUSEOVER , ( connection : Connection ) => {
try {
if ( this . exitTimer !== undefined ) {
clearTimeout ( this . exitTimer ) ;
this . exitTimer = undefined ;
}
if (
this . isReadOnly ||
this . enterTimer ||
! connection ||
connection === this . activeConnection
)
return ;
if ( this . activeConnection ) NodeViewUtils . hideConnectionActions ( this . activeConnection ) ;
this . enterTimer = setTimeout ( ( ) => {
this . enterTimer = undefined ;
if ( connection ) {
NodeViewUtils . showConnectionActions ( connection ) ;
this . activeConnection = connection ;
}
} , 150 ) ;
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
}
} ) ;
this . instance . bind ( EVENT _CONNECTION _MOUSEOUT , ( connection : Connection ) => {
try {
if ( this . exitTimer ) return ;
if ( this . enterTimer ) {
clearTimeout ( this . enterTimer ) ;
this . enterTimer = undefined ;
}
if ( this . isReadOnly || ! connection || this . activeConnection ? . id !== connection . id ) return ;
this . exitTimer = setTimeout ( ( ) => {
this . exitTimer = undefined ;
if ( connection && this . activeConnection === connection ) {
NodeViewUtils . hideConnectionActions ( this . activeConnection ) ;
this . activeConnection = null ;
}
} , 500 ) ;
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
}
} ) ;
this . instance . bind ( EVENT _CONNECTION _MOVED , ( info : ConnectionMovedParams ) => {
2022-12-14 01:04:10 -08:00
try {
// When a connection gets moved from one node to another it for some reason
// calls the "connection" event but not the "connectionDetached" one. So we listen
// additionally to the "connectionMoved" event and then only delete the existing connection.
2019-06-23 03:35:23 -07:00
2023-01-30 09:20:50 -08:00
NodeViewUtils . resetInputLabelPosition ( info . connection ) ;
2021-11-19 01:17:13 -08:00
2023-01-30 09:20:50 -08:00
const sourceInfo = info . connection . parameters ;
const targetInfo = info . originalEndpoint . parameters ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
const connectionInfo = [
{
node : this . workflowsStore . getNodeById ( sourceInfo . nodeId ) ? . name || '' ,
type : sourceInfo . type ,
index : sourceInfo . index ,
} ,
{
node : this . workflowsStore . getNodeById ( targetInfo . nodeId ) ? . name || '' ,
type : targetInfo . type ,
index : targetInfo . index ,
} ,
] as [ IConnection , IConnection ] ;
this . _ _removeConnection ( connectionInfo , false ) ;
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
}
} ) ;
2023-01-30 09:20:50 -08:00
this . instance . bind ( EVENT _ENDPOINT _MOUSEOVER , ( endpoint : Endpoint , mouse ) => {
// This event seems bugged. It gets called constantly even when the mouse is not over the endpoint
// if the endpoint has a connection attached to it. So we need to check if the mouse is actually over
// the endpoint.
if ( ! endpoint . isTarget || mouse . target !== endpoint . endpoint . canvas ) return ;
this . instance . setHover ( endpoint , true ) ;
} ) ;
this . instance . bind ( EVENT _ENDPOINT _MOUSEOUT , ( endpoint : Endpoint ) => {
if ( ! endpoint . isTarget ) return ;
this . instance . setHover ( endpoint , false ) ;
} ) ;
this . instance . bind ( EVENT _CONNECTION _DETACHED , async ( info : ConnectionDetachedParams ) => {
2022-12-14 01:04:10 -08:00
try {
const connectionInfo : [ IConnection , IConnection ] | null = getConnectionInfo ( info ) ;
NodeViewUtils . resetInputLabelPosition ( info . targetEndpoint ) ;
info . connection . removeOverlays ( ) ;
this . _ _removeConnectionByConnectionInfo ( info , false , false ) ;
if ( this . pullConnActiveNodeName ) {
// establish new connection when dragging connection from one node to another
this . historyStore . startRecordingUndo ( ) ;
2023-01-30 09:20:50 -08:00
const sourceNode = this . workflowsStore . getNodeById ( info . connection . parameters . nodeId ) ;
2022-12-14 01:04:10 -08:00
const sourceNodeName = sourceNode . name ;
2023-01-30 09:20:50 -08:00
const outputIndex = info . connection . parameters . index ;
2022-12-14 01:04:10 -08:00
if ( connectionInfo ) {
2023-01-30 09:20:50 -08:00
this . historyStore . pushCommandToUndo ( new RemoveConnectionCommand ( connectionInfo ) ) ;
2019-08-02 06:56:05 -07:00
}
2023-02-01 07:50:35 -08:00
this . connectTwoNodes ( sourceNodeName , outputIndex , this . pullConnActiveNodeName , 0 ) ;
2022-12-14 01:04:10 -08:00
this . pullConnActiveNodeName = null ;
await this . $nextTick ( ) ;
this . historyStore . stopRecordingUndo ( ) ;
} else if (
! this . historyStore . bulkInProgress &&
! this . suspendRecordingDetachedConnections &&
connectionInfo
) {
// Ff connection being detached by user, save this in history
// but skip if it's detached as a side effect of bulk undo/redo or node rename process
const removeCommand = new RemoveConnectionCommand ( connectionInfo , this ) ;
this . historyStore . pushCommandToUndo ( removeCommand ) ;
2019-08-02 06:56:05 -07:00
}
2022-12-14 01:04:10 -08:00
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
}
} ) ;
2023-01-30 09:20:50 -08:00
this . instance . bind ( EVENT _CONNECTION _DRAG , ( connection : Connection ) => {
// The overlays are visible by default so we need to hide the midpoint arrow
// manually
connection . overlays [ 'midpoint-arrow' ] ? . setVisible ( false ) ;
2022-12-14 01:04:10 -08:00
try {
this . pullConnActiveNodeName = null ;
this . pullConnActive = true ;
this . newNodeInsertPosition = null ;
NodeViewUtils . resetConnection ( connection ) ;
2021-12-06 00:41:15 -08:00
2023-01-30 09:20:50 -08:00
const nodes = [ ... document . querySelectorAll ( '.node-wrapper' ) ] ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
const onMouseMove = ( e : MouseEvent | TouchEvent ) => {
if ( ! connection ) {
return ;
}
2019-06-23 03:35:23 -07:00
2023-01-30 09:20:50 -08:00
const element = document . querySelector ( '.jtk-endpoint.jtk-drag-hover' ) ;
2022-12-14 01:04:10 -08:00
if ( element ) {
2023-01-30 09:20:50 -08:00
const endpoint = element . jtk . endpoint ;
NodeViewUtils . showDropConnectionState ( connection , endpoint ) ;
2022-12-14 01:04:10 -08:00
return ;
}
2019-08-02 06:56:05 -07:00
2022-12-14 01:04:10 -08:00
const inputMargin = 24 ;
const intersecting = nodes . find ( ( element : Element ) => {
const { top , left , right , bottom } = element . getBoundingClientRect ( ) ;
const [ x , y ] = NodeViewUtils . getMousePosition ( e ) ;
if ( top <= y && bottom >= y && left - inputMargin <= x && right >= x ) {
const nodeName = ( element as HTMLElement ) . dataset [ 'name' ] as string ;
const node = this . workflowsStore . getNodeByName ( nodeName ) as INodeUi | null ;
if ( node ) {
const nodeType = this . nodeTypesStore . getNodeType ( node . type , node . typeVersion ) ;
if ( nodeType && nodeType . inputs && nodeType . inputs . length === 1 ) {
this . pullConnActiveNodeName = node . name ;
const endpointUUID = this . getInputEndpointUUID ( nodeName , 0 ) ;
if ( endpointUUID ) {
2023-01-30 09:20:50 -08:00
const endpoint = this . instance ? . getEndpoint ( endpointUUID ) ;
2022-12-14 01:04:10 -08:00
NodeViewUtils . showDropConnectionState ( connection , endpoint ) ;
return true ;
2021-11-19 01:17:13 -08:00
}
}
}
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
return false ;
} ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! intersecting ) {
NodeViewUtils . showPullConnectionState ( connection ) ;
this . pullConnActiveNodeName = null ;
}
} ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const onMouseUp = ( e : MouseEvent | TouchEvent ) => {
this . pullConnActive = false ;
this . newNodeInsertPosition = this . getMousePositionWithinNodeView ( e ) ;
NodeViewUtils . resetConnectionAfterPull ( connection ) ;
window . removeEventListener ( 'mousemove' , onMouseMove ) ;
window . removeEventListener ( 'mouseup' , onMouseUp ) ;
} ;
2019-06-27 02:27:02 -07:00
2022-12-14 01:04:10 -08:00
window . addEventListener ( 'mousemove' , onMouseMove ) ;
window . addEventListener ( 'touchmove' , onMouseMove ) ;
window . addEventListener ( 'mouseup' , onMouseUp ) ;
window . addEventListener ( 'touchend' , onMouseMove ) ;
} catch ( e ) {
console . error ( e ) ; // eslint-disable-line no-console
}
} ) ;
2023-01-30 09:20:50 -08:00
this . instance . bind (
[ EVENT _CONNECTION _DRAG , EVENT _CONNECTION _ABORT , EVENT _CONNECTION _DETACHED ] ,
( connection : Connection ) => {
Object . values ( this . instance ? . endpointsByElement )
. flatMap ( ( endpoints ) => Object . values ( endpoints ) )
. filter ( ( endpoint ) => endpoint . endpoint . type === 'N8nPlus' )
. forEach ( ( endpoint ) =>
setTimeout ( ( ) => endpoint . instance . revalidate ( endpoint . element ) , 0 ) ,
) ;
} ,
) ;
2022-12-14 01:04:10 -08:00
this . instance . bind ( 'plusEndpointClick' , ( endpoint : Endpoint ) => {
if ( endpoint && endpoint . _ _meta ) {
insertNodeAfterSelected ( {
sourceId : endpoint . _ _meta . nodeId ,
index : endpoint . _ _meta . index ,
eventSource : 'plus_endpoint' ,
} ) ;
}
} ) ;
} ,
async newWorkflow ( ) : Promise < void > {
this . startLoading ( ) ;
await this . resetWorkspace ( ) ;
this . workflowData = await this . workflowsStore . getNewWorkflowData ( ) ;
this . workflowsStore . currentWorkflowExecutions = [ ] ;
this . workflowsStore . activeWorkflowExecution = null ;
2022-05-16 09:19:33 -07:00
2022-12-14 01:04:10 -08:00
this . uiStore . stateIsDirty = false ;
2023-01-13 02:56:29 -08:00
this . canvasStore . setZoomLevel ( 1 , [ 0 , 0 ] ) ;
this . tryToAddWelcomeSticky ( ) ;
this . uiStore . nodeViewInitialized = true ;
this . historyStore . reset ( ) ;
this . workflowsStore . activeWorkflowExecution = null ;
this . stopLoading ( ) ;
2022-12-14 01:04:10 -08:00
} ,
2023-01-13 02:56:29 -08:00
async tryToAddWelcomeSticky ( ) : Promise < void > {
2022-12-14 01:04:10 -08:00
const newWorkflow = this . workflowData ;
2023-02-21 00:35:35 -08:00
if (
usePostHogStore ( ) . isVariantEnabled ( ASSUMPTION _EXPERIMENT . name , ASSUMPTION _EXPERIMENT . video )
) {
2022-12-14 01:04:10 -08:00
// For novice users (onboardingFlowEnabled == true)
// Inject welcome sticky note and zoom to fit
if ( newWorkflow ? . onboardingFlowEnabled && ! this . isReadOnly ) {
// Position the welcome sticky left to the added trigger node
2023-01-13 02:56:29 -08:00
const position : XYPosition = [ 50 , 250 ] ;
2022-12-14 01:04:10 -08:00
await this . addNodes ( [
{
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
id : uuid ( ) ,
2022-11-24 01:52:56 -08:00
... NodeViewUtils . WELCOME _STICKY _NODE ,
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
parameters : {
// Use parameters from the template but add translated content
2022-11-24 01:52:56 -08:00
... NodeViewUtils . WELCOME _STICKY _NODE . parameters ,
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
content : this . $locale . baseText ( 'onboardingWorkflow.stickyContent' ) ,
} ,
position ,
2022-12-14 01:04:10 -08:00
} ,
] ) ;
2023-01-13 02:56:29 -08:00
setTimeout ( ( ) => {
this . canvasStore . zoomToFit ( ) ;
this . canvasStore . canvasAddButtonPosition = [ 500 , 350 ] ;
this . $telemetry . track ( 'welcome note inserted' ) ;
} , 0 ) ;
2019-06-23 03:35:23 -07:00
}
2023-01-13 02:56:29 -08:00
} else {
this . canvasStore . zoomToFit ( ) ;
2022-12-14 01:04:10 -08:00
}
2023-01-13 02:56:29 -08:00
} ,
2022-12-14 01:04:10 -08:00
async initView ( ) : Promise < void > {
if ( this . $route . params . action === 'workflowSave' ) {
// In case the workflow got saved we do not have to run init
// as only the route changed but all the needed data is already loaded
this . uiStore . stateIsDirty = false ;
return Promise . resolve ( ) ;
}
if ( this . blankRedirect ) {
this . blankRedirect = false ;
} else if ( this . $route . name === VIEWS . TEMPLATE _IMPORT ) {
const templateId = this . $route . params . id ;
await this . openWorkflowTemplate ( templateId ) ;
} else {
const result = this . uiStore . stateIsDirty ;
if ( result ) {
const confirmModal = await this . confirmModal (
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.message' ) ,
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.headline' ) ,
'warning' ,
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.confirmButtonText' ) ,
this . $locale . baseText ( 'generic.unsavedWork.confirmMessage.cancelButtonText' ) ,
true ,
) ;
if ( confirmModal === MODAL _CONFIRMED ) {
const saved = await this . saveCurrentWorkflow ( ) ;
if ( saved ) await this . settingsStore . fetchPromptsData ( ) ;
} else if ( confirmModal === MODAL _CLOSE ) {
return Promise . resolve ( ) ;
}
2021-06-22 10:33:07 -07:00
}
2022-12-14 01:04:10 -08:00
// Load a workflow
let workflowId = null as string | null ;
if ( this . $route . params . name ) {
workflowId = this . $route . params . name ;
2021-06-22 10:33:07 -07:00
}
2022-12-14 01:04:10 -08:00
if ( workflowId !== null ) {
2023-01-25 02:45:30 -08:00
let workflow : IWorkflowDb | undefined = undefined ;
2022-12-14 01:04:10 -08:00
try {
workflow = await this . restApi ( ) . getWorkflow ( workflowId ) ;
} catch ( error ) {
this . $showError ( error , this . $locale . baseText ( 'openWorkflow.workflowNotFoundError' ) ) ;
this . $router . push ( {
name : VIEWS . NEW _WORKFLOW ,
} ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-06 04:35:57 -08:00
2022-12-14 01:04:10 -08:00
if ( workflow ) {
this . $titleSet ( workflow . name , 'IDLE' ) ;
// Open existing workflow
2023-01-25 02:45:30 -08:00
await this . openWorkflow ( workflow ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
} else if ( this . $route . meta ? . nodeView === true ) {
// Create new workflow
await this . newWorkflow ( ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
}
this . historyStore . reset ( ) ;
this . uiStore . nodeViewInitialized = true ;
document . addEventListener ( 'keydown' , this . keyDown ) ;
document . addEventListener ( 'keyup' , this . keyUp ) ;
2023-02-09 06:59:01 -08:00
// allow to be overriden in e2e tests
// @ts-ignore
window . onBeforeUnload = ( e ) => {
2022-12-14 01:04:10 -08:00
if ( this . isDemo ) {
return ;
2023-02-01 07:50:35 -08:00
} else if ( this . uiStore . stateIsDirty ) {
2022-12-14 01:04:10 -08:00
const confirmationMessage = this . $locale . baseText (
'nodeView.itLooksLikeYouHaveBeenEditingSomething' ,
) ;
( e || window . event ) . returnValue = confirmationMessage ; //Gecko + IE
return confirmationMessage ; //Gecko + Webkit, Safari, Chrome etc.
} else {
this . startLoading ( this . $locale . baseText ( 'nodeView.redirecting' ) ) ;
return ;
2022-08-03 04:06:53 -07:00
}
2023-02-09 06:59:01 -08:00
} ;
window . addEventListener ( 'beforeunload' , window . onBeforeUnload ) ;
2022-12-14 01:04:10 -08:00
} ,
getOutputEndpointUUID ( nodeName : string , index : number ) : string | null {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( ! node ) {
return null ;
}
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
return NodeViewUtils . getOutputEndpointUUID ( node . id , index ) ;
} ,
getInputEndpointUUID ( nodeName : string , index : number ) {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( ! node ) {
return null ;
}
return NodeViewUtils . getInputEndpointUUID ( node . id , index ) ;
} ,
2023-02-09 07:04:26 -08:00
_ _addConnection ( connection : [ IConnection , IConnection ] ) {
const outputUuid = this . getOutputEndpointUUID ( connection [ 0 ] . node , connection [ 0 ] . index ) ;
const inputUuid = this . getInputEndpointUUID ( connection [ 1 ] . node , connection [ 1 ] . index ) ;
if ( ! outputUuid || ! inputUuid ) {
return ;
2022-12-14 01:04:10 -08:00
}
2023-02-09 07:04:26 -08:00
const uuid : [ string , string ] = [ outputUuid , inputUuid ] ;
// Create connections in DOM
this . instance ? . connect ( {
uuids : uuid ,
detachable : ! this . isReadOnly ,
} ) ;
2022-12-14 01:04:10 -08:00
setTimeout ( ( ) => {
this . addPinDataConnections ( this . workflowsStore . pinData ) ;
} ) ;
} ,
_ _removeConnection ( connection : [ IConnection , IConnection ] , removeVisualConnection = false ) {
if ( removeVisualConnection ) {
const sourceNode = this . workflowsStore . getNodeByName ( connection [ 0 ] . node ) ;
const targetNode = this . workflowsStore . getNodeByName ( connection [ 1 ] . node ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! sourceNode || ! targetNode ) {
return ;
2019-06-23 03:35:23 -07:00
}
2023-01-30 09:20:50 -08:00
const connections = this . instance ? . getConnections ( {
2022-12-14 01:04:10 -08:00
source : sourceNode . id ,
target : targetNode . id ,
2022-07-20 08:50:39 -07:00
} ) ;
2019-06-23 03:35:23 -07:00
2023-01-30 09:20:50 -08:00
connections . forEach ( ( connectionInstance : Connection ) => {
2022-12-14 01:04:10 -08:00
if ( connectionInstance . _ _meta ) {
// Only delete connections from specific indexes (if it can be determined by meta)
if (
connectionInstance . _ _meta . sourceOutputIndex === connection [ 0 ] . index &&
connectionInstance . _ _meta . targetOutputIndex === connection [ 1 ] . index
) {
2022-12-09 06:07:37 -08:00
this . _ _deleteJSPlumbConnection ( connectionInstance ) ;
}
2022-12-14 01:04:10 -08:00
} else {
this . _ _deleteJSPlumbConnection ( connectionInstance ) ;
}
} ) ;
}
this . workflowsStore . removeConnection ( { connection } ) ;
} ,
_ _deleteJSPlumbConnection ( connection : Connection , trackHistory = false ) {
// Make sure to remove the overlay else after the second move
// it visibly stays behind free floating without a connection.
connection . removeOverlays ( ) ;
this . pullConnActiveNodeName = null ; // prevent new connections when connectionDetached is triggered
2023-01-30 09:20:50 -08:00
this . instance ? . deleteConnection ( connection ) ; // on delete, triggers connectionDetached event which applies mutation to store
2022-12-14 01:04:10 -08:00
if ( trackHistory && connection . _ _meta ) {
const connectionData : [ IConnection , IConnection ] = [
{
index : connection . _ _meta ? . sourceOutputIndex ,
node : connection . _ _meta . sourceNodeName ,
type : 'main' ,
} ,
{
index : connection . _ _meta ? . targetOutputIndex ,
node : connection . _ _meta . targetNodeName ,
type : 'main' ,
} ,
] ;
const removeCommand = new RemoveConnectionCommand ( connectionData , this ) ;
this . historyStore . pushCommandToUndo ( removeCommand ) ;
}
} ,
2023-01-30 09:20:50 -08:00
_ _removeConnectionByConnectionInfo ( info , removeVisualConnection = false , trackHistory = false ) {
2022-12-14 01:04:10 -08:00
const connectionInfo : [ IConnection , IConnection ] | null = getConnectionInfo ( info ) ;
if ( connectionInfo ) {
if ( removeVisualConnection ) {
this . _ _deleteJSPlumbConnection ( info . connection , trackHistory ) ;
} else if ( trackHistory ) {
2023-01-30 09:20:50 -08:00
this . historyStore . pushCommandToUndo ( new RemoveConnectionCommand ( connectionInfo ) ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
this . workflowsStore . removeConnection ( { connection : connectionInfo } ) ;
}
} ,
async duplicateNode ( nodeName : string ) {
if ( ! this . editAllowedCheck ( ) ) {
return ;
}
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( node ) {
const nodeTypeData = this . nodeTypesStore . getNodeType ( node . type , node . typeVersion ) ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
if (
nodeTypeData &&
nodeTypeData . maxNodes !== undefined &&
this . getNodeTypeCount ( node . type ) >= nodeTypeData . maxNodes
) {
this . showMaxNodeTypeError ( nodeTypeData ) ;
2019-06-23 03:35:23 -07:00
return ;
}
2022-12-14 01:04:10 -08:00
// Deep copy the data so that data on lower levels of the node-properties do
// not share objects
const newNodeData = deepCopy ( this . getNodeDataToSave ( node ) ) ;
newNodeData . id = uuid ( ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Check if node-name is unique else find one that is
newNodeData . name = this . getUniqueNodeName ( {
originalName : newNodeData . name ,
type : newNodeData . type ,
} ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
newNodeData . position = NodeViewUtils . getNewNodePosition (
this . nodes ,
[ node . position [ 0 ] , node . position [ 1 ] + 140 ] ,
[ 0 , 140 ] ,
) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( newNodeData . webhookId ) {
// Make sure that the node gets a new unique webhook-ID
newNodeData . webhookId = uuid ( ) ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if (
newNodeData . credentials &&
2022-12-21 07:42:07 -08:00
this . settingsStore . isEnterpriseFeatureEnabled ( EnterpriseEditionFeature . Sharing )
2022-12-14 01:04:10 -08:00
) {
const usedCredentials = this . workflowsStore . usedCredentials ;
newNodeData . credentials = Object . fromEntries (
Object . entries ( newNodeData . credentials ) . filter ( ( [ _ , credential ] ) => {
return (
credential . id &&
( ! usedCredentials [ credential . id ] ||
usedCredentials [ credential . id ] ? . currentUserHasAccess )
) ;
} ) ,
2022-11-04 06:04:31 -07:00
) ;
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
await this . addNodes ( [ newNodeData ] , [ ] , true ) ;
2020-10-04 08:22:11 -07:00
2022-12-14 01:04:10 -08:00
const pinData = this . workflowsStore . pinDataByNodeName ( nodeName ) ;
if ( pinData ) {
this . workflowsStore . pinData ( {
node : newNodeData ,
data : pinData ,
} ) ;
}
2022-11-15 04:25:04 -08:00
2022-12-14 01:04:10 -08:00
this . uiStore . stateIsDirty = true ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Automatically deselect all nodes and select the current one and also active
// current node
this . deselectAllNodes ( ) ;
setTimeout ( ( ) => {
this . nodeSelectedByName ( newNodeData . name , false ) ;
} ) ;
2022-07-20 08:50:39 -07:00
2022-12-14 01:04:10 -08:00
this . $telemetry . track ( 'User duplicated node' , {
node _type : node . type ,
workflow _id : this . workflowsStore . workflowId ,
} ) ;
}
} ,
getJSPlumbConnection (
sourceNodeName : string ,
sourceOutputIndex : number ,
targetNodeName : string ,
targetInputIndex : number ,
) : Connection | undefined {
const sourceNode = this . workflowsStore . getNodeByName ( sourceNodeName ) ;
const targetNode = this . workflowsStore . getNodeByName ( targetNodeName ) ;
if ( ! sourceNode || ! targetNode ) {
return ;
}
2020-11-04 04:04:40 -08:00
2022-12-14 01:04:10 -08:00
const sourceId = sourceNode . id ;
const targetId = targetNode . id ;
2021-10-18 20:57:49 -07:00
2022-12-14 01:04:10 -08:00
const sourceEndpoint = NodeViewUtils . getOutputEndpointUUID ( sourceId , sourceOutputIndex ) ;
const targetEndpoint = NodeViewUtils . getInputEndpointUUID ( targetId , targetInputIndex ) ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
// @ts-ignore
2023-01-30 09:20:50 -08:00
const connections = this . instance ? . getConnections ( {
2022-12-14 01:04:10 -08:00
source : sourceId ,
target : targetId ,
} ) as Connection [ ] ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
return connections . find ( ( connection : Connection ) => {
const uuids = connection . getUuids ( ) ;
return uuids [ 0 ] === sourceEndpoint && uuids [ 1 ] === targetEndpoint ;
} ) ;
} ,
getJSPlumbEndpoints ( nodeName : string ) : Endpoint [ ] {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
2023-02-02 00:05:14 -08:00
const nodeEl = this . instance . getManagedElement ( node ? . id ) ;
2023-01-30 09:20:50 -08:00
2023-02-02 00:05:14 -08:00
const endpoints = this . instance ? . getEndpoints ( nodeEl ) ;
return endpoints ;
2022-12-14 01:04:10 -08:00
} ,
getPlusEndpoint ( nodeName : string , outputIndex : number ) : Endpoint | undefined {
const endpoints = this . getJSPlumbEndpoints ( nodeName ) ;
return endpoints . find (
( endpoint : Endpoint ) =>
2023-01-30 09:20:50 -08:00
// @ts-ignore
endpoint . endpoint . type === 'N8nPlus' && endpoint ? . _ _meta ? . index === outputIndex ,
2022-12-14 01:04:10 -08:00
) ;
} ,
getIncomingOutgoingConnections ( nodeName : string ) : {
incoming : Connection [ ] ;
outgoing : Connection [ ] ;
} {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
if ( node ) {
2021-11-19 01:17:13 -08:00
// @ts-ignore
2023-01-30 09:20:50 -08:00
const outgoing = this . instance ? . getConnections ( {
2022-12-14 01:04:10 -08:00
source : node . id ,
2021-11-19 01:17:13 -08:00
} ) ;
2022-12-14 01:04:10 -08:00
// @ts-ignore
2023-01-30 09:20:50 -08:00
const incoming = this . instance ? . getConnections ( {
2022-12-14 01:04:10 -08:00
target : node . id ,
} ) as Connection [ ] ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
return {
incoming ,
outgoing ,
} ;
}
return { incoming : [ ] , outgoing : [ ] } ;
} ,
onNodeMoved ( node : INodeUi ) {
const { incoming , outgoing } = this . getIncomingOutgoingConnections ( node . name ) ;
2022-11-04 06:04:31 -07:00
2022-12-14 01:04:10 -08:00
[ ... incoming , ... outgoing ] . forEach ( ( connection : Connection ) => {
NodeViewUtils . showOrHideMidpointArrow ( connection ) ;
NodeViewUtils . showOrHideItemsLabel ( connection ) ;
} ) ;
} ,
onNodeRun ( {
name ,
data ,
waiting ,
} : {
name : string ;
data : ITaskData [ ] | null ;
waiting : boolean ;
} ) {
const pinData = this . workflowsStore . getPinData ;
if ( pinData && pinData [ name ] ) return ;
const sourceNodeName = name ;
const sourceNode = this . workflowsStore . getNodeByName ( sourceNodeName ) ;
const sourceId = sourceNode !== null ? sourceNode . id : '' ;
if ( data === null || data . length === 0 || waiting ) {
2023-01-30 09:20:50 -08:00
const outgoing = this . instance ? . getConnections ( {
2022-12-14 01:04:10 -08:00
source : sourceId ,
} ) as Connection [ ] ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
outgoing . forEach ( ( connection : Connection ) => {
NodeViewUtils . resetConnection ( connection ) ;
2021-11-19 01:17:13 -08:00
} ) ;
2022-12-14 01:04:10 -08:00
const endpoints = this . getJSPlumbEndpoints ( sourceNodeName ) ;
endpoints . forEach ( ( endpoint : Endpoint ) => {
2023-01-30 09:20:50 -08:00
if ( endpoint . endpoint . type === 'N8nPlus' ) {
2022-12-14 01:04:10 -08:00
( endpoint . endpoint as N8nPlusEndpoint ) . clearSuccessOutput ( ) ;
}
} ) ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
return ;
}
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
const nodeConnections =
this . workflowsStore . outgoingConnectionsByNodeName ( sourceNodeName ) . main ;
const outputMap = NodeViewUtils . getOutputSummary ( data , nodeConnections || [ ] ) ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
Object . keys ( outputMap ) . forEach ( ( sourceOutputIndex : string ) => {
Object . keys ( outputMap [ sourceOutputIndex ] ) . forEach ( ( targetNodeName : string ) => {
Object . keys ( outputMap [ sourceOutputIndex ] [ targetNodeName ] ) . forEach (
( targetInputIndex : string ) => {
2021-12-03 09:53:55 -08:00
if ( targetNodeName ) {
2022-12-14 01:04:10 -08:00
const connection = this . getJSPlumbConnection (
sourceNodeName ,
parseInt ( sourceOutputIndex , 10 ) ,
targetNodeName ,
parseInt ( targetInputIndex , 10 ) ,
) ;
2021-11-19 01:17:13 -08:00
2021-12-03 09:53:55 -08:00
if ( connection ) {
const output = outputMap [ sourceOutputIndex ] [ targetNodeName ] [ targetInputIndex ] ;
2022-07-20 08:50:39 -07:00
2023-02-17 01:54:07 -08:00
if ( output . isArtificalRecoveredEventItem ) {
NodeViewUtils . recoveredConnection ( connection ) ;
} else if ( ( ! output || ! output . total ) && ! output . isArtificalRecoveredEventItem ) {
2022-11-24 01:52:56 -08:00
NodeViewUtils . resetConnection ( connection ) ;
2022-12-14 01:04:10 -08:00
} else {
2022-11-24 01:52:56 -08:00
NodeViewUtils . addConnectionOutputSuccess ( connection , output ) ;
2021-12-03 09:53:55 -08:00
}
}
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
const endpoint = this . getPlusEndpoint (
sourceNodeName ,
parseInt ( sourceOutputIndex , 10 ) ,
) ;
2021-12-03 09:53:55 -08:00
if ( endpoint && endpoint . endpoint ) {
const output = outputMap [ sourceOutputIndex ] [ NODE _OUTPUT _DEFAULT _KEY ] [ 0 ] ;
2023-01-30 09:20:50 -08:00
2021-12-03 09:53:55 -08:00
if ( output && output . total > 0 ) {
2022-12-14 01:04:10 -08:00
( endpoint . endpoint as N8nPlusEndpoint ) . setSuccessOutput (
NodeViewUtils . getRunItemsLabel ( output ) ,
) ;
} else {
2021-12-03 09:53:55 -08:00
( endpoint . endpoint as N8nPlusEndpoint ) . clearSuccessOutput ( ) ;
}
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
} ,
) ;
2021-11-19 01:17:13 -08:00
} ) ;
2022-12-14 01:04:10 -08:00
} ) ;
} ,
removeNode ( nodeName : string , trackHistory = false , trackBulk = true ) {
if ( ! this . editAllowedCheck ( ) ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( ! node ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( trackHistory && trackBulk ) {
this . historyStore . startRecordingUndo ( ) ;
}
2022-12-09 06:07:37 -08:00
2022-12-14 01:04:10 -08:00
// "requiredNodeTypes" are also defined in cli/commands/run.ts
const requiredNodeTypes : string [ ] = [ ] ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( requiredNodeTypes . includes ( node . type ) ) {
// The node is of the required type so check first
// if any node of that type would be left when the
// current one would get deleted.
let deleteAllowed = false ;
for ( const checkNode of this . nodes ) {
if ( checkNode . name === node . name ) {
continue ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
if ( requiredNodeTypes . includes ( checkNode . type ) ) {
deleteAllowed = true ;
break ;
2019-06-23 03:35:23 -07:00
}
}
2022-12-14 01:04:10 -08:00
if ( ! deleteAllowed ) {
return ;
2021-11-19 01:17:13 -08:00
}
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( node . type === STICKY _NODE _TYPE ) {
this . $telemetry . track ( 'User deleted workflow note' , {
workflow _id : this . workflowsStore . workflowId ,
is _welcome _note : node . name === QUICKSTART _NOTE _NAME ,
} ) ;
} else {
this . $externalHooks ( ) . run ( 'node.deleteNode' , { node } ) ;
this . $telemetry . track ( 'User deleted node' , {
node _type : node . type ,
workflow _id : this . workflowsStore . workflowId ,
} ) ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
let waitForNewConnection = false ;
// connect nodes before/after deleted node
const nodeType = this . nodeTypesStore . getNodeType ( node . type , node . typeVersion ) ;
if ( nodeType && nodeType . outputs . length === 1 && nodeType . inputs . length === 1 ) {
const { incoming , outgoing } = this . getIncomingOutgoingConnections ( node . name ) ;
if ( incoming . length === 1 && outgoing . length === 1 ) {
const conn1 = incoming [ 0 ] ;
const conn2 = outgoing [ 0 ] ;
if ( conn1 . _ _meta && conn2 . _ _meta ) {
waitForNewConnection = true ;
const sourceNodeName = conn1 . _ _meta . sourceNodeName ;
const sourceNodeOutputIndex = conn1 . _ _meta . sourceOutputIndex ;
const targetNodeName = conn2 . _ _meta . targetNodeName ;
const targetNodeOuputIndex = conn2 . _ _meta . targetOutputIndex ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
setTimeout ( ( ) => {
this . connectTwoNodes (
sourceNodeName ,
sourceNodeOutputIndex ,
targetNodeName ,
targetNodeOuputIndex ,
) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( waitForNewConnection ) {
2023-01-30 09:20:50 -08:00
this . instance ? . setSuspendDrawing ( false , true ) ;
2022-12-14 01:04:10 -08:00
waitForNewConnection = false ;
}
} , 100 ) ; // just to make it clear to users that this is a new connection
2022-12-09 06:07:37 -08:00
}
}
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
setTimeout ( ( ) => {
// Suspend drawing
2023-01-30 09:20:50 -08:00
this . instance ? . setSuspendDrawing ( true ) ;
( this . instance ? . endpointsByElement [ node . id ] || [ ] )
. flat ( )
. forEach ( ( endpoint ) => this . instance ? . deleteEndpoint ( endpoint ) ) ;
2019-07-24 06:21:44 -07:00
2022-12-14 01:04:10 -08:00
// Remove the connections in data
this . workflowsStore . removeAllNodeConnection ( node ) ;
this . workflowsStore . removeNode ( node ) ;
this . workflowsStore . clearNodeExecutionData ( node . name ) ;
2019-07-24 06:21:44 -07:00
2022-12-14 01:04:10 -08:00
if ( ! waitForNewConnection ) {
// Now it can draw again
2023-01-30 09:20:50 -08:00
this . instance ? . setSuspendDrawing ( false , true ) ;
2019-06-23 03:35:23 -07:00
}
2022-04-11 06:12:13 -07:00
2022-12-14 01:04:10 -08:00
// Remove node from selected index if found in it
this . uiStore . removeNodeFromSelection ( node ) ;
2022-12-09 06:07:37 -08:00
if ( trackHistory ) {
2023-01-30 09:20:50 -08:00
this . historyStore . pushCommandToUndo ( new RemoveNodeCommand ( node ) ) ;
2022-12-09 06:07:37 -08:00
}
2022-12-14 01:04:10 -08:00
} , 0 ) ; // allow other events to finish like drag stop
if ( trackHistory && trackBulk ) {
const recordingTimeout = waitForNewConnection ? 100 : 0 ;
setTimeout ( ( ) => {
this . historyStore . stopRecordingUndo ( ) ;
} , recordingTimeout ) ;
}
} ,
valueChanged ( parameterData : IUpdateInformation ) {
if ( parameterData . name === 'name' && parameterData . oldValue ) {
// The name changed so we have to take care that
// the connections get changed.
this . renameNode ( parameterData . oldValue as string , parameterData . value as string ) ;
}
} ,
async renameNodePrompt ( currentName : string ) {
try {
const promptResponsePromise = this . $prompt (
this . $locale . baseText ( 'nodeView.prompt.newName' ) + ':' ,
this . $locale . baseText ( 'nodeView.prompt.renameNode' ) + ` : ${ currentName } ` ,
{
customClass : 'rename-prompt' ,
confirmButtonText : this . $locale . baseText ( 'nodeView.prompt.rename' ) ,
cancelButtonText : this . $locale . baseText ( 'nodeView.prompt.cancel' ) ,
inputErrorMessage : this . $locale . baseText ( 'nodeView.prompt.invalidName' ) ,
inputValue : currentName ,
} ,
) ;
2022-12-09 06:07:37 -08:00
2022-12-14 01:04:10 -08:00
// Wait till it had time to display
await Vue . nextTick ( ) ;
// Get the input and select the text in it
const nameInput = document . querySelector ( '.rename-prompt .el-input__inner' ) as
| HTMLInputElement
| undefined ;
if ( nameInput ) {
nameInput . focus ( ) ;
nameInput . select ( ) ;
2022-04-11 06:12:13 -07:00
}
2022-12-14 01:04:10 -08:00
const promptResponse = ( await promptResponsePromise ) as MessageBoxInputData ;
this . renameNode ( currentName , promptResponse . value , true ) ;
} catch ( e ) { }
} ,
async renameNode ( currentName : string , newName : string , trackHistory = false ) {
if ( currentName === newName ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . suspendRecordingDetachedConnections = true ;
if ( trackHistory ) {
this . historyStore . startRecordingUndo ( ) ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const activeNodeName = this . activeNode && this . activeNode . name ;
const isActive = activeNodeName === currentName ;
if ( isActive ) {
this . renamingActive = true ;
}
2022-12-09 06:07:37 -08:00
2022-12-14 01:04:10 -08:00
// Check if node-name is unique else find one that is
newName = this . getUniqueNodeName ( {
originalName : newName ,
} ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Rename the node and update the connections
const workflow = this . getCurrentWorkflow ( true ) ;
workflow . renameNode ( currentName , newName ) ;
2021-11-30 11:37:55 -08:00
2022-12-14 01:04:10 -08:00
if ( trackHistory ) {
2023-01-30 09:20:50 -08:00
this . historyStore . pushCommandToUndo ( new RenameNodeCommand ( currentName , newName ) ) ;
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Update also last selected node and execution data
this . workflowsStore . renameNodeSelectedAndExecution ( { old : currentName , new : newName } ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Reset all nodes and connections to load the new ones
this . deleteEveryEndpoint ( ) ;
2019-07-24 06:04:24 -07:00
2022-12-14 01:04:10 -08:00
this . workflowsStore . removeAllConnections ( { setStateDirty : false } ) ;
this . workflowsStore . removeAllNodes ( { removePinData : false , setStateDirty : true } ) ;
2022-04-11 06:12:13 -07:00
2022-12-14 01:04:10 -08:00
// Wait a tick that the old nodes had time to get removed
await Vue . nextTick ( ) ;
2022-12-09 06:07:37 -08:00
2022-12-14 01:04:10 -08:00
// Add the new updated nodes
await this . addNodes ( Object . values ( workflow . nodes ) , workflow . connectionsBySourceNode , false ) ;
2021-11-30 11:37:55 -08:00
2022-12-14 01:04:10 -08:00
// Make sure that the node is selected again
this . deselectAllNodes ( ) ;
this . nodeSelectedByName ( newName ) ;
if ( isActive ) {
this . ndvStore . activeNodeName = newName ;
this . renamingActive = false ;
}
if ( trackHistory ) {
this . historyStore . stopRecordingUndo ( ) ;
}
this . suspendRecordingDetachedConnections = false ;
} ,
deleteEveryEndpoint ( ) {
// Check as it does not exist on first load
if ( this . instance ) {
2023-01-30 09:20:50 -08:00
this . instance ? . reset ( ) ;
Object . values ( this . instance ? . endpointsByElement )
. flatMap ( ( endpoint ) => endpoint )
. forEach ( ( endpoint ) => endpoint . destroy ( ) ) ;
2022-12-14 01:04:10 -08:00
2023-01-30 09:20:50 -08:00
this . instance . deleteEveryConnection ( { fireEvent : true } ) ;
2022-12-14 01:04:10 -08:00
}
} ,
matchCredentials ( node : INodeUi ) {
if ( ! node . credentials ) {
return ;
}
Object . entries ( node . credentials ) . forEach (
( [ nodeCredentialType , nodeCredentials ] : [ string , INodeCredentialsDetails ] ) => {
2022-11-09 01:01:50 -08:00
const credentialOptions = this . credentialsStore . getCredentialsByType ( nodeCredentialType ) ;
2021-10-13 15:21:00 -07:00
// Check if workflows applies old credentials style
if ( typeof nodeCredentials === 'string' ) {
nodeCredentials = {
id : null ,
name : nodeCredentials ,
} ;
this . credentialsUpdated = true ;
}
if ( nodeCredentials . id ) {
// Check whether the id is matching with a credential
2021-11-04 19:23:10 -07:00
const credentialsId = nodeCredentials . id . toString ( ) ; // due to a fixed bug in the migration UpdateWorkflowCredentials (just sqlite) we have to cast to string and check later if it has been a number
2022-12-14 01:04:10 -08:00
const credentialsForId = credentialOptions . find (
( optionData : ICredentialsResponse ) => optionData . id === credentialsId ,
2021-11-04 19:23:10 -07:00
) ;
2021-10-13 15:21:00 -07:00
if ( credentialsForId ) {
2022-12-14 01:04:10 -08:00
if (
credentialsForId . name !== nodeCredentials . name ||
typeof nodeCredentials . id === 'number'
) {
node . credentials ! [ nodeCredentialType ] = {
id : credentialsForId . id ,
name : credentialsForId . name ,
} ;
2021-10-13 15:21:00 -07:00
this . credentialsUpdated = true ;
}
return ;
}
}
// No match for id found or old credentials type used
node . credentials ! [ nodeCredentialType ] = nodeCredentials ;
// check if only one option with the name would exist
2022-12-14 01:04:10 -08:00
const credentialsForName = credentialOptions . filter (
( optionData : ICredentialsResponse ) => optionData . name === nodeCredentials . name ,
) ;
2021-10-13 15:21:00 -07:00
// only one option exists for the name, take it
if ( credentialsForName . length === 1 ) {
node . credentials ! [ nodeCredentialType ] . id = credentialsForName [ 0 ] . id ;
this . credentialsUpdated = true ;
}
2022-12-14 01:04:10 -08:00
} ,
) ;
} ,
async addNodes ( nodes : INodeUi [ ] , connections ? : IConnections , trackHistory = false ) {
if ( ! nodes || ! nodes . length ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Before proceeding we must check if all nodes contain the `properties` attribute.
// Nodes are loaded without this information so we must make sure that all nodes
// being added have this information.
await this . loadNodesProperties (
nodes . map ( ( node ) => ( { name : node . type , version : node . typeVersion } ) ) ,
) ;
// Add the node to the node-list
let nodeType : INodeTypeDescription | null ;
let foundNodeIssues : INodeIssues | null ;
nodes . forEach ( ( node ) => {
if ( ! node . id ) {
node . id = uuid ( ) ;
}
2020-10-22 08:24:35 -07:00
2022-12-14 01:04:10 -08:00
nodeType = this . nodeTypesStore . getNodeType ( node . type , node . typeVersion ) ;
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
// Make sure that some properties always exist
if ( ! node . hasOwnProperty ( 'disabled' ) ) {
node . disabled = false ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( ! node . hasOwnProperty ( 'parameters' ) ) {
node . parameters = { } ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Load the defaul parameter values because only values which differ
// from the defaults get saved
if ( nodeType !== null ) {
let nodeParameters = null ;
try {
nodeParameters = NodeHelpers . getNodeParameters (
nodeType . properties ,
node . parameters ,
true ,
false ,
node ,
) ;
} catch ( e ) {
console . error (
this . $locale . baseText ( 'nodeView.thereWasAProblemLoadingTheNodeParametersOfNode' ) +
` : " ${ node . name } " ` ,
) ; // eslint-disable-line no-console
console . error ( e ) ; // eslint-disable-line no-console
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
node . parameters = nodeParameters !== null ? nodeParameters : { } ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// if it's a webhook and the path is empty set the UUID as the default path
if ( node . type === WEBHOOK _NODE _TYPE && node . parameters . path === '' ) {
node . parameters . path = node . webhookId as string ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// check and match credentials, apply new format if old is used
this . matchCredentials ( node ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
foundNodeIssues = this . getNodeIssues ( nodeType , node ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( foundNodeIssues !== null ) {
node . issues = foundNodeIssues ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . workflowsStore . addNode ( node ) ;
if ( trackHistory ) {
2023-01-30 09:20:50 -08:00
this . historyStore . pushCommandToUndo ( new AddNodeCommand ( node ) ) ;
2022-12-14 01:04:10 -08:00
}
} ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Wait for the node to be rendered
await Vue . nextTick ( ) ;
// Suspend drawing
2023-01-30 09:20:50 -08:00
this . instance ? . setSuspendDrawing ( true ) ;
2022-12-14 01:04:10 -08:00
// Load the connections
if ( connections !== undefined ) {
let connectionData ;
for ( const sourceNode of Object . keys ( connections ) ) {
for ( const type of Object . keys ( connections [ sourceNode ] ) ) {
for (
let sourceIndex = 0 ;
sourceIndex < connections [ sourceNode ] [ type ] . length ;
sourceIndex ++
) {
const outwardConnections = connections [ sourceNode ] [ type ] [ sourceIndex ] ;
if ( ! outwardConnections ) {
continue ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
outwardConnections . forEach ( ( targetData ) => {
connectionData = [
{
node : sourceNode ,
type ,
index : sourceIndex ,
} ,
{
node : targetData . node ,
type : targetData . type ,
index : targetData . index ,
} ,
] as [ IConnection , IConnection ] ;
2023-02-09 07:04:26 -08:00
this . _ _addConnection ( connectionData ) ;
2022-12-14 01:04:10 -08:00
} ) ;
2019-06-23 03:35:23 -07:00
}
}
}
2022-12-14 01:04:10 -08:00
}
// Now it can draw again
2023-01-30 09:20:50 -08:00
this . instance ? . setSuspendDrawing ( false , true ) ;
2022-12-14 01:04:10 -08:00
} ,
async addNodesToWorkflow ( data : IWorkflowDataUpdate ) : Promise < IWorkflowDataUpdate > {
// Because nodes with the same name maybe already exist, it could
// be needed that they have to be renamed. Also could it be possible
// that nodes are not allowd to be created because they have a create
// limit set. So we would then link the new nodes with the already existing ones.
// In this object all that nodes get saved in the format:
// old-name -> new-name
const nodeNameTable : {
[ key : string ] : string ;
} = { } ;
const newNodeNames : string [ ] = [ ] ;
if ( ! data . nodes ) {
// No nodes to add
throw new Error ( this . $locale . baseText ( 'nodeView.noNodesGivenToAdd' ) ) ;
}
2020-10-23 04:44:34 -07:00
2022-12-14 01:04:10 -08:00
// Get how many of the nodes of the types which have
// a max limit set already exist
const nodeTypesCount = this . getNodeTypesMaxCount ( ) ;
let oldName : string ;
let newName : string ;
const createNodes : INode [ ] = [ ] ;
await this . loadNodesProperties (
data . nodes . map ( ( node ) => ( { name : node . type , version : node . typeVersion } ) ) ,
) ;
data . nodes . forEach ( ( node ) => {
if ( nodeTypesCount [ node . type ] !== undefined ) {
if ( nodeTypesCount [ node . type ] . exist >= nodeTypesCount [ node . type ] . max ) {
// Node is not allowed to be created so
// do not add it to the create list but
// add the name of the existing node
// that this one gets linked up instead.
nodeNameTable [ node . name ] = nodeTypesCount [ node . type ] . nodeNames [ 0 ] ;
return ;
} else {
// Node can be created but increment the
// counter in case multiple ones are
// supposed to be created
nodeTypesCount [ node . type ] . exist += 1 ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
oldName = node . name ;
newName = this . getUniqueNodeName ( {
originalName : node . name ,
additionalUsedNames : newNodeNames ,
type : node . type ,
2019-06-23 03:35:23 -07:00
} ) ;
2022-12-14 01:04:10 -08:00
newNodeNames . push ( newName ) ;
nodeNameTable [ oldName ] = newName ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
createNodes . push ( node ) ;
} ) ;
// Get only the connections of the nodes that get created
const newConnections : IConnections = { } ;
const currentConnections = data . connections ! ;
const createNodeNames = createNodes . map ( ( node ) => node . name ) ;
let sourceNode , type , sourceIndex , connectionIndex , connectionData ;
for ( sourceNode of Object . keys ( currentConnections ) ) {
if ( ! createNodeNames . includes ( sourceNode ) ) {
// Node does not get created so skip output connections
continue ;
}
2021-05-26 06:34:20 -07:00
2022-12-14 01:04:10 -08:00
const connection : INodeConnections = { } ;
for ( type of Object . keys ( currentConnections [ sourceNode ] ) ) {
connection [ type ] = [ ] ;
for (
sourceIndex = 0 ;
sourceIndex < currentConnections [ sourceNode ] [ type ] . length ;
sourceIndex ++
) {
const nodeSourceConnections = [ ] ;
if ( currentConnections [ sourceNode ] [ type ] [ sourceIndex ] ) {
for (
connectionIndex = 0 ;
connectionIndex < currentConnections [ sourceNode ] [ type ] [ sourceIndex ] . length ;
connectionIndex ++
) {
connectionData = currentConnections [ sourceNode ] [ type ] [ sourceIndex ] [ connectionIndex ] ;
if ( ! createNodeNames . includes ( connectionData . node ) ) {
// Node does not get created so skip input connection
continue ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
nodeSourceConnections . push ( connectionData ) ;
// Add connection
2019-06-23 03:35:23 -07:00
}
}
2022-12-14 01:04:10 -08:00
connection [ type ] . push ( nodeSourceConnections ) ;
2019-06-23 03:35:23 -07:00
}
}
2022-12-14 01:04:10 -08:00
newConnections [ sourceNode ] = connection ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Create a workflow with the new nodes and connections that we can use
// the rename method
const tempWorkflow : Workflow = this . getWorkflow ( createNodes , newConnections ) ;
2019-08-09 09:47:33 -07:00
2022-12-14 01:04:10 -08:00
// Rename all the nodes of which the name changed
for ( oldName in nodeNameTable ) {
if ( oldName === nodeNameTable [ oldName ] ) {
// Name did not change so skip
continue ;
}
tempWorkflow . renameNode ( oldName , nodeNameTable [ oldName ] ) ;
}
2019-08-09 09:47:33 -07:00
2022-12-14 01:04:10 -08:00
// Add the nodes with the changed node names, expressions and connections
this . historyStore . startRecordingUndo ( ) ;
await this . addNodes (
Object . values ( tempWorkflow . nodes ) ,
tempWorkflow . connectionsBySourceNode ,
true ,
) ;
2023-01-30 09:20:50 -08:00
2022-12-14 01:04:10 -08:00
this . historyStore . stopRecordingUndo ( ) ;
2020-11-04 04:04:40 -08:00
2022-12-14 01:04:10 -08:00
this . uiStore . stateIsDirty = true ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
return {
nodes : Object . values ( tempWorkflow . nodes ) ,
connections : tempWorkflow . connectionsBySourceNode ,
} ;
} ,
getSelectedNodesToSave ( ) : Promise < IWorkflowData > {
const data : IWorkflowData = {
nodes : [ ] ,
connections : { } ,
} ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Get data of all the selected noes
let nodeData ;
const exportNodeNames : string [ ] = [ ] ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
for ( const node of this . uiStore . getSelectedNodes ) {
try {
nodeData = this . getNodeDataToSave ( node ) ;
exportNodeNames . push ( node . name ) ;
} catch ( e ) {
return Promise . reject ( e ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
data . nodes . push ( nodeData ) ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Get only connections of exported nodes and ignore all other ones
let connectionToKeep ,
connections : INodeConnections ,
type : string ,
connectionIndex : number ,
sourceIndex : number ,
connectionData : IConnection ,
typeConnections : INodeConnections ;
data . nodes . forEach ( ( node ) => {
connections = this . workflowsStore . outgoingConnectionsByNodeName ( node . name ) ;
if ( Object . keys ( connections ) . length === 0 ) {
return ;
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Keep only the connection to node which get also exported
typeConnections = { } ;
for ( type of Object . keys ( connections ) ) {
for ( sourceIndex = 0 ; sourceIndex < connections [ type ] . length ; sourceIndex ++ ) {
connectionToKeep = [ ] ;
for (
connectionIndex = 0 ;
connectionIndex < connections [ type ] [ sourceIndex ] . length ;
connectionIndex ++
) {
connectionData = connections [ type ] [ sourceIndex ] [ connectionIndex ] ;
if ( exportNodeNames . indexOf ( connectionData . node ) !== - 1 ) {
connectionToKeep . push ( connectionData ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( connectionToKeep . length ) {
if ( ! typeConnections . hasOwnProperty ( type ) ) {
typeConnections [ type ] = [ ] ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
typeConnections [ type ] [ sourceIndex ] = connectionToKeep ;
2019-06-23 03:35:23 -07:00
}
}
2022-12-14 01:04:10 -08:00
}
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( Object . keys ( typeConnections ) . length ) {
data . connections [ node . name ] = typeConnections ;
}
} ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
return Promise . resolve ( data ) ;
} ,
resetWorkspace ( ) {
this . workflowsStore . resetWorkflow ( ) ;
2023-01-03 02:25:07 -08:00
this . onToggleNodeCreator ( { createNodeActive : false } ) ;
this . nodeCreatorStore . setShowScrim ( false ) ;
2022-12-14 01:04:10 -08:00
// Reset nodes
this . deleteEveryEndpoint ( ) ;
if ( this . executionWaitingForWebhook ) {
// Make sure that if there is a waiting test-webhook that
// it gets removed
this . restApi ( )
. removeTestWebhook ( this . workflowsStore . workflowId )
. catch ( ( ) => {
// Ignore all errors
} ) ;
}
this . workflowsStore . removeAllConnections ( { setStateDirty : false } ) ;
this . workflowsStore . removeAllNodes ( { setStateDirty : false , removePinData : true } ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
// Reset workflow execution data
this . workflowsStore . setWorkflowExecutionData ( null ) ;
this . workflowsStore . resetAllNodesIssues ( ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . workflowsStore . setActive ( false ) ;
this . workflowsStore . setWorkflowId ( PLACEHOLDER _EMPTY _WORKFLOW _ID ) ;
this . workflowsStore . setWorkflowName ( { newName : '' , setStateDirty : false } ) ;
this . workflowsStore . setWorkflowSettings ( { } ) ;
this . workflowsStore . setWorkflowTagIds ( [ ] ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . workflowsStore . activeExecutionId = null ;
this . workflowsStore . executingNode = null ;
this . workflowsStore . executionWaitingForWebhook = false ;
this . uiStore . removeActiveAction ( 'workflowRunning' ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . uiStore . resetSelectedNodes ( ) ;
this . uiStore . nodeViewOffsetPosition = [ 0 , 0 ] ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
this . credentialsUpdated = false ;
return Promise . resolve ( ) ;
} ,
async loadActiveWorkflows ( ) : Promise < void > {
const activeWorkflows = await this . restApi ( ) . getActiveWorkflows ( ) ;
this . workflowsStore . activeWorkflows = activeWorkflows ;
} ,
async loadNodeTypes ( ) : Promise < void > {
await this . nodeTypesStore . getNodeTypes ( ) ;
} ,
async loadCredentialTypes ( ) : Promise < void > {
await this . credentialsStore . fetchCredentialTypes ( true ) ;
} ,
async loadCredentials ( ) : Promise < void > {
await this . credentialsStore . fetchAllCredentials ( ) ;
} ,
async loadNodesProperties ( nodeInfos : INodeTypeNameVersion [ ] ) : Promise < void > {
const allNodes : INodeTypeDescription [ ] = this . nodeTypesStore . allNodeTypes ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
const nodesToBeFetched : INodeTypeNameVersion [ ] = [ ] ;
allNodes . forEach ( ( node ) => {
const nodeVersions = Array . isArray ( node . version ) ? node . version : [ node . version ] ;
if (
! ! nodeInfos . find ( ( n ) => n . name === node . name && nodeVersions . includes ( n . version ) ) &&
! node . hasOwnProperty ( 'properties' )
) {
nodesToBeFetched . push ( {
name : node . name ,
version : Array . isArray ( node . version ) ? node . version . slice ( - 1 ) [ 0 ] : node . version ,
} ) ;
}
} ) ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
if ( nodesToBeFetched . length > 0 ) {
// Only call API if node information is actually missing
this . startLoading ( ) ;
await this . nodeTypesStore . getNodesInformation ( nodesToBeFetched ) ;
this . stopLoading ( ) ;
}
} ,
async onPostMessageReceived ( message : MessageEvent ) {
try {
const json = JSON . parse ( message . data ) ;
if ( json && json . command === 'openWorkflow' ) {
try {
await this . importWorkflowExact ( json ) ;
this . isExecutionPreview = false ;
} catch ( e ) {
if ( window . top ) {
window . top . postMessage (
JSON . stringify ( {
command : 'error' ,
message : this . $locale . baseText ( 'openWorkflow.workflowImportError' ) ,
} ) ,
'*' ,
) ;
}
this . $showMessage ( {
title : this . $locale . baseText ( 'openWorkflow.workflowImportError' ) ,
message : ( e as Error ) . message ,
type : 'error' ,
2021-09-21 10:38:24 -07:00
} ) ;
}
2022-12-14 01:04:10 -08:00
} else if ( json && json . command === 'openExecution' ) {
try {
// If this NodeView is used in preview mode (in iframe) it will not have access to the main app store
// so everything it needs has to be sent using post messages and passed down to child components
this . isProductionExecutionPreview = json . executionMode !== 'manual' ;
2021-09-21 10:38:24 -07:00
2022-12-14 01:04:10 -08:00
await this . openExecution ( json . executionId ) ;
this . isExecutionPreview = true ;
} catch ( e ) {
if ( window . top ) {
window . top . postMessage (
JSON . stringify ( {
command : 'error' ,
message : this . $locale . baseText ( 'nodeView.showError.openExecution.title' ) ,
} ) ,
'*' ,
) ;
2022-10-26 01:02:56 -07:00
}
2022-12-14 01:04:10 -08:00
this . $showMessage ( {
title : this . $locale . baseText ( 'nodeView.showError.openExecution.title' ) ,
message : ( e as Error ) . message ,
type : 'error' ,
2022-07-20 08:50:39 -07:00
} ) ;
2022-08-03 04:06:53 -07:00
}
2022-12-14 01:04:10 -08:00
}
} catch ( e ) { }
} ,
async onImportWorkflowDataEvent ( data : IDataObject ) {
2023-01-30 09:20:50 -08:00
await this . importWorkflowData ( data . data as IWorkflowDataUpdate , 'file' ) ;
2022-12-14 01:04:10 -08:00
} ,
async onImportWorkflowUrlEvent ( data : IDataObject ) {
const workflowData = await this . getWorkflowDataFromUrl ( data . url as string ) ;
if ( workflowData !== undefined ) {
2023-01-30 09:20:50 -08:00
await this . importWorkflowData ( workflowData , 'url' ) ;
2022-12-14 01:04:10 -08:00
}
} ,
addPinDataConnections ( pinData : IPinData ) {
Object . keys ( pinData ) . forEach ( ( nodeName ) => {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( ! node ) {
return ;
}
2022-08-03 04:06:53 -07:00
2022-12-14 01:04:10 -08:00
// @ts-ignore
2023-01-30 09:20:50 -08:00
const connections = this . instance ? . getConnections ( {
2022-12-14 01:04:10 -08:00
source : node . id ,
} ) as Connection [ ] ;
2022-07-20 08:50:39 -07:00
2022-12-14 01:04:10 -08:00
connections . forEach ( ( connection ) => {
NodeViewUtils . addConnectionOutputSuccess ( connection , {
total : pinData [ nodeName ] . length ,
iterations : 0 ,
feat(editor): Node creator actions (#4696)
* WIP: Node Actions List UI
* WIP: Recommended Actions and preseting of fields
* WIP: Resource category
* :art: Moved actions categorisation to the server
* :label: Add missing INodeAction type
* :sparkles: Improve SSR categorisation, fix adding of mixed actions
* :recycle: Refactor CategorizedItems to composition api, style fixes
* WIP: Adding multiple nodes
* :recycle: Refactor rest of the NodeCreator component to composition API, conver globalLinkActions to composable
* :sparkles: Allow actions dragging, fix search and refactor passing of actions to categorized items
* :lipstick: Fix node actions title
* Migrate to the pinia store, add posthog feature and various fixes
* :bug: Fix filtering of trigger actions when not merged
* fix: N8N-5439 — Do not use simple node item when at NodeHelperPanel root
* :bug: Design review fixes
* :bug: Fix disabling of merged actions
* Fix trigger root filtering
* :sparkles: Allow for custom node actions parser, introduce hubspot parser
* :bug: Fix initial node params validation, fix position of second added node
* :bug: Introduce operations category, removed canvas node names overrride, fix API actions display and prevent dragging of action nodes
* :sparkles: Prevent NDV auto-open feature flag
* :bug: Inject recommened action for trigger nodes without actions
* Refactored NodeCreatorNode to Storybook, change filtering of merged nodes for the trigger helper panel, minor fixes
* Improve rendering of app nodes and animation
* Cleanup, any only enable accordion transition on triggerhelperpanel
* Hide node creator scrollbars in Firefox
* Minor styles fixes
* Do not copy the array in rendering method
* Removed unused props
* Fix memory leak
* Fix categorisation of regular nodes with a single resource
* Implement telemetry calls for node actions
* Move categorization to FE
* Fix client side actions categorisation
* Skip custom action show
* Only load tooltip for NodeIcon if necessary
* Fix lodash startCase import
* Remove lodash.startcase
* Cleanup
* Fix node creator autofocus on "tab"
* Prevent posthog getFeatureFlag from crashing
* Debugging preview env search issues
* Remove logs
* Make sure the pre-filled params are update not overwritten
* Get rid of transition in itemiterator
* WIP: Rough version of NodeActions keyboard navigation, replace nodeCreator composable with Pinia store module
* Rewrite to add support for ActionItem to ItemIterator and make CategorizedItems accept items props
* Fix category item counter & cleanup
* Add APIHint to actions search no-result, clean up NodeCreatorNode
* Improve node actions no results message
* Remove logging, fix filtering of recommended placeholder category
* Remove unused NodeActions component and node merging feature falg
* Do not show regular nodes without actions
* Make sure to add manual trigger when adding http node via actions hint
* Fixed api hint footer line height
* Prevent pointer-events od NodeIcon img and remove "this" from template
* Address PR points
* Fix e2e specs
* Make sure canvas ia loaded
* Make sure canvas ia loaded before opening nodeCreator in e2e spec
* Fix flaky workflows tags e2e getter
* Imrpove node creator click outside UX, add manual node to regular nodes added from trigger panel
* Add manual trigger node if dragging regular from trigger panel
2022-12-09 01:56:36 -08:00
} ) ;
} ) ;
2022-12-14 01:04:10 -08:00
} ) ;
} ,
removePinDataConnections ( pinData : IPinData ) {
Object . keys ( pinData ) . forEach ( ( nodeName ) => {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( ! node ) {
2022-12-09 06:07:37 -08:00
return ;
}
2022-12-14 01:04:10 -08:00
// @ts-ignore
2023-01-30 09:20:50 -08:00
const connections = this . instance ? . getConnections ( {
2022-12-14 01:04:10 -08:00
source : node . id ,
} ) as Connection [ ] ;
2023-01-30 09:20:50 -08:00
this . instance . setSuspendDrawing ( true ) ;
2022-12-14 01:04:10 -08:00
connections . forEach ( NodeViewUtils . resetConnection ) ;
2023-01-30 09:20:50 -08:00
this . instance . setSuspendDrawing ( false , true ) ;
2022-12-14 01:04:10 -08:00
} ) ;
} ,
onToggleNodeCreator ( {
source ,
createNodeActive ,
} : {
source ? : string ;
createNodeActive : boolean ;
} ) {
if ( createNodeActive === this . createNodeActive ) return ;
// Default to the trigger tab in node creator if there's no trigger node yet
2023-02-17 06:08:26 -08:00
this . nodeCreatorStore . setSelectedView (
this . containsTrigger ? REGULAR _NODE _FILTER : TRIGGER _NODE _FILTER ,
) ;
2022-12-14 01:04:10 -08:00
this . createNodeActive = createNodeActive ;
const mode =
2023-02-17 06:08:26 -08:00
this . nodeCreatorStore . selectedView === TRIGGER _NODE _FILTER ? 'trigger' : 'regular' ;
2022-12-14 01:04:10 -08:00
this . $externalHooks ( ) . run ( 'nodeView.createNodeActiveChanged' , {
source ,
mode ,
createNodeActive ,
} ) ;
this . $telemetry . trackNodesPanel ( 'nodeView.createNodeActiveChanged' , {
source ,
mode ,
createNodeActive ,
workflow _id : this . workflowsStore . workflowId ,
} ) ;
} ,
onAddNode (
nodeTypes : Array < { nodeTypeName : string ; position : XYPosition } > ,
dragAndDrop : boolean ,
) {
nodeTypes . forEach ( ( { nodeTypeName , position } , index ) => {
2023-02-17 06:08:26 -08:00
const isManualTrigger = nodeTypeName === MANUAL _TRIGGER _NODE _TYPE ;
const openNDV = ! isManualTrigger && ( nodeTypes . length === 1 || index > 0 ) ;
2022-12-14 01:04:10 -08:00
this . addNode (
nodeTypeName ,
{ position , dragAndDrop } ,
2023-02-17 06:08:26 -08:00
openNDV ,
2022-12-14 01:04:10 -08:00
true ,
2023-02-17 06:08:26 -08:00
nodeTypes . length > 1 && index < 1 ,
2022-12-14 01:04:10 -08:00
) ;
if ( index === 0 ) return ;
// If there's more than one node, we want to connect them
// this has to be done in mutation subscriber to make sure both nodes already
// exist
const actionWatcher = this . workflowsStore . $onAction ( ( { name , after , args } ) => {
if ( name === 'addNode' && args [ 0 ] . type === nodeTypeName ) {
after ( ( ) => {
const lastAddedNode = this . nodes [ this . nodes . length - 1 ] ;
const previouslyAddedNode = this . nodes [ this . nodes . length - 2 ] ;
this . $nextTick ( ( ) =>
this . connectTwoNodes ( previouslyAddedNode . name , 0 , lastAddedNode . name , 0 ) ,
) ;
2023-02-17 06:08:26 -08:00
// Position the added node to the right side of the previously added one
2022-12-14 01:04:10 -08:00
lastAddedNode . position = [
previouslyAddedNode . position [ 0 ] + NodeViewUtils . NODE _SIZE * 2 ,
previouslyAddedNode . position [ 1 ] ,
] ;
actionWatcher ( ) ;
} ) ;
}
} ) ;
} ) ;
} ,
async saveCurrentWorkflowExternal ( callback : ( ) => void ) {
await this . saveCurrentWorkflow ( ) ;
callback ? . ( ) ;
} ,
setSuspendRecordingDetachedConnections ( suspend : boolean ) {
this . suspendRecordingDetachedConnections = suspend ;
} ,
onMoveNode ( { nodeName , position } : { nodeName : string ; position : XYPosition } ) : void {
this . workflowsStore . updateNodeProperties ( { name : nodeName , properties : { position } } ) ;
2023-01-30 09:20:50 -08:00
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
2022-12-14 01:04:10 -08:00
setTimeout ( ( ) => {
2022-12-09 06:07:37 -08:00
if ( node ) {
2023-01-30 09:20:50 -08:00
this . instance ? . repaintEverything ( ) ;
2022-12-14 01:04:10 -08:00
this . onNodeMoved ( node ) ;
2022-12-09 06:07:37 -08:00
}
2022-12-14 01:04:10 -08:00
} , 0 ) ;
:sparkles: Add Templates (#2720)
* Templates Bugs / Fixed Various Bugs / Multiply Api Request, Carousel Gradient, Core Nodes Filters ...
* Updated MainSidebar Paddings
* N8N-Templates Bugfixing - Remove Unnecesairy Icon (Shape), Refatctor infiniteScrollEnabled Prop + updated infiniterScroll functinality
* N8N-2853 Fixed Carousel Arrows Bug after Cleaning the SearchBar
* fix telemetry init
* fix search tracking issues
* N8N-2853 Created FilterTemplateNode Constant Array, Filter PlayButton and WebhookRespond from Nodes, Added Box for showing more nodes inside TemplateList, Updated NewWorkflowButton to primary, Fixed Markdown issue with Code
* N8N-2853 Removed Placeholder if Workflows Or Collections are not found, Updated the Logic
* fix telemetry events
* clean up session id
* update user inserted event
* N8N-2853 Fixed Categories to Moving if the names are long
* Add todos
* Update Routes on loading
* fix spacing
* Update Border Color
* Update Border Readius
* fix filter fn
* fix constant, console error
* N8N-2853 PR Fixes, Refactoring, Removing unnecesairy code ..
* N8N-2853 PR Fixes - Editor-ui Fixes, Refactoring, Removing Dead Code ...
* N8N-2853 Refactor Card to LongCard
* clean up spacing, replace css var
* clean up spacing
* set categories as optional in node
* replace vars
* refactor store
* remove unnesssary import
* fix error
* fix templates view to start
* add to cache
* fix coll view data
* fix categories
* fix category event
* fix collections carousel
* fix initial load and search
* fix infinite load
* fix query param
* fix scrolling issues
* fix scroll to top
* fix search
* fix collections search
* fix navigation bug
* rename view
* update package lock
* rename workflow view
* rename coll view
* update routes
* add wrapper component
* set session id
* fix search tracking
* fix session tracking
* remove deleted mutation
* remove check for unsupported nodes
* refactor filters
* lazy load template
* clean up types
* refactor infinte scroll
* fix end of search
* Fix spacing
* fix coll loading
* fix types
* fix coll view list
* fix navigation
* rename types
* rename state
* fix search responsiveness
* fix coll view spacing
* fix search view spacing
* clean up views
* set background color
* center page not vert
* fix workflow view
* remove import
* fix background color
* fix background
* clean props
* clean up imports
* refactor button
* update background color
* fix spacing issue
* rename event
* update telemetry event
* update endpoints, add loading view, check for endpoint health
* remove conolse log
* N8N-2853 Fixed Menu Items Padding
* replace endpoints
* fix type issues
* fix categories
* N8N-2853 Fixed ParameterInput Placeholder after ElementUI Upgrade
* update createdAt
* :zap: Fix placeholder in creds config modal
* :pencil2: Adjust docstring to `credText` placeholder version
* N8N-2853 Optimized
* N8N-2853 Optimized code
* :zap: Add deployment type to FE settings
* :zap: Add deployment type to interfaces
* N8N-2853 Removed Animated prop from components
* :zap: Add deployment type to store module
* :sparkles: Create hiring banner
* :zap: Display hiring banner
* :rewind: Undo unrelated change
* N8N-2853 Refactor TemplateFilters
* :zap: Fix indentation
* N8N-2853 Reorder items / TemplateList
* :shirt: Fix lint
* N8N-2853 Refactor TemplateFilters Component
* N8N-2853 Reorder TemplateList
* refactor template card
* update timeout
* fix removelistener
* fix spacing
* split enabled from offline
* add spacing to go back
* N8N-2853 Fixed Screens for Tablet & Mobile
* N8N-2853 Update Stores Order
* remove image componet
* remove placeholder changes
* N8N-2853 Fixed Chinnese Placeholders for El Select Component that comes from the Library Upgrade
* N8N-2853 Fixed Vue Agile Console Warnings
* N8N-2853 Update Collection Route
* :pencil2: Update jobs URL
* :truck: Move logging to root component
* :zap: Refactor `deploymentType` to `isInternalUser`
* :zap: Improve syntax
* fix cut bug in readonly view
* N8N-3012 Fixed Details section in templates with lots of description, Fixed Mardown Block with overflox-x
* N8N-3012 Increased Font-size, Spacing and Line-height of the Categories Items
* N8N-3012 Fixed Vue-agile client width error on resize
* only delay redirect for root path
* N8N-3012 Fixed Carousel Arrows that Disappear
* N8N-3012 Make Loading Screen same color as Templates
* N8N-3012 Markdown renders inline block as block code
* add offline warning
* hide log from workflow iframe
* update text
* make search button larger
* N8N-3012 Categories / Tags extended all the way in details section
* load data in cred modals
* remove deleted message
* add external hook
* remove import
* update env variable description
* fix markdown width issue
* disable telemetry for demo, add session id to template pages
* fix telemetery bugs
* N8N-3012 Not found Collections/Wokrkflow
* N8N-3012 Checkboxes change order when categories are changed
* N8N-3012 Refactor SortedCategories inside TemplateFilters component
* fix firefox bug
* add telemetry requirements
* add error check
* N8N-3012 Update GoBackButton to check if Route History is present
* N8N-3012 Fixed WF Nodes Icons
* hide workflow screenshots
* remove unnessary mixins
* rename prop
* fix design a bit
* rename data
* clear workspace on destroy
* fix copy paste bug
* fix disabled state
* N8N-3012 Fixed Saving/Leave without saving Modal
* fix telemetry issue
* fix telemetry issues, error bug
* fix error notification
* disable workflow menu items on templates
* fix i18n elementui issue
* Remove Emit - NodeType from HoverableNodeIcon component
* TechnicalFixes: NavigateTo passed down as function should be helper
* TechnicalFixes: Update NavigateTo function
* TechnicalFixes: Add FilterCoreNodes directly as function
* check for empty connecitions
* fix titles
* respect new lines
* increase categories to be sliced
* rename prop
* onUseWorkflow
* refactor click event
* fix bug, refactor
* fix loading story
* add default
* fix styles at right level of abstraction
* add wrapper with width
* remove loading blocks component
* add story
* rename prop
* fix spacing
* refactor tag, add story
* move margin to container
* fix tag redirect, remove unnessary check
* make version optional
* rename view
* move from workflows to templates store
* remove unnessary change
* remove unnessary css
* rename component
* refactor collection card
* add boolean to prevent shrink
* clean up carousel
* fix redirection bug on save
* remove listeners to fix multiple listeners bug
* remove unnessary types
* clean up boolean set
* fix node select bug
* rename component
* remove unnessary class
* fix redirection bug
* remove unnessary error
* fix typo
* fix blockquotes, pre
* refactor markdown rendering
* remove console log
* escape markdown
* fix safari bug
* load active workflows to fix modal bug
* :arrow_up: Update package-lock.json file
* :zap: Add n8n version as header
Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2022-02-28 01:57:44 -08:00
} ,
2022-12-14 01:04:10 -08:00
onRevertAddNode ( { node } : { node : INodeUi } ) : void {
this . removeNode ( node . name , false ) ;
} ,
async onRevertRemoveNode ( { node } : { node : INodeUi } ) : Promise < void > {
const prevNode = this . workflowsStore . workflow . nodes . find ( ( n ) => n . id === node . id ) ;
if ( prevNode ) {
return ;
}
// For some reason, returning node to canvas with old id
// makes it's endpoint to render at wrong position
node . id = uuid ( ) ;
await this . addNodes ( [ node ] ) ;
} ,
onRevertAddConnection ( { connection } : { connection : [ IConnection , IConnection ] } ) {
this . suspendRecordingDetachedConnections = true ;
this . _ _removeConnection ( connection , true ) ;
this . suspendRecordingDetachedConnections = false ;
} ,
async onRevertRemoveConnection ( { connection } : { connection : [ IConnection , IConnection ] } ) {
this . suspendRecordingDetachedConnections = true ;
2023-02-09 07:04:26 -08:00
this . _ _addConnection ( connection ) ;
2022-12-14 01:04:10 -08:00
this . suspendRecordingDetachedConnections = false ;
} ,
async onRevertNameChange ( { currentName , newName } : { currentName : string ; newName : string } ) {
await this . renameNode ( newName , currentName ) ;
} ,
onRevertEnableToggle ( { nodeName , isDisabled } : { nodeName : string ; isDisabled : boolean } ) {
const node = this . workflowsStore . getNodeByName ( nodeName ) ;
if ( node ) {
this . disableNodes ( [ node ] ) ;
2022-09-29 06:06:40 -07:00
}
2022-12-14 01:04:10 -08:00
} ,
} ,
async mounted ( ) {
2023-01-30 09:20:50 -08:00
this . resetWorkspace ( ) ;
this . canvasStore . initInstance ( this . $refs . nodeView as HTMLElement ) ;
2022-12-14 01:04:10 -08:00
this . $titleReset ( ) ;
window . addEventListener ( 'message' , this . onPostMessageReceived ) ;
this . startLoading ( ) ;
const loadPromises = [
this . loadActiveWorkflows ( ) ,
this . loadCredentials ( ) ,
this . loadCredentialTypes ( ) ,
] ;
if ( this . nodeTypesStore . allNodeTypes . length === 0 ) {
loadPromises . push ( this . loadNodeTypes ( ) ) ;
}
2022-09-29 06:06:40 -07:00
2022-12-14 01:04:10 -08:00
try {
await Promise . all ( loadPromises ) ;
} catch ( error ) {
this . $showError (
error ,
this . $locale . baseText ( 'nodeView.showError.mounted1.title' ) ,
this . $locale . baseText ( 'nodeView.showError.mounted1.message' ) + ':' ,
) ;
return ;
}
2023-01-30 09:20:50 -08:00
ready ( async ( ) => {
2019-06-23 03:35:23 -07:00
try {
2022-12-14 01:04:10 -08:00
try {
this . initNodeView ( ) ;
} catch { } // This will break if mounted after jsplumb has been initiated from executions preview, so continue if it breaks
await this . initView ( ) ;
if ( window . top ) {
window . top . postMessage (
JSON . stringify ( { command : 'n8nReady' , version : this . rootStore . versionCli } ) ,
'*' ,
) ;
}
2019-06-23 03:35:23 -07:00
} catch ( error ) {
2021-11-10 10:41:40 -08:00
this . $showError (
error ,
2022-12-14 01:04:10 -08:00
this . $locale . baseText ( 'nodeView.showError.mounted2.title' ) ,
this . $locale . baseText ( 'nodeView.showError.mounted2.message' ) + ':' ,
2021-11-10 10:41:40 -08:00
) ;
2022-07-27 07:28:13 -07:00
}
2022-12-14 01:04:10 -08:00
this . stopLoading ( ) ;
setTimeout ( ( ) => {
this . usersStore . showPersonalizationSurvey ( ) ;
this . checkForNewVersions ( ) ;
this . addPinDataConnections ( this . workflowsStore . getPinData || ( { } as IPinData ) ) ;
} , 0 ) ;
} ) ;
// TODO: This currently breaks since front-end hooks are still not updated to work with pinia store
this . $externalHooks ( )
. run ( 'nodeView.mount' )
. catch ( ( e ) => { } ) ;
if (
this . currentUser ? . personalizationAnswers !== null &&
this . settingsStore . onboardingCallPromptEnabled &&
this . currentUser &&
getAccountAge ( this . currentUser ) <= ONBOARDING _PROMPT _TIMEBOX
) {
const onboardingResponse = await this . uiStore . getNextOnboardingPrompt ( ) ;
const promptTimeout =
onboardingResponse . toast _sequence _number === 1 ? FIRST _ONBOARDING _PROMPT _TIMEOUT : 1000 ;
if ( onboardingResponse . title && onboardingResponse . description ) {
setTimeout ( async ( ) => {
this . $showToast ( {
type : 'info' ,
title : onboardingResponse . title ,
message : onboardingResponse . description ,
duration : 0 ,
customClass : 'clickable' ,
closeOnClick : true ,
onClick : ( ) => {
this . $telemetry . track ( 'user clicked onboarding toast' , {
seq _num : onboardingResponse . toast _sequence _number ,
title : onboardingResponse . title ,
description : onboardingResponse . description ,
} ) ;
this . uiStore . openModal ( ONBOARDING _CALL _SIGNUP _MODAL _KEY ) ;
} ,
} ) ;
} , promptTimeout ) ;
2022-10-26 01:02:56 -07:00
}
2022-12-14 01:04:10 -08:00
}
} ,
activated ( ) {
const openSideMenu = this . uiStore . addFirstStepOnLoad ;
if ( openSideMenu ) {
this . showTriggerCreator ( 'trigger_placeholder_button' ) ;
}
this . uiStore . addFirstStepOnLoad = false ;
2023-01-30 09:20:50 -08:00
this . initNodeView ( ) ;
2022-12-14 01:04:10 -08:00
document . addEventListener ( 'keydown' , this . keyDown ) ;
document . addEventListener ( 'keyup' , this . keyUp ) ;
window . addEventListener ( 'message' , this . onPostMessageReceived ) ;
this . $root . $on ( 'newWorkflow' , this . newWorkflow ) ;
this . $root . $on ( 'importWorkflowData' , this . onImportWorkflowDataEvent ) ;
this . $root . $on ( 'importWorkflowUrl' , this . onImportWorkflowUrlEvent ) ;
2023-01-30 09:20:50 -08:00
historyBus . $on ( 'nodeMove' , this . onMoveNode ) ;
historyBus . $on ( 'revertAddNode' , this . onRevertAddNode ) ;
historyBus . $on ( 'revertRemoveNode' , this . onRevertRemoveNode ) ;
historyBus . $on ( 'revertAddConnection' , this . onRevertAddConnection ) ;
historyBus . $on ( 'revertRemoveConnection' , this . onRevertRemoveConnection ) ;
historyBus . $on ( 'revertRenameNode' , this . onRevertNameChange ) ;
historyBus . $on ( 'enableNodeToggle' , this . onRevertEnableToggle ) ;
2022-12-14 01:04:10 -08:00
dataPinningEventBus . $on ( 'pin-data' , this . addPinDataConnections ) ;
dataPinningEventBus . $on ( 'unpin-data' , this . removePinDataConnections ) ;
nodeViewEventBus . $on ( 'saveWorkflow' , this . saveCurrentWorkflowExternal ) ;
this . canvasStore . isDemo = this . isDemo ;
} ,
deactivated ( ) {
document . removeEventListener ( 'keydown' , this . keyDown ) ;
document . removeEventListener ( 'keyup' , this . keyUp ) ;
window . removeEventListener ( 'message' , this . onPostMessageReceived ) ;
this . $root . $off ( 'newWorkflow' , this . newWorkflow ) ;
this . $root . $off ( 'importWorkflowData' , this . onImportWorkflowDataEvent ) ;
this . $root . $off ( 'importWorkflowUrl' , this . onImportWorkflowUrlEvent ) ;
2023-01-30 09:20:50 -08:00
historyBus . $off ( 'nodeMove' , this . onMoveNode ) ;
historyBus . $off ( 'revertAddNode' , this . onRevertAddNode ) ;
historyBus . $off ( 'revertRemoveNode' , this . onRevertRemoveNode ) ;
historyBus . $off ( 'revertAddConnection' , this . onRevertAddConnection ) ;
historyBus . $off ( 'revertRemoveConnection' , this . onRevertRemoveConnection ) ;
historyBus . $off ( 'revertRenameNode' , this . onRevertNameChange ) ;
historyBus . $off ( 'enableNodeToggle' , this . onRevertEnableToggle ) ;
2022-12-14 01:04:10 -08:00
dataPinningEventBus . $off ( 'pin-data' , this . addPinDataConnections ) ;
dataPinningEventBus . $off ( 'unpin-data' , this . removePinDataConnections ) ;
nodeViewEventBus . $off ( 'saveWorkflow' , this . saveCurrentWorkflowExternal ) ;
2023-01-30 09:20:50 -08:00
this . instance . unbind ( ) ;
2022-12-14 01:04:10 -08:00
} ,
destroyed ( ) {
this . resetWorkspace ( ) ;
2023-01-30 09:20:50 -08:00
this . instance . unbind ( ) ;
this . instance . destroy ( ) ;
2022-12-14 01:04:10 -08:00
this . uiStore . stateIsDirty = false ;
window . removeEventListener ( 'message' , this . onPostMessageReceived ) ;
this . $root . $off ( 'newWorkflow' , this . newWorkflow ) ;
this . $root . $off ( 'importWorkflowData' , this . onImportWorkflowDataEvent ) ;
this . $root . $off ( 'importWorkflowUrl' , this . onImportWorkflowUrlEvent ) ;
this . workflowsStore . setWorkflowId ( PLACEHOLDER _EMPTY _WORKFLOW _ID ) ;
} ,
} ) ;
2019-06-23 03:35:23 -07:00
< / script >
< style scoped lang = "scss" >
. node - view - root {
2022-10-26 01:02:56 -07:00
position : relative ;
flex : 1 ;
2019-06-23 03:35:23 -07:00
overflow : hidden ;
feat: Add User Management (#2636)
* ✅ adjust tests
* 🛠 refactor user invites to be indempotent (#2791)
* 🔐 Encrypt SMTP pass for user management backend (#2793)
* :package: Add crypto-js to /cli
* :package: Update package-lock.json
* :sparkles: Create type for SMTP config
* :zap: Encrypt SMTP pass
* :zap: Update format for `userManagement.emails.mode`
* :zap: Update format for `binaryDataManager.mode`
* :zap: Update format for `logs.level`
* :fire: Remove logging
* :shirt: Fix lint
* 👰 n8n 2826 um wedding FE<>BE (#2789)
* remove mocks
* update authorization func
* lock down default role
* 🐛 fix requiring authentication for OPTIONS requests
* :bug: fix cors and cookie issues in dev
* update setup route
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
* update telemetry
* 🐛 preload role for users
* :bug: remove auth for password reset routes
* 🐛 fix forgot-password flow
* :zap: allow workflow tag disabling
* update telemetry init
* add reset
* clear error notifications on signin
* remove load settings from node view
* remove user id from user state
* inherit existing user props
* go back in history on button click
* use replace to force redirect
* update stories
* :zap: add env check for tag create
* :test_tube: Add `/users` tests for user management backend (#2790)
* :zap: Refactor users namespace
* :zap: Adjust fillout endpoint
* :zap: Refactor initTestServer arg
* :pencil2: Specify agent type
* :pencil2: Specify role type
* :zap: Tighten `/users/:id` check
* :sparkles: Add initial tests
* :truck: Reposition init server map
* :zap: Set constants in `validatePassword()`
* :zap: Tighten `/users/:id` check
* :zap: Improve checks in `/users/:id`
* :sparkles: Add tests for `/users/:id`
* :package: Update package-lock.json
* :zap: Simplify expectation
* :zap: Reuse util for authless agent
* :truck: Make role names consistent
* :blue_book: Tighten namespaces map type
* :fire: Remove unneeded default arg
* :sparkles: Add tests for `POST /users`
* :blue_book: Create test SMTP account type
* :pencil2: Improve wording
* :art: Formatting
* :fire: Remove temp fix
* :zap: Replace helper with config call
* :zap: Fix failing tests
* :fire: Remove outdated test
* :fire: Remove unused helper
* :zap: Increase readability of domain fetcher
* :zap: Refactor payload validation
* :fire: Remove repetition
* :rewind: Restore logging
* :zap: Initialize logger in tests
* :fire: Remove redundancy from check
* :truck: Move `globalOwnerRole` fetching to global scope
* :fire: Remove unused imports
* :truck: Move random utils to own module
* :truck: Move test types to own module
* :pencil2: Add dividers to utils
* :pencil2: Reorder `initTestServer` param docstring
* :pencil2: Add TODO comment
* :zap: Dry up member creation
* :zap: Tighten search criteria
* :test_tube: Add expectation to `GET /users`
* :zap: Create role fetcher utils
* :zap: Create one more role fetch util
* :fire: Remove unneeded DB query
* :test_tube: Add expectation to `POST /users`
* :test_tube: Add expectation to `DELETE /users/:id`
* :test_tube: Add another expectation to `DELETE /users/:id`
* :test_tube: Add expectations to `DELETE /users/:id`
* :test_tube: Adjust expectations in `POST /users/:id`
* :test_tube: Add expectations to `DELETE /users/:id`
* :shirt: Fix build
* :zap: Update method
* :blue_book: Fix `userToDelete` type
* :zap: Refactor `createAgent()`
* :zap: Make role fetching global
* :zap: Optimize roles fetching
* :zap: Centralize member creation
* :zap: Refactor truncation helper
* :test_tube: Add teardown to `DELETE /users/:id`
* :test_tube: Add DB expectations to users tests
* :fire: Remove pass validation due to hash
* :pencil2: Improve pass validation error message
* :zap: Improve owner pass validation
* :zap: Create logger initialization helper
* :zap: Optimize helpers
* :zap: Restructure `getAllRoles` helper
* :test_tube: Add password reset flow tests for user management backend (#2807)
* :zap: Refactor users namespace
* :zap: Adjust fillout endpoint
* :zap: Refactor initTestServer arg
* :pencil2: Specify agent type
* :pencil2: Specify role type
* :zap: Tighten `/users/:id` check
* :sparkles: Add initial tests
* :truck: Reposition init server map
* :zap: Set constants in `validatePassword()`
* :zap: Tighten `/users/:id` check
* :zap: Improve checks in `/users/:id`
* :sparkles: Add tests for `/users/:id`
* :package: Update package-lock.json
* :zap: Simplify expectation
* :zap: Reuse util for authless agent
* :truck: Make role names consistent
* :blue_book: Tighten namespaces map type
* :fire: Remove unneeded default arg
* :sparkles: Add tests for `POST /users`
* :blue_book: Create test SMTP account type
* :pencil2: Improve wording
* :art: Formatting
* :fire: Remove temp fix
* :zap: Replace helper with config call
* :zap: Fix failing tests
* :fire: Remove outdated test
* :sparkles: Add tests for password reset flow
* :pencil2: Fix test wording
* :zap: Set password reset namespace
* :fire: Remove unused helper
* :zap: Increase readability of domain fetcher
* :zap: Refactor payload validation
* :fire: Remove repetition
* :rewind: Restore logging
* :zap: Initialize logger in tests
* :fire: Remove redundancy from check
* :truck: Move `globalOwnerRole` fetching to global scope
* :fire: Remove unused imports
* :truck: Move random utils to own module
* :truck: Move test types to own module
* :pencil2: Add dividers to utils
* :pencil2: Reorder `initTestServer` param docstring
* :pencil2: Add TODO comment
* :zap: Dry up member creation
* :zap: Tighten search criteria
* :test_tube: Add expectation to `GET /users`
* :zap: Create role fetcher utils
* :zap: Create one more role fetch util
* :fire: Remove unneeded DB query
* :test_tube: Add expectation to `POST /users`
* :test_tube: Add expectation to `DELETE /users/:id`
* :test_tube: Add another expectation to `DELETE /users/:id`
* :test_tube: Add expectations to `DELETE /users/:id`
* :test_tube: Adjust expectations in `POST /users/:id`
* :test_tube: Add expectations to `DELETE /users/:id`
* :blue_book: Add namespace name to type
* :truck: Adjust imports
* :zap: Optimize `globalOwnerRole` fetching
* :test_tube: Add expectations
* :shirt: Fix build
* :shirt: Fix build
* :zap: Update method
* :zap: Update method
* :test_tube: Fix `POST /change-password` test
* :blue_book: Fix `userToDelete` type
* :zap: Refactor `createAgent()`
* :zap: Make role fetching global
* :zap: Optimize roles fetching
* :zap: Centralize member creation
* :zap: Refactor truncation helper
* :test_tube: Add teardown to `DELETE /users/:id`
* :test_tube: Add DB expectations to users tests
* :zap: Refactor as in users namespace
* :test_tube: Add expectation to `POST /change-password`
* :fire: Remove pass validation due to hash
* :pencil2: Improve pass validation error message
* :zap: Improve owner pass validation
* :zap: Create logger initialization helper
* :zap: Optimize helpers
* :zap: Restructure `getAllRoles` helper
* :zap: Update `truncate` calls
* :bug: return 200 for non-existing user
* ✅ fix tests for forgot-password and user creation
* Update packages/editor-ui/src/components/MainSidebar.vue
Co-authored-by: Ahsan Virani <ahsan.virani@gmail.com>
* Update packages/editor-ui/src/components/Telemetry.vue
Co-authored-by: Ahsan Virani <ahsan.virani@gmail.com>
* Update packages/editor-ui/src/plugins/telemetry/index.ts
Co-authored-by: Ahsan Virani <ahsan.virani@gmail.com>
* Update packages/editor-ui/src/plugins/telemetry/index.ts
Co-authored-by: Ahsan Virani <ahsan.virani@gmail.com>
* Update packages/editor-ui/src/plugins/telemetry/index.ts
Co-authored-by: Ahsan Virani <ahsan.virani@gmail.com>
* :truck: Fix imports
* :zap: reset password just if password exists
* Fix validation at `PATCH /workfows/:id` (#2819)
* :bug: Validate entity only if workflow
* :shirt: Fix build
* 🔨 refactor response from user creation
* 🐛 um email invite fix (#2833)
* update users invite
* fix notificaitons stacking on top of each other
* remove unnessary check
* fix type issues
* update structure
* fix types
* 🐘 database migrations UM + password reset expiration (#2710)
* Add table prefix and assign existing workflows and credentials to owner for sqlite
* Added user management migration to MySQL
* Fixed some missing table prefixes and removed unnecessary user id
* Created migration for postgres and applies minor fixes
* Fixed migration for sqlite by removing the unnecessary index and for mysql by removing unnecessary user data
* Added password reset token expiration
* Addressing comments made by Ben
* ⚡️ add missing tablePrefix
* ✅ fix tests + add tests for expiring pw-reset-token
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
* :zap: treat skipped personalizationSurvey as not answered
* :bug: removing active workflows when deleting user, :bug: fix reinvite, :bug: fix resolve-signup-token, 🐘 remove workflowname uniqueness
* ✅ Add DB state check tests (#2841)
* :fire: Remove unneeded import
* :fire: Remove unneeded vars
* :pencil2: Improve naming
* :test_tube: Add expectations to `POST /owner`
* :test_tube: Add expectations to `PATCH /me`
* :test_tube: Add expectation to `PATCH /me/password`
* :pencil2: Clarify when owner is owner shell
* :test_tube: Add more expectations
* :rewind: Restore package-lock to parent branch state
* Add logging to user management endpoints v2 (#2836)
* :zap: Initialize logger in tests
* :zap: Add logs to mailer
* :zap: Add logs to middleware
* :zap: Add logs to me endpoints
* :zap: Add logs to owner endpoints
* :zap: Add logs to pass flow endpoints
* :zap: Add logs to users endpoints
* :blue_book: Improve typings
* :zap: Merge two logs into one
* :zap: Adjust log type
* :zap: Add password reset email log
* :pencil2: Reword log message
* :zap: Adjust log meta object
* :zap: Add total to log
* :pencil2: Add detail to log message
* :pencil2: Reword log message
* :pencil2: Reword log message
* :bug: Make total users to set up accurate
* :pencil2: Reword `Logger.debug()` messages
* :pencil2: Phrasing change for consistency
* :bug: Fix ID overridden in range query
* :hammer: small refactoring
* 🔐 add auth to push-connection
* 🛠 ✅ Create credentials namespace and add tests (#2831)
* :test_tube: Fix failing test
* :blue_book: Improve `createAgent` signature
* :truck: Fix `LoggerProxy` import
* :sparkles: Create credentials endpoints namespace
* :test_tube: Set up initial tests
* :zap: Add validation to model
* :zap: Adjust validation
* :test_tube: Add test
* :truck: Sort creds endpoints
* :pencil2: Plan out pending tests
* :test_tube: Add deletion tests
* :test_tube: Add patch tests
* :test_tube: Add get cred tests
* :truck: Hoist import
* :pencil2: Make test descriptions consistent
* :pencil2: Adjust description
* :test_tube: Add missing test
* :pencil2: Make get descriptions consistent
* :rewind: Undo line break
* :zap: Refactor to simplify `saveCredential`
* :test_tube: Add non-owned tests for owner
* :pencil2: Improve naming
* :pencil2: Add clarifying comments
* :truck: Improve imports
* :zap: Initialize config file
* :fire: Remove unneeded import
* :truck: Rename dir
* :zap: Adjust deletion call
* :zap: Adjust error code
* :pencil2: Touch up comment
* :zap: Optimize fetching with `@RelationId`
* :test_tube: Add expectations
* :zap: Simplify mock calls
* :blue_book: Set deep readonly to object constants
* :fire: Remove unused param and encryption key
* :zap: Add more `@RelationId` calls in models
* :rewind: Restore
* :bug: no auth for .svg
* 🛠 move auth cookie name to constant; 🐛 fix auth for push-connection
* ✅ Add auth middleware tests (#2853)
* :zap: Simplify existing suite
* :test_tube: Validate that auth cookie exists
* :pencil2: Move comment
* :fire: Remove unneeded imports
* :pencil2: Add clarifying comments
* :pencil2: Document auth endpoints
* :test_tube: Add middleware tests
* :pencil2: Fix typos
Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
* 🔥 Remove test description wrappers (#2874)
* :fire: Remove /owner test wrappers
* :fire: Remove auth middleware test wrappers
* :fire: Remove auth endpoints test wrappers
* :fire: Remove overlooked middleware wrappers
* :fire: Remove me namespace test wrappers
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
* ✨ Runtime checks for credentials load and execute workflows (#2697)
* Runtime checks for credentials load and execute workflows
* Fixed from reviewers
* Changed runtime validation for credentials to be on start instead of on demand
* Refactored validations to use user id instead of whole User instance
* Removed user entity from workflow project because it is no longer needed
* General fixes and improvements to runtime checks
* Remove query builder and improve styling
* Fix lint issues
* :zap: remove personalizationAnswers when fetching all users
* ✅ fix failing get all users test
* ✅ check authorization routes also for authentication
* :bug: fix defaults in reset command
* 🛠 refactorings from walkthrough (#2856)
* :zap: Make `getTemplate` async
* :zap: Remove query builder from `getCredentials`
* :zap: Add save manual executions log message
* :rewind: Restore and hide migrations logs
* :zap: Centralize ignore paths check
* :shirt: Fix build
* :truck: Rename `hasOwner` to `isInstanceOwnerSetUp`
* :zap: Add `isSetUp` flag to `User`
* :zap: Add `isSetUp` to FE interface
* :zap: Adjust `isSetUp` checks on FE
* :shirt: Fix build
* :zap: Adjust `isPendingUser()` check
* :truck: Shorten helper name
* :zap: Refactor as `isPending` per feedback
* :pencil2: Update log message
* :zap: Broaden check
* :fire: Remove unneeded relation
* :zap: Refactor query
* :fire: Re-remove logs from migrations
* 🛠 set up credentials router (#2882)
* :zap: Refactor creds endpoints into router
* :test_tube: Refactor creds tests to use router
* :truck: Rename arg for consistency
* :truck: Move `credentials.api.ts` outside /public
* :truck: Rename constant for consistency
* :blue_book: Simplify types
* :fire: Remove unneeded arg
* :truck: Rename router to controller
* :zap: Shorten endpoint
* :zap: Update `initTestServer()` arg
* :zap: Mutate response body in GET /credentials
* 🏎 improve performance of type cast for FE
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
* :bug: remove GET /login from auth
* 🔀 merge master + FE update (#2905)
* :sparkles: Add Templates (#2720)
* Templates Bugs / Fixed Various Bugs / Multiply Api Request, Carousel Gradient, Core Nodes Filters ...
* Updated MainSidebar Paddings
* N8N-Templates Bugfixing - Remove Unnecesairy Icon (Shape), Refatctor infiniteScrollEnabled Prop + updated infiniterScroll functinality
* N8N-2853 Fixed Carousel Arrows Bug after Cleaning the SearchBar
* fix telemetry init
* fix search tracking issues
* N8N-2853 Created FilterTemplateNode Constant Array, Filter PlayButton and WebhookRespond from Nodes, Added Box for showing more nodes inside TemplateList, Updated NewWorkflowButton to primary, Fixed Markdown issue with Code
* N8N-2853 Removed Placeholder if Workflows Or Collections are not found, Updated the Logic
* fix telemetry events
* clean up session id
* update user inserted event
* N8N-2853 Fixed Categories to Moving if the names are long
* Add todos
* Update Routes on loading
* fix spacing
* Update Border Color
* Update Border Readius
* fix filter fn
* fix constant, console error
* N8N-2853 PR Fixes, Refactoring, Removing unnecesairy code ..
* N8N-2853 PR Fixes - Editor-ui Fixes, Refactoring, Removing Dead Code ...
* N8N-2853 Refactor Card to LongCard
* clean up spacing, replace css var
* clean up spacing
* set categories as optional in node
* replace vars
* refactor store
* remove unnesssary import
* fix error
* fix templates view to start
* add to cache
* fix coll view data
* fix categories
* fix category event
* fix collections carousel
* fix initial load and search
* fix infinite load
* fix query param
* fix scrolling issues
* fix scroll to top
* fix search
* fix collections search
* fix navigation bug
* rename view
* update package lock
* rename workflow view
* rename coll view
* update routes
* add wrapper component
* set session id
* fix search tracking
* fix session tracking
* remove deleted mutation
* remove check for unsupported nodes
* refactor filters
* lazy load template
* clean up types
* refactor infinte scroll
* fix end of search
* Fix spacing
* fix coll loading
* fix types
* fix coll view list
* fix navigation
* rename types
* rename state
* fix search responsiveness
* fix coll view spacing
* fix search view spacing
* clean up views
* set background color
* center page not vert
* fix workflow view
* remove import
* fix background color
* fix background
* clean props
* clean up imports
* refactor button
* update background color
* fix spacing issue
* rename event
* update telemetry event
* update endpoints, add loading view, check for endpoint health
* remove conolse log
* N8N-2853 Fixed Menu Items Padding
* replace endpoints
* fix type issues
* fix categories
* N8N-2853 Fixed ParameterInput Placeholder after ElementUI Upgrade
* update createdAt
* :zap: Fix placeholder in creds config modal
* :pencil2: Adjust docstring to `credText` placeholder version
* N8N-2853 Optimized
* N8N-2853 Optimized code
* :zap: Add deployment type to FE settings
* :zap: Add deployment type to interfaces
* N8N-2853 Removed Animated prop from components
* :zap: Add deployment type to store module
* :sparkles: Create hiring banner
* :zap: Display hiring banner
* :rewind: Undo unrelated change
* N8N-2853 Refactor TemplateFilters
* :zap: Fix indentation
* N8N-2853 Reorder items / TemplateList
* :shirt: Fix lint
* N8N-2853 Refactor TemplateFilters Component
* N8N-2853 Reorder TemplateList
* refactor template card
* update timeout
* fix removelistener
* fix spacing
* split enabled from offline
* add spacing to go back
* N8N-2853 Fixed Screens for Tablet & Mobile
* N8N-2853 Update Stores Order
* remove image componet
* remove placeholder changes
* N8N-2853 Fixed Chinnese Placeholders for El Select Component that comes from the Library Upgrade
* N8N-2853 Fixed Vue Agile Console Warnings
* N8N-2853 Update Collection Route
* :pencil2: Update jobs URL
* :truck: Move logging to root component
* :zap: Refactor `deploymentType` to `isInternalUser`
* :zap: Improve syntax
* fix cut bug in readonly view
* N8N-3012 Fixed Details section in templates with lots of description, Fixed Mardown Block with overflox-x
* N8N-3012 Increased Font-size, Spacing and Line-height of the Categories Items
* N8N-3012 Fixed Vue-agile client width error on resize
* only delay redirect for root path
* N8N-3012 Fixed Carousel Arrows that Disappear
* N8N-3012 Make Loading Screen same color as Templates
* N8N-3012 Markdown renders inline block as block code
* add offline warning
* hide log from workflow iframe
* update text
* make search button larger
* N8N-3012 Categories / Tags extended all the way in details section
* load data in cred modals
* remove deleted message
* add external hook
* remove import
* update env variable description
* fix markdown width issue
* disable telemetry for demo, add session id to template pages
* fix telemetery bugs
* N8N-3012 Not found Collections/Wokrkflow
* N8N-3012 Checkboxes change order when categories are changed
* N8N-3012 Refactor SortedCategories inside TemplateFilters component
* fix firefox bug
* add telemetry requirements
* add error check
* N8N-3012 Update GoBackButton to check if Route History is present
* N8N-3012 Fixed WF Nodes Icons
* hide workflow screenshots
* remove unnessary mixins
* rename prop
* fix design a bit
* rename data
* clear workspace on destroy
* fix copy paste bug
* fix disabled state
* N8N-3012 Fixed Saving/Leave without saving Modal
* fix telemetry issue
* fix telemetry issues, error bug
* fix error notification
* disable workflow menu items on templates
* fix i18n elementui issue
* Remove Emit - NodeType from HoverableNodeIcon component
* TechnicalFixes: NavigateTo passed down as function should be helper
* TechnicalFixes: Update NavigateTo function
* TechnicalFixes: Add FilterCoreNodes directly as function
* check for empty connecitions
* fix titles
* respect new lines
* increase categories to be sliced
* rename prop
* onUseWorkflow
* refactor click event
* fix bug, refactor
* fix loading story
* add default
* fix styles at right level of abstraction
* add wrapper with width
* remove loading blocks component
* add story
* rename prop
* fix spacing
* refactor tag, add story
* move margin to container
* fix tag redirect, remove unnessary check
* make version optional
* rename view
* move from workflows to templates store
* remove unnessary change
* remove unnessary css
* rename component
* refactor collection card
* add boolean to prevent shrink
* clean up carousel
* fix redirection bug on save
* remove listeners to fix multiple listeners bug
* remove unnessary types
* clean up boolean set
* fix node select bug
* rename component
* remove unnessary class
* fix redirection bug
* remove unnessary error
* fix typo
* fix blockquotes, pre
* refactor markdown rendering
* remove console log
* escape markdown
* fix safari bug
* load active workflows to fix modal bug
* :arrow_up: Update package-lock.json file
* :zap: Add n8n version as header
Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
* :bookmark: Release n8n-workflow@0.88.0
* :arrow_up: Set n8n-workflow@0.88.0 on n8n-core
* :bookmark: Release n8n-core@0.106.0
* :arrow_up: Set n8n-core@0.106.0 and n8n-workflow@0.88.0 on n8n-node-dev
* :bookmark: Release n8n-node-dev@0.45.0
* :arrow_up: Set n8n-core@0.106.0 and n8n-workflow@0.88.0 on n8n-nodes-base
* :bookmark: Release n8n-nodes-base@0.163.0
* :bookmark: Release n8n-design-system@0.12.0
* :arrow_up: Set n8n-design-system@0.12.0 and n8n-workflow@0.88.0 on n8n-editor-ui
* :bookmark: Release n8n-editor-ui@0.132.0
* :arrow_up: Set n8n-core@0.106.0, n8n-editor-ui@0.132.0, n8n-nodes-base@0.163.0 and n8n-workflow@0.88.0 on n8n
* :bookmark: Release n8n@0.165.0
* fix default user bug
* fix bug
* update package lock
* fix duplicate import
* fix settings
* fix templates access
Co-authored-by: Oliver Trajceski <olivertrajceski@yahoo.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
* :zap: n8n 2952 personalisation (#2911)
* refactor/update survey
* update customers
* Fix up personalization survey
* fix recommendation logic
* set to false
* hide suggested nodes when empty
* use keys
* add missing logic
* switch types
* Fix logic
* remove unused constants
* add back constant
* refactor filtering inputs
* hide last input on personal
* fix other
* ✨ add current pw check for change password (#2912)
* fix back button
* Add current password input
* add to modal
* update package.json
* delete mock file
* delete mock file
* get settings func
* update router
* update package lock
* update package lock
* Fix invite text
* update error i18n
* open personalization on search if not set
* update error view i18n
* update change password
* update settings sidebar
* remove import
* fix sidebar
* :goal_net: fix error for credential/workflow not found
* update invite modal
* ✨ persist skipping owner setup (#2894)
* 🚧 added skipInstanceOwnerSetup to DB + route to save skipping
* ✨ skipping owner setup persists
* ✅ add tests for authorization and /owner/skip-setup
* 🛠 refactor FE settings getter
* 🛠 move setting setup stop to owner creation
* :bug: fix wrong setting of User.isPending
* :bug: fix isPending
* 🏷 add isPending to PublicUser
* :bug: fix unused import
* update delete modal
* change password modal
* remove _label
* sort keys
* remove key
* update key names
* fix test endpoint
* 🥅 Handle error workflows permissions (#2908)
* Handle error workflows permissions
* Fixed wrong query format
* 🛠 refactor query
Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
* fix ts issue
* fix list after ispending changes
* fix error page bugs
* fix error redirect
* fix notification
* :bug: fix survey import in migration
* fix up spacing
* update keys spacing
* update keys
* add space
* update key
* fix up more spacing
* 🔐 add current password (#2919)
* add curr pass
* update key names
* :bug: stringify tag ids
* 🔐 check current password before update
* add package lock
* fix dep version
* update version
* 🐛 fix access for instance owner to credentials (#2927)
* 🛠 stringify tag id on entity
* 🔐 Update password requirements (#2920)
* :zap: Update password requirements
* :zap: Adjust random helpers
* ✅ fix tests for currentPassword check
* change redirection, add homepage
* fix error view redirection
* updated wording
* fix setup redirection
* update validator
* remove successfully
* update consumers
* update settings redirect
* on signup, redirect to homepage
* update empty state
* add space to emails
* remove brackets
* add opacity
* update spacing
* remove border from last user
* personal details updated
* update redirect on sign up
* prevent text wrap
* fix notification title line height
* remove console log
* 🐘 Support testing with Postgres and MySQL (#2886)
* :card_file_box: Fix Postgres migrations
* :zap: Add DB-specific scripts
* :sparkles: Set up test connections
* :zap: Add Postgres UUID check
* :test_tube: Make test adjustments for Postgres
* :zap: Refactor connection logic
* :sparkles: Set up double init for Postgres
* :pencil2: Add TODOs
* :zap: Refactor DB dropping logic
* :sparkles: Implement global teardown
* :sparkles: Create TypeORM wrappers
* :sparkles: Initial MySQL setup
* :zap: Clean up Postgres connection options
* :zap: Simplify by sharing bootstrap connection name
* :card_file_box: Fix MySQL migrations
* :fire: Remove comments
* :zap: Use ES6 imports
* :fire: Remove outdated comments
* :zap: Centralize bootstrap connection name handles
* :zap: Centralize database types
* :pencil2: Update comment
* :truck: Rename `findRepository`
* :construction: Attempt to truncate MySQL
* :sparkles: Implement creds router
* :bug: Fix duplicated MySQL bootstrap
* :bug: Fix misresolved merge conflict
* :card_file_box: Fix tags migration
* :card_file_box: Fix MySQL UM migration
* :bug: Fix MySQL parallelization issues
* :blue_book: Augment TypeORM to prevent error
* :fire: Remove comments
* :sparkles: Support one sqlite DB per suite run
* :truck: Move `testDb` to own module
* :fire: Deduplicate bootstrap Postgres logic
* :fire: Remove unneeded comment
* :zap: Make logger init calls consistent
* :pencil2: Improve comment
* :pencil2: Add dividers
* :art: Improve formatting
* :fire: Remove duplicate MySQL global setting
* :truck: Move comment
* :zap: Update default test script
* :fire: Remove unneeded helper
* :zap: Unmarshal answers from Postgres
* :bug: Phase out `isTestRun`
* :zap: Refactor `isEmailSetup`
* :fire: Remove unneeded imports
* :zap: Handle bootstrap connection errors
* :fire: Remove unneeded imports
* :fire: Remove outdated comments
* :pencil2: Fix typos
* :truck: Relocate `answersFormatter`
* :rewind: Undo package.json miscommit
* :fire: Remove unneeded import
* :zap: Refactor test DB prefixing
* :zap: Add no-leftover check to MySQL
* :package: Update package.json
* :zap: Autoincrement on simulated MySQL truncation
* :fire: Remove debugging queries
* ✏️ fix email template link expiry
* 🔥 remove unused import
* ✅ fix testing email not sent error
* fix duplicate import
* add package lock
* fix export
* change opacity
* fix text issue
* update action box
* update error title
* update forgot password
* update survey
* update product text
* remove unset fields
* add category to page events
* remove duplicate import
* update key
* update key
* update label type
* 🎨 um/fe review (#2946)
* :whale: Update Node.js versions of Docker images to 16
* :bug: Fix that some keyboard shortcuts did no longer work
* N8N-3057 Fixed Keyboard shortcuts no longer working on / Fixed callDebounced function
* N8N-3057 Update Debounce Function
* N8N-3057 Refactor callDebounce function
* N8N-3057 Update Dobounce Function
* :bug: Fix issue with tooltips getting displayed behind node details view
* fix tooltips z-index
* move all element ui components
* update package lock
* :bug: Fix credentials list load issue (#2931)
* always fetch credentials
* only fetch credentials once
* :zap: Allow to disable hiring banner (#2902)
* :sparkles: Add flag
* :zap: Adjust interfaces
* :zap: Adjust store module
* :zap: Adjust frontend settings
* :zap: Adjust frontend display
* :bug: Fix issue that ctrl + o did behave wrong on workflow templates page (#2934)
* N8N-3094 Workflow Templates cmd-o acts on the Preview/Iframe
* N8N-3094 Workflow Templates cmd-o acts on the Preview/Iframe
* disable shortcuts for preview
Co-authored-by: Mutasem <mutdmour@gmail.com>
* :arrow_up: Update package-lock.json file
* :bug: Fix sorting by field in Baserow Node (#2942)
This fixes a bug which currently leads to the "Sorting" option of the node to be ignored.
* :bug: Fix some i18n line break issues
* :sparkles: Add Odoo Node (#2601)
* added odoo scaffolding
* update getting data from odoo instance
* added scaffolding for main loop and request functions
* added functions for CRUD opperations
* improoved error handling for odooJSONRPCRequest
* updated odoo node and fixing nodelinter issues
* fixed alpabetical order
* fixed types in odoo node
* fixing linter errors
* fixing linter errors
* fixed data shape returned from man loop
* updated node input types, added fields list to models
* update when custom resource is selected options for fields list will be populated dynamicly
* minor fixes
* :hammer: fixed credential test, updating CRUD methods
* :hammer: added additional fields to crm resource
* :hammer: added descriptions, fixed credentials test bug
* :hammer: standardize node and descriptions design
* :hammer: removed comments
* :hammer: added pagination to getAll operation
* :zap: removed leftover function from previous implementation, removed required from optional fields
* :zap: fixed id field, added indication of type and if required to field description, replaced string input in filters to fetched list of fields
* :hammer: fetching list of models from odoo, added selection of fields to be returned to predefined models, fixes accordingly to review
* :zap: Small improvements
* :hammer: extracted adress fields into collection, changed fields to include in descriptions, minor tweaks
* :zap: Improvements
* :hammer: working on review
* :hammer: fixed linter errors
* :hammer: review wip
* :hammer: review wip
* :hammer: review wip
* :zap: updated display name for URL in credentials
* :hammer: added checks for valid id to delete and update
* :zap: Minor improvements
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
* :bug: Handle Wise SCA requests (#2734)
* :zap: Improve Wise error message after previous change
* fix duplicate import
* add package lock
* fix export
* change opacity
* fix text issue
* update action box
* update error title
* update forgot password
* update survey
* update product text
* remove unset fields
* add category to page events
* remove duplicate import
* update key
* update key
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
Co-authored-by: Oliver Trajceski <olivertrajceski@yahoo.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Tom <19203795+that-one-tom@users.noreply.github.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: pemontto <939704+pemontto@users.noreply.github.com>
* Move owner skip from settings
* 🐛 SMTP fixes (#2937)
* :fire: Remove `UM_` from SMTP env vars
* :fire: Remove SMTP host default value
* :zap: Update sender value
* :zap: Update invite template
* :zap: Update password reset template
* :zap: Update `N8N_EMAIL_MODE` default value
* :fire: Remove `EMAIL` from all SMTP vars
* :sparkles: Implement `verifyConnection()`
* :truck: Reposition comment
* :pencil2: Fix typo
* :pencil2: Minor env var documentation improvements
* :art: Fix spacing
* :art: Fix spacing
* :card_file_box: Remove SMTP settings cache
* :zap: Adjust log message
* :zap: Update error message
* :pencil2: Fix template typo
* :pencil2: Adjust wording
* :zap: Interpolate email into success toast
* :pencil2: Adjust base message in `verifyConnection()`
* :zap: Verify connection on password reset
* :zap: Bring up POST /users SMTP check
* :bug: remove cookie if cookie is not valid
* :zap: verify connection on instantiation
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
* 🔊 create logger helper for migrations (#2944)
* 🔥 remove unused database
* :loud_sound: add migration logging for sqlite
* 🔥 remove unnecessary index creation
* ⚡️ change log level to warn
* 🐛 Fix issue with workflow process to initialize db connection correctly (#2948)
* ✏️ update error messages for webhhook run/activation
* 📈 Implement telemetry events (#2868)
* Implement basic telemetry events
* Fixing user id as part of the telemetry data
* Added user id to be part of the tracked data
* :sparkles: Create telemetry mock
* :test_tube: Fix tests with telemetry mock
* :test_tube: Fix missing key in authless endpoint
* :blue_book: Create authless request type
* :fire: Remove log
* :bug: Fix `migration_strategy` assignment
* :blue_book: Remove `instance_id` from `ITelemetryUserDeletionData`
* :zap: Simplify concatenation
* :zap: Simplify `track()` call signature
* Fixed payload of telemetry to always include user_id
* Fixing minor issues
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
* 🔊 Added logs to credentials, executions and workflows (#2915)
* Added logs to credentials, executions and workflows
* Some updates according to ivov's feedback
* :zap: update log levels
* ✅ fix tests
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
* :bug: fix telemetry error
* fix conflicts with master
* fix duplicate
* add package-lock
* :bug: Um/fixes (#2952)
* add initials to avatar
* redirect to signin if invalid token
* update pluralization
* add auth page category
* data transferred
* touch up setup page
* update button to add cursor
* fix personalization modal not closing
* ✏️ fix environment name
* 🐛 fix disabling UM
* 🐛 fix email setup flag
* 🐛 FE fixes 1 (#2953)
* add initials to avatar
* redirect to signin if invalid token
* update pluralization
* add auth page category
* data transferred
* touch up setup page
* update button to add cursor
* fix personalization modal not closing
* capitalize labels, refactor text
* Fixed the issue with telemetry data missing for personalization survey
* Changed invite email text
* 🐛 Fix quotes issue with postgres migration (#2958)
* Changed text for invite link
* 🐛 fix reset command for mysql
* ✅ fix race condition in test DB creation
* 🔐 block user creation if UM is disabled
* 🥅 improve smtp setup issue error
* :zap: update error message
* refactor route rules
* set package lock
* fix access
* remove capitalize
* update input labels
* refactor heading
* change span to fragment
* add route types
* refactor views
* ✅ fix increase timeout for mysql
* :zap: correct logic of error message
* refactor view names
* :zap: update randomString
* 📈 Added missing event regarding failed emails (#2964)
* replace label with info
* 🛠 refactor JWT-secret creation
* remove duplicate key
* remove unused part
* remove semicolon
* fix up i18n pattern
* update translation keys
* update urls
* support i18n in nds
* fix how external keys are handled
* add source
* 💥 update timestamp of UM migration
* ✏️ small message updates
* fix tracking
* update notification line-height
* fix avatar opacity
* fix up empty state
* shift focus to input
* 🔐 Disable basic auth after owner has been set up (#2973)
* Disable basic auth after owner has been set up
* Remove unnecessary comparison
* rename modal title
* 🐛 use pgcrypto extension for uuid creation (#2977)
* 📧 Added public url variable for emails (#2967)
* Added public url variable for emails
* Fixed base url for reset password - the current implementation overrides possibly existing path
* Change variable name to editorUrl
* Using correct name editorUrl for emails
* Changed variable description
* Improved base url naming and appending path so it remains consistent
* Removed trailing slash from editor base url
* 🌐 fix i18n pattern (#2970)
* fix up i18n pattern
* update translation keys
* update urls
* support i18n in nds
* fix how external keys are handled
* add source
* Um/fixes 1000 (#2980)
* fix select issue
* 😫 hacky solution to circumvent pgcrypto (#2979)
* fix owner bug after transfer. always fetch latest credentials
* add confirmation modal to setup
* Use webhook url as fallback when editor url is not defined
* fix enter bug
* update modal
* update modal
* update modal text, fix bug in settings view
* Updating editor url to not append path
* rename keys
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Ahsan Virani <ahsan.virani@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
Co-authored-by: Oliver Trajceski <olivertrajceski@yahoo.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
Co-authored-by: Tom <19203795+that-one-tom@users.noreply.github.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: pemontto <939704+pemontto@users.noreply.github.com>
2022-03-14 06:46:32 -07:00
background - color : var ( -- color - canvas - background ) ;
2022-09-26 06:25:19 -07:00
width : 100 % ;
height : 100 % ;
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
position : relative ;
2019-06-23 03:35:23 -07:00
}
. node - view - wrapper {
position : fixed ;
}
. node - view {
position : relative ;
width : 100 % ;
height : 100 % ;
2021-02-28 09:08:14 -08:00
transform - origin : 0 0 ;
2022-09-26 06:25:19 -07:00
z - index : - 1 ;
2019-06-23 03:35:23 -07:00
}
. node - view - background {
:sparkles: Add Templates (#2720)
* Templates Bugs / Fixed Various Bugs / Multiply Api Request, Carousel Gradient, Core Nodes Filters ...
* Updated MainSidebar Paddings
* N8N-Templates Bugfixing - Remove Unnecesairy Icon (Shape), Refatctor infiniteScrollEnabled Prop + updated infiniterScroll functinality
* N8N-2853 Fixed Carousel Arrows Bug after Cleaning the SearchBar
* fix telemetry init
* fix search tracking issues
* N8N-2853 Created FilterTemplateNode Constant Array, Filter PlayButton and WebhookRespond from Nodes, Added Box for showing more nodes inside TemplateList, Updated NewWorkflowButton to primary, Fixed Markdown issue with Code
* N8N-2853 Removed Placeholder if Workflows Or Collections are not found, Updated the Logic
* fix telemetry events
* clean up session id
* update user inserted event
* N8N-2853 Fixed Categories to Moving if the names are long
* Add todos
* Update Routes on loading
* fix spacing
* Update Border Color
* Update Border Readius
* fix filter fn
* fix constant, console error
* N8N-2853 PR Fixes, Refactoring, Removing unnecesairy code ..
* N8N-2853 PR Fixes - Editor-ui Fixes, Refactoring, Removing Dead Code ...
* N8N-2853 Refactor Card to LongCard
* clean up spacing, replace css var
* clean up spacing
* set categories as optional in node
* replace vars
* refactor store
* remove unnesssary import
* fix error
* fix templates view to start
* add to cache
* fix coll view data
* fix categories
* fix category event
* fix collections carousel
* fix initial load and search
* fix infinite load
* fix query param
* fix scrolling issues
* fix scroll to top
* fix search
* fix collections search
* fix navigation bug
* rename view
* update package lock
* rename workflow view
* rename coll view
* update routes
* add wrapper component
* set session id
* fix search tracking
* fix session tracking
* remove deleted mutation
* remove check for unsupported nodes
* refactor filters
* lazy load template
* clean up types
* refactor infinte scroll
* fix end of search
* Fix spacing
* fix coll loading
* fix types
* fix coll view list
* fix navigation
* rename types
* rename state
* fix search responsiveness
* fix coll view spacing
* fix search view spacing
* clean up views
* set background color
* center page not vert
* fix workflow view
* remove import
* fix background color
* fix background
* clean props
* clean up imports
* refactor button
* update background color
* fix spacing issue
* rename event
* update telemetry event
* update endpoints, add loading view, check for endpoint health
* remove conolse log
* N8N-2853 Fixed Menu Items Padding
* replace endpoints
* fix type issues
* fix categories
* N8N-2853 Fixed ParameterInput Placeholder after ElementUI Upgrade
* update createdAt
* :zap: Fix placeholder in creds config modal
* :pencil2: Adjust docstring to `credText` placeholder version
* N8N-2853 Optimized
* N8N-2853 Optimized code
* :zap: Add deployment type to FE settings
* :zap: Add deployment type to interfaces
* N8N-2853 Removed Animated prop from components
* :zap: Add deployment type to store module
* :sparkles: Create hiring banner
* :zap: Display hiring banner
* :rewind: Undo unrelated change
* N8N-2853 Refactor TemplateFilters
* :zap: Fix indentation
* N8N-2853 Reorder items / TemplateList
* :shirt: Fix lint
* N8N-2853 Refactor TemplateFilters Component
* N8N-2853 Reorder TemplateList
* refactor template card
* update timeout
* fix removelistener
* fix spacing
* split enabled from offline
* add spacing to go back
* N8N-2853 Fixed Screens for Tablet & Mobile
* N8N-2853 Update Stores Order
* remove image componet
* remove placeholder changes
* N8N-2853 Fixed Chinnese Placeholders for El Select Component that comes from the Library Upgrade
* N8N-2853 Fixed Vue Agile Console Warnings
* N8N-2853 Update Collection Route
* :pencil2: Update jobs URL
* :truck: Move logging to root component
* :zap: Refactor `deploymentType` to `isInternalUser`
* :zap: Improve syntax
* fix cut bug in readonly view
* N8N-3012 Fixed Details section in templates with lots of description, Fixed Mardown Block with overflox-x
* N8N-3012 Increased Font-size, Spacing and Line-height of the Categories Items
* N8N-3012 Fixed Vue-agile client width error on resize
* only delay redirect for root path
* N8N-3012 Fixed Carousel Arrows that Disappear
* N8N-3012 Make Loading Screen same color as Templates
* N8N-3012 Markdown renders inline block as block code
* add offline warning
* hide log from workflow iframe
* update text
* make search button larger
* N8N-3012 Categories / Tags extended all the way in details section
* load data in cred modals
* remove deleted message
* add external hook
* remove import
* update env variable description
* fix markdown width issue
* disable telemetry for demo, add session id to template pages
* fix telemetery bugs
* N8N-3012 Not found Collections/Wokrkflow
* N8N-3012 Checkboxes change order when categories are changed
* N8N-3012 Refactor SortedCategories inside TemplateFilters component
* fix firefox bug
* add telemetry requirements
* add error check
* N8N-3012 Update GoBackButton to check if Route History is present
* N8N-3012 Fixed WF Nodes Icons
* hide workflow screenshots
* remove unnessary mixins
* rename prop
* fix design a bit
* rename data
* clear workspace on destroy
* fix copy paste bug
* fix disabled state
* N8N-3012 Fixed Saving/Leave without saving Modal
* fix telemetry issue
* fix telemetry issues, error bug
* fix error notification
* disable workflow menu items on templates
* fix i18n elementui issue
* Remove Emit - NodeType from HoverableNodeIcon component
* TechnicalFixes: NavigateTo passed down as function should be helper
* TechnicalFixes: Update NavigateTo function
* TechnicalFixes: Add FilterCoreNodes directly as function
* check for empty connecitions
* fix titles
* respect new lines
* increase categories to be sliced
* rename prop
* onUseWorkflow
* refactor click event
* fix bug, refactor
* fix loading story
* add default
* fix styles at right level of abstraction
* add wrapper with width
* remove loading blocks component
* add story
* rename prop
* fix spacing
* refactor tag, add story
* move margin to container
* fix tag redirect, remove unnessary check
* make version optional
* rename view
* move from workflows to templates store
* remove unnessary change
* remove unnessary css
* rename component
* refactor collection card
* add boolean to prevent shrink
* clean up carousel
* fix redirection bug on save
* remove listeners to fix multiple listeners bug
* remove unnessary types
* clean up boolean set
* fix node select bug
* rename component
* remove unnessary class
* fix redirection bug
* remove unnessary error
* fix typo
* fix blockquotes, pre
* refactor markdown rendering
* remove console log
* escape markdown
* fix safari bug
* load active workflows to fix modal bug
* :arrow_up: Update package-lock.json file
* :zap: Add n8n version as header
Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2022-02-28 01:57:44 -08:00
background - color : var ( -- color - canvas - background ) ;
2019-06-23 03:35:23 -07:00
position : absolute ;
width : 10000 px ;
height : 10000 px ;
2022-09-26 06:25:19 -07:00
z - index : - 2 ;
2019-06-23 03:35:23 -07:00
}
. move - active {
cursor : grab ;
cursor : - moz - grab ;
cursor : - webkit - grab ;
touch - action : none ;
}
. move - in - process {
cursor : grabbing ;
cursor : - moz - grabbing ;
cursor : - webkit - grabbing ;
touch - action : none ;
}
. workflow - execute - wrapper {
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
position : absolute ;
display : flex ;
justify - content : center ;
2022-11-07 00:53:27 -08:00
align - items : center ;
feat(editor, core, cli): implement new workflow experience (#4358)
* 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 <krynble@gmail.com>
* :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 <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2022-10-18 05:23:22 -07:00
left : 50 % ;
transform : translateX ( - 50 % ) ;
bottom : 110 px ;
width : auto ;
2022-11-07 00:53:27 -08:00
@ media ( max - width : $breakpoint - 2 xs ) {
bottom : 150 px ;
}
button {
display : flex ;
justify - content : center ;
align - items : center ;
2022-11-07 03:56:19 -08:00
margin - left : 0.625 rem ;
& : first - child {
margin : 0 ;
}
2019-06-23 03:35:23 -07:00
}
}
/* Makes sure that when selected with mouse it does not select text */
. do - not - select * ,
. jtk - drag - select * {
- webkit - touch - callout : none ;
- webkit - user - select : none ;
- khtml - user - select : none ;
- moz - user - select : none ;
- ms - user - select : none ;
user - select : none ;
}
< / style >
< style lang = "scss" >
. drop - add - node - label {
2022-07-26 03:45:55 -07:00
color : var ( -- color - text - dark ) ;
2019-06-23 03:35:23 -07:00
font - weight : 600 ;
font - size : 0.8 em ;
text - align : center ;
background - color : # ffffff55 ;
}
2021-11-19 01:17:13 -08:00
. connection - actions {
& : hover {
display : block ! important ;
}
2023-01-30 09:20:50 -08:00
> button {
2021-11-19 01:17:13 -08:00
color : var ( -- color - foreground - xdark ) ;
border : 2 px solid var ( -- color - foreground - xdark ) ;
background - color : var ( -- color - background - xlight ) ;
border - radius : var ( -- border - radius - base ) ;
height : var ( -- spacing - l ) ;
width : var ( -- spacing - l ) ;
cursor : pointer ;
display : inline - flex ;
align - items : center ;
justify - content : center ;
position : absolute ;
top : - 12 px ;
& . add {
right : 4 px ;
}
& . delete {
left : 4 px ;
}
svg {
pointer - events : none ;
font - size : var ( -- font - size - 2 xs ) ;
}
& : hover {
border - color : var ( -- color - primary ) ;
color : var ( -- color - primary ) ;
}
}
}
2019-06-23 03:35:23 -07:00
< / style >
2022-10-26 01:02:56 -07:00
< style module lang = "scss" >
. content {
position : relative ;
display : flex ;
overflow : auto ;
2023-02-02 03:08:17 -08:00
height : 100 % ;
width : 100 % ;
2022-10-26 01:02:56 -07:00
}
. shake {
animation : 1 s 200 ms shake ;
}
@ keyframes shake {
2022-12-14 01:04:10 -08:00
10 % ,
90 % {
transform : translate3d ( - 1 px , 0 , 0 ) ;
}
2022-10-26 01:02:56 -07:00
2022-12-14 01:04:10 -08:00
20 % ,
80 % {
transform : translate3d ( 2 px , 0 , 0 ) ;
}
2022-10-26 01:02:56 -07:00
2022-12-14 01:04:10 -08:00
30 % ,
50 % ,
70 % {
transform : translate3d ( - 4 px , 0 , 0 ) ;
}
2022-10-26 01:02:56 -07:00
2022-12-14 01:04:10 -08:00
40 % ,
60 % {
transform : translate3d ( 4 px , 0 , 0 ) ;
}
2022-10-26 01:02:56 -07:00
}
< / style >