2022-12-14 01:04:10 -08:00
import { PropType } from 'vue' ;
2019-06-23 03:35:23 -07:00
import mixins from 'vue-typed-mixins' ;
2023-01-30 09:20:50 -08:00
import { INodeUi } from '@/Interface' ;
2022-11-23 04:41:53 -08:00
import { deviceSupportHelpers } from '@/mixins/deviceSupportHelpers' ;
2023-01-30 09:20:50 -08:00
import { NO_OP_NODE_TYPE } from '@/constants' ;
2021-11-19 01:17:13 -08:00
2022-12-14 01:04:10 -08:00
import { INodeTypeDescription } from 'n8n-workflow' ;
2022-11-04 06:04:31 -07:00
import { mapStores } from 'pinia' ;
import { useUIStore } from '@/stores/ui' ;
2022-12-14 01:04:10 -08:00
import { useWorkflowsStore } from '@/stores/workflows' ;
import { useNodeTypesStore } from '@/stores/nodeTypes' ;
2023-01-30 09:20:50 -08:00
import { BrowserJsPlumbInstance } from '@jsplumb/browser-ui' ;
2023-02-08 05:48:28 -08:00
import { Endpoint , EndpointOptions } from '@jsplumb/core' ;
2022-11-24 01:52:56 -08:00
import * as NodeViewUtils from '@/utils/nodeViewUtils' ;
2022-12-14 01:04:10 -08:00
import { useHistoryStore } from '@/stores/history' ;
2023-01-30 09:20:50 -08:00
import { useCanvasStore } from '@/stores/canvas' ;
2019-06-23 03:35:23 -07:00
2022-12-14 01:04:10 -08:00
export const nodeBase = mixins ( deviceSupportHelpers ) . extend ( {
mounted() {
2019-06-23 03:35:23 -07:00
// Initialize the node
if ( this . data !== null ) {
2022-10-26 01:02:56 -07:00
try {
this . __addNode ( this . data ) ;
2022-12-14 01:04:10 -08:00
} catch ( error ) {
2022-10-26 01:02:56 -07:00
// This breaks when new nodes are loaded into store but workflow tab is not currently active
// Shouldn't affect anything
}
2019-06-23 03:35:23 -07:00
}
} ,
computed : {
2023-01-30 09:20:50 -08:00
. . . mapStores ( useNodeTypesStore , useUIStore , useCanvasStore , useWorkflowsStore , useHistoryStore ) ,
2022-12-14 01:04:10 -08:00
data ( ) : INodeUi | null {
2022-11-04 06:04:31 -07:00
return this . workflowsStore . getNodeByName ( this . name ) ;
2019-06-23 03:35:23 -07:00
} ,
2022-12-14 01:04:10 -08:00
nodeId ( ) : string {
return this . data ? . id || '' ;
2019-06-23 03:35:23 -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
props : {
name : {
type : String ,
} ,
instance : {
2023-01-30 09:20:50 -08:00
type : Object as PropType < BrowserJsPlumbInstance > ,
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
} ,
isReadOnly : {
type : Boolean ,
} ,
isActive : {
type : Boolean ,
} ,
hideActions : {
type : Boolean ,
} ,
disableSelecting : {
type : Boolean ,
} ,
showCustomTooltip : {
type : Boolean ,
} ,
} ,
2019-06-23 03:35:23 -07:00
methods : {
2023-02-08 05:48:28 -08:00
__addEndpointTestingData ( endpoint : Endpoint , type : string , inputIndex : number ) {
if ( window ? . Cypress && 'canvas' in endpoint . endpoint ) {
const canvas = endpoint . endpoint . canvas ;
this . instance . setAttribute ( canvas , 'data-endpoint-name' , this . data . name ) ;
this . instance . setAttribute ( canvas , 'data-input-index' , inputIndex . toString ( ) ) ;
this . instance . setAttribute ( canvas , 'data-endpoint-type' , type ) ;
}
} ,
2022-12-14 01:04:10 -08:00
__addInputEndpoints ( node : INodeUi , nodeTypeData : INodeTypeDescription ) {
2019-06-23 03:35:23 -07:00
// Add Inputs
2021-11-19 01:17:13 -08:00
let index ;
const indexData : {
2019-06-23 03:35:23 -07:00
[ key : string ] : number ;
} = { } ;
2021-11-19 01:17:13 -08:00
nodeTypeData . inputs . forEach ( ( inputName : string , i : number ) = > {
2019-06-23 03:35:23 -07:00
// Increment the index for inputs with current name
if ( indexData . hasOwnProperty ( inputName ) ) {
indexData [ inputName ] ++ ;
} else {
indexData [ inputName ] = 0 ;
}
index = indexData [ inputName ] ;
// Get the position of the anchor depending on how many it has
2022-12-14 01:04:10 -08:00
const anchorPosition =
NodeViewUtils . ANCHOR_POSITIONS . input [ nodeTypeData . inputs . length ] [ index ] ;
2019-06-23 03:35:23 -07:00
2023-01-30 09:20:50 -08:00
const newEndpointData : EndpointOptions = {
2022-12-14 01:04:10 -08:00
uuid : NodeViewUtils.getInputEndpointUUID ( this . nodeId , index ) ,
2019-06-23 03:35:23 -07:00
anchor : anchorPosition ,
2021-11-19 01:17:13 -08:00
maxConnections : - 1 ,
endpoint : 'Rectangle' ,
2023-01-30 09:20:50 -08:00
paintStyle : NodeViewUtils.getInputEndpointStyle ( nodeTypeData , '--color-foreground-xdark' ) ,
hoverPaintStyle : NodeViewUtils.getInputEndpointStyle ( nodeTypeData , '--color-primary' ) ,
source : false ,
target : ! this . isReadOnly && nodeTypeData . inputs . length > 1 , // only enabled for nodes with multiple inputs.. otherwise attachment handled by connectionDrag event in NodeView,
2019-06-23 03:35:23 -07:00
parameters : {
2022-08-03 04:06:53 -07:00
nodeId : this.nodeId ,
2019-06-23 03:35:23 -07:00
type : inputName ,
index ,
} ,
2021-12-03 09:53:55 -08:00
enabled : ! this . isReadOnly , // enabled in default case to allow dragging
cssClass : 'rect-input-endpoint' ,
2021-11-19 01:17:13 -08:00
dragAllowedWhenFull : true ,
2023-01-30 09:20:50 -08:00
hoverClass : 'dropHover' ,
2019-06-23 03:35:23 -07:00
} ;
2023-01-30 09:20:50 -08:00
const endpoint = this . instance ? . addEndpoint (
this . $refs [ this . data . name ] as Element ,
newEndpointData ,
) ;
2023-02-08 05:48:28 -08:00
this . __addEndpointTestingData ( endpoint , 'input' , index ) ;
2019-08-02 06:56:05 -07:00
if ( nodeTypeData . inputNames ) {
// Apply input names if they got set
2023-01-30 09:20:50 -08:00
endpoint . addOverlay ( NodeViewUtils . getInputNameOverlay ( nodeTypeData . inputNames [ index ] ) ) ;
2019-08-02 06:56:05 -07:00
}
2022-12-14 01:04:10 -08:00
if ( ! Array . isArray ( endpoint ) ) {
2022-10-24 11:17:25 -07:00
endpoint . __meta = {
nodeName : node.name ,
nodeId : this.nodeId ,
index : i ,
totalEndpoints : nodeTypeData.inputs.length ,
} ;
}
2019-06-23 03:35:23 -07:00
2019-08-02 06:56:05 -07:00
// TODO: Activate again if it makes sense. Currently makes problems when removing
// connection on which the input has a name. It does not get hidden because
// the endpoint to which it connects when letting it go over the node is
// different to the regular one (have different ids). So that seems to make
// problems when hiding the input-name.
// if (index === 0 && inputName === 'main') {
// // Make the first main-input the default one to connect to when connection gets dropped on node
2021-11-19 01:17:13 -08:00
// this.instance.makeTarget(this.nodeId, newEndpointData);
2019-08-02 06:56:05 -07:00
// }
2019-06-23 03:35:23 -07:00
} ) ;
2023-01-30 09:20:50 -08:00
if ( nodeTypeData . inputs . length === 0 ) {
this . instance . manage ( this . $refs [ this . data . name ] as Element ) ;
}
2021-11-19 01:17:13 -08:00
} ,
__addOutputEndpoints ( node : INodeUi , nodeTypeData : INodeTypeDescription ) {
let index ;
const indexData : {
[ key : string ] : number ;
} = { } ;
2019-06-23 03:35:23 -07:00
2021-11-19 01:17:13 -08:00
nodeTypeData . outputs . forEach ( ( inputName : string , i : number ) = > {
2019-06-23 03:35:23 -07:00
// Increment the index for outputs with current name
if ( indexData . hasOwnProperty ( inputName ) ) {
indexData [ inputName ] ++ ;
} else {
indexData [ inputName ] = 0 ;
}
index = indexData [ inputName ] ;
// Get the position of the anchor depending on how many it has
2022-12-14 01:04:10 -08:00
const anchorPosition =
NodeViewUtils . ANCHOR_POSITIONS . output [ nodeTypeData . outputs . length ] [ index ] ;
2019-06-23 03:35:23 -07:00
2023-01-30 09:20:50 -08:00
const newEndpointData : EndpointOptions = {
2022-11-24 01:52:56 -08:00
uuid : NodeViewUtils.getOutputEndpointUUID ( this . nodeId , index ) ,
2019-06-23 03:35:23 -07:00
anchor : anchorPosition ,
2021-11-19 01:17:13 -08:00
maxConnections : - 1 ,
2023-01-30 09:20:50 -08:00
endpoint : {
type : 'Dot' ,
options : {
radius : nodeTypeData && nodeTypeData . outputs . length > 2 ? 7 : 9 ,
} ,
} ,
paintStyle : NodeViewUtils.getOutputEndpointStyle (
2022-12-14 01:04:10 -08:00
nodeTypeData ,
'--color-foreground-xdark' ,
) ,
2023-01-30 09:20:50 -08:00
hoverPaintStyle : NodeViewUtils.getOutputEndpointStyle ( nodeTypeData , '--color-primary' ) ,
source : true ,
target : false ,
2021-11-19 01:17:13 -08:00
enabled : ! this . isReadOnly ,
2019-06-23 03:35:23 -07:00
parameters : {
2022-08-03 04:06:53 -07:00
nodeId : this.nodeId ,
2019-06-23 03:35:23 -07:00
type : inputName ,
index ,
} ,
2023-01-30 09:20:50 -08:00
hoverClass : 'dot-output-endpoint-hover' ,
connectionsDirected : true ,
2021-12-03 09:53:55 -08:00
cssClass : 'dot-output-endpoint' ,
2021-11-19 01:17:13 -08:00
dragAllowedWhenFull : false ,
2019-06-23 03:35:23 -07:00
} ;
2023-01-30 09:20:50 -08:00
const endpoint = this . instance . addEndpoint (
this . $refs [ this . data . name ] as Element ,
newEndpointData ,
) ;
2023-02-08 05:48:28 -08:00
this . __addEndpointTestingData ( endpoint , 'output' , index ) ;
2019-06-23 03:35:23 -07:00
if ( nodeTypeData . outputNames ) {
// Apply output names if they got set
2023-01-30 09:20:50 -08:00
const overlaySpec = NodeViewUtils . getOutputNameOverlay ( nodeTypeData . outputNames [ index ] ) ;
2023-02-08 05:48:28 -08:00
endpoint . addOverlay ( overlaySpec ) ;
2019-06-23 03:35:23 -07:00
}
2022-12-14 01:04:10 -08:00
if ( ! Array . isArray ( endpoint ) ) {
endpoint . __meta = {
nodeName : node.name ,
nodeId : this.nodeId ,
index : i ,
totalEndpoints : nodeTypeData.outputs.length ,
} ;
}
2021-12-03 09:53:55 -08:00
if ( ! this . isReadOnly ) {
2023-01-30 09:20:50 -08:00
const plusEndpointData : EndpointOptions = {
2022-11-24 01:52:56 -08:00
uuid : NodeViewUtils.getOutputEndpointUUID ( this . nodeId , index ) ,
2021-12-03 09:53:55 -08:00
anchor : anchorPosition ,
maxConnections : - 1 ,
2023-01-30 09:20:50 -08:00
endpoint : {
type : 'N8nPlus' ,
options : {
dimensions : 24 ,
connectedEndpoint : endpoint ,
showOutputLabel : nodeTypeData.outputs.length === 1 ,
size : nodeTypeData.outputs.length >= 3 ? 'small' : 'medium' ,
hoverMessage : this.$locale.baseText ( 'nodeBase.clickToAddNodeOrDragToConnect' ) ,
} ,
} ,
source : true ,
target : false ,
2021-12-03 09:53:55 -08:00
enabled : ! this . isReadOnly ,
2023-01-30 09:20:50 -08:00
paintStyle : {
2021-12-03 09:53:55 -08:00
outlineStroke : 'none' ,
} ,
2023-01-30 09:20:50 -08:00
hoverPaintStyle : {
2021-12-03 09:53:55 -08:00
outlineStroke : 'none' ,
} ,
parameters : {
2022-08-03 04:06:53 -07:00
nodeId : this.nodeId ,
2021-12-03 09:53:55 -08:00
type : inputName ,
index ,
} ,
cssClass : 'plus-draggable-endpoint' ,
dragAllowedWhenFull : false ,
} ;
2023-01-30 09:20:50 -08:00
const plusEndpoint = this . instance . addEndpoint (
this . $refs [ this . data . name ] as Element ,
plusEndpointData ,
) ;
2023-02-08 05:48:28 -08:00
this . __addEndpointTestingData ( plusEndpoint , 'plus' , index ) ;
2021-12-03 09:53:55 -08:00
2022-12-14 01:04:10 -08:00
if ( ! Array . isArray ( plusEndpoint ) ) {
2022-10-24 11:17:25 -07:00
plusEndpoint . __meta = {
nodeName : node.name ,
nodeId : this.nodeId ,
index : i ,
totalEndpoints : nodeTypeData.outputs.length ,
} ;
}
2021-12-03 09:53:55 -08:00
}
2019-06-23 03:35:23 -07:00
} ) ;
2021-11-19 01:17:13 -08:00
} ,
2022-12-14 01:04:10 -08:00
__addNode ( node : INodeUi ) {
2023-01-30 09:20:50 -08:00
const nodeTypeData = ( this . nodeTypesStore . getNodeType ( node . type , node . typeVersion ) ? ?
this . nodeTypesStore . getNodeType ( NO_OP_NODE_TYPE ) ) as INodeTypeDescription ;
2020-06-07 15:34:15 -07:00
2021-11-19 01:17:13 -08:00
this . __addInputEndpoints ( node , nodeTypeData ) ;
this . __addOutputEndpoints ( node , nodeTypeData ) ;
2019-06-23 03:35:23 -07:00
} ,
2021-08-08 02:14:09 -07:00
touchEnd ( e : MouseEvent ) {
if ( this . isTouchDevice ) {
2022-11-04 06:04:31 -07:00
if ( this . uiStore . isActionActive ( 'dragActive' ) ) {
this . uiStore . removeActiveAction ( 'dragActive' ) ;
2021-08-08 02:14:09 -07:00
}
}
} ,
2022-12-14 01:04:10 -08:00
mouseLeftClick ( e : MouseEvent ) {
2020-12-23 23:37:13 -08:00
// @ts-ignore
const path = e . path || ( e . composedPath && e . composedPath ( ) ) ;
for ( let index = 0 ; index < path . length ; index ++ ) {
2022-12-14 01:04:10 -08:00
if (
path [ index ] . className &&
typeof path [ index ] . className === 'string' &&
path [ index ] . className . includes ( 'no-select-on-click' )
) {
2020-12-23 23:37:13 -08:00
return ;
}
}
2020-10-23 09:15:52 -07:00
if ( ! this . isTouchDevice ) {
2022-11-04 06:04:31 -07:00
if ( this . uiStore . isActionActive ( 'dragActive' ) ) {
this . uiStore . removeActiveAction ( 'dragActive' ) ;
2019-07-17 10:05:03 -07:00
} else {
2022-10-11 01:06:33 -07:00
if ( ! this . isCtrlKeyPressed ( e ) ) {
2020-10-23 09:15:52 -07:00
this . $emit ( 'deselectAllNodes' ) ;
}
2022-11-04 06:04:31 -07:00
if ( this . uiStore . isNodeSelected ( this . data . name ) ) {
2020-10-23 09:15:52 -07:00
this . $emit ( 'deselectNode' , this . name ) ;
} else {
this . $emit ( 'nodeSelected' , this . name ) ;
}
2019-07-17 10:05:03 -07:00
}
2019-06-23 03:35:23 -07:00
}
} ,
} ,
} ) ;