From adc2515dee2aa429ca076694b67f70f41db4dae7 Mon Sep 17 00:00:00 2001 From: Oliver Trajceski Date: Thu, 25 Nov 2021 23:33:41 +0100 Subject: [PATCH] :sparkles: Improve Waiting Webhook call state in WF Canvas (#2430) * N8N-2586 Improve Waiting Webhook call state in WF Canvas * N8N-2586 Added watcher for showing Webhook's Node Tooltip on execution * N8N-2586 Show helping tooltip for trigger node if wokrflow is running, it is a trigger node, if it is only one trigger node in WF * N8N-2586 Rework/Move logic to computed property, Created getter for ActveTriggerNodesInWokrflow, Add style to trigger node's tooltip, remove comments * N8N-2586 Added EventTriggerDescription prop in INodeTypeDescription Interface, Updated Logic for TriggerNode Tooltip based on the new prop * N8N-2586 Add new use cases/watcher to show Trigger Nodes Tooltip / If has issues, if paused, if wokrlfow is running, Refactor Getter * N8N-2586 Added z-index to tooltip, Added new Scenario for Tooltip if it is Draged&Droped on the WF * N8N-2586 Refactor computed property for draged nodes * N8N-2586 Fixed Conflicts * N8N-2586 Fixed Tooltip * N8N-2586 Dont show tooltip on core trigger nodes that execute automatically * N8N-2586 Fixed Webhook tooltip when adding/deleting canvas during WF execution * N8N-2586 Updated Logic, Simplify the code * N8N-2586 Simplify Code * N8N-2586 Added check for nodetype * update dragging to use local state * N8N-2586 Added eventTriggerDescription to Interval Node * add comment, use new getter * update to always check Co-authored-by: Mutasem --- packages/editor-ui/src/components/Node.vue | 82 +++++++++++++++++-- .../src/components/mixins/nodeBase.ts | 4 + packages/editor-ui/src/store.ts | 5 ++ packages/editor-ui/src/views/NodeView.vue | 2 +- packages/nodes-base/nodes/Cron/Cron.node.ts | 1 + .../nodes/EmailReadImap/EmailReadImap.node.ts | 1 + .../nodes/ErrorTrigger/ErrorTrigger.node.ts | 1 + .../nodes/Interval/Interval.node.ts | 1 + .../LocalFileTrigger/LocalFileTrigger.node.ts | 1 + .../nodes/N8nTrigger/N8nTrigger.node.ts | 1 + .../nodes/SseTrigger/SseTrigger.node.ts | 1 + .../nodes-base/nodes/Webhook/Webhook.node.ts | 1 + .../WorkflowTrigger/WorkflowTrigger.node.ts | 1 + packages/workflow/src/Interfaces.ts | 1 + 14 files changed, 96 insertions(+), 7 deletions(-) diff --git a/packages/editor-ui/src/components/Node.vue b/packages/editor-ui/src/components/Node.vue index 3f806432c2..fd3ffb8a3d 100644 --- a/packages/editor-ui/src/components/Node.vue +++ b/packages/editor-ui/src/components/Node.vue @@ -26,6 +26,13 @@ +
+ +
+ +
+
+ @@ -106,11 +113,41 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext return workflowResultDataNode.length; }, + canvasOffsetPosition() { + return this.$store.getters.getNodeViewOffsetPosition; + }, + getTriggerNodeTooltip (): string | undefined { + if (this.nodeType !== null && this.nodeType.hasOwnProperty('eventTriggerDescription')) { + return this.nodeType.eventTriggerDescription; + } else { + return `Waiting for you to create an event in ${this.nodeType && this.nodeType.displayName.replace(/Trigger/, "")}`; + } + }, isExecuting (): boolean { return this.$store.getters.executingNode === this.data.name; }, + isSingleActiveTriggerNode (): boolean { + const nodes = this.$store.getters.workflowTriggerNodes.filter((node: INodeUi) => { + const nodeType = this.$store.getters.nodeType(node.type) as INodeTypeDescription | null; + return nodeType && nodeType.eventTriggerDescription !== '' && !node.disabled; + }); + + return nodes.length === 1; + }, + isTriggerNode (): boolean { + return !!(this.nodeType && this.nodeType.group.includes('trigger')); + }, + isTriggerNodeTooltipEmpty () : boolean { + return this.nodeType !== null ? this.nodeType.eventTriggerDescription === '' : false; + }, + isNodeDisabled (): boolean | undefined { + return this.node && this.node.disabled; + }, nodeType (): INodeTypeDescription | null { - return this.$store.getters.nodeType(this.data.type); + return this.data && this.$store.getters.nodeType(this.data.type); + }, + node (): INodeUi | undefined { // same as this.data but reactive.. + return this.$store.getters.nodesByName[this.name] as INodeUi | undefined; }, nodeClass (): object { return { @@ -136,9 +173,7 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext } }, position (): XYPosition { - const node = this.$store.getters.nodesByName[this.name] as INodeUi; // position responsive to store changes - - return node.position; + return this.node ? this.node.position : [0, 0]; }, showDisabledLinethrough(): boolean { return !!(this.data.disabled && this.nodeType && this.nodeType.inputs.length === 1 && this.nodeType.outputs.length === 1); @@ -207,13 +242,33 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext shiftOutputCount (): boolean { return !!(this.nodeType && this.nodeType.outputs.length > 2); }, - }, + shouldShowTriggerTooltip () : boolean { + return !!this.node && this.workflowRunning && this.isTriggerNode && this.isSingleActiveTriggerNode && !this.isTriggerNodeTooltipEmpty && !this.isNodeDisabled && !this.hasIssues && !this.dragging; + }, + }, watch: { isActive(newValue, oldValue) { if (!newValue && oldValue) { this.setSubtitle(); } }, + canvasOffsetPosition() { + if (this.showTriggerNodeTooltip) { + this.showTriggerNodeTooltip = false; + setTimeout(() => { + this.showTriggerNodeTooltip = this.shouldShowTriggerTooltip; + }, 200); + } + }, + shouldShowTriggerTooltip(shouldShowTriggerTooltip) { + if (shouldShowTriggerTooltip) { + setTimeout(() => { + this.showTriggerNodeTooltip = this.shouldShowTriggerTooltip; + }, 2500); + } else { + this.showTriggerNodeTooltip = false; + } + }, nodeRunData(newValue) { this.$emit('run', {name: this.data.name, data: newValue, waiting: !!this.waiting}); }, @@ -228,6 +283,8 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext return { isTouchActive: false, nodeSubtitle: '', + showTriggerNodeTooltip: false, + dragging: false, }; }, methods: { @@ -459,7 +516,6 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext border-color: var(--color-success-light); } } -