🔀 Merge master

This commit is contained in:
Iván Ovejero
2021-11-29 10:05:37 +01:00
166 changed files with 46944 additions and 728 deletions

View File

@@ -26,6 +26,13 @@
<font-awesome-icon icon="sync-alt" spin />
</div>
<div class="node-trigger-tooltip__wrapper">
<n8n-tooltip placement="top" :manual="true" :value="showTriggerNodeTooltip" popper-class="node-trigger-tooltip__wrapper--item">
<div slot="content" v-text="getTriggerNodeTooltip"></div>
<span />
</n8n-tooltip>
</div>
<NodeIcon class="node-icon" :nodeType="nodeType" :size="40" :shrink="false" :disabled="this.data.disabled"/>
</div>
@@ -110,11 +117,41 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
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 {
@@ -140,9 +177,7 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
}
},
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);
@@ -236,13 +271,33 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
shiftOutputCount (): boolean {
return !!(this.nodeType && this.nodeType.outputs.length > 2);
},
},
shouldShowTriggerTooltip () : boolean {
return !!this.node && this.workflowRunning && this.workflowDataItems === 0 && 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});
},
@@ -257,6 +312,8 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
return {
isTouchActive: false,
nodeSubtitle: '',
showTriggerNodeTooltip: false,
dragging: false,
};
},
methods: {
@@ -517,7 +574,6 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
border-color: var(--color-success-light);
}
}
</style>
<style lang="scss">
@@ -526,6 +582,20 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
z-index: 2;
}
.node-trigger-tooltip {
&__wrapper {
top: -22px;
left: 50px;
position: relative;
&--item {
max-width: 160px;
position: fixed;
z-index: 0!important;
}
}
}
/** connector */
.jtk-connector {
z-index: 3;

View File

@@ -74,7 +74,7 @@ export const nodeBase = mixins(
type: inputName,
index,
},
enabled: !this.isReadOnly,
enabled: !this.isReadOnly && nodeTypeData.inputs.length > 1, // only enabled for nodes with multiple inputs.. otherwise attachment handled by connectionDrag event in NodeView
dragAllowedWhenFull: true,
dropOptions: {
tolerance: 'touch',
@@ -170,6 +170,8 @@ export const nodeBase = mixins(
// Do not allow to move nodes in readOnly mode
return false;
}
// @ts-ignore
this.dragging = true;
if (params.e && !this.$store.getters.isNodeSelected(this.data.name)) {
// Only the node which gets dragged directly gets an event, for all others it is
@@ -183,6 +185,8 @@ export const nodeBase = mixins(
return true;
},
stop: (params: { e: MouseEvent }) => {
// @ts-ignore
this.dragging = false;
if (this.$store.getters.isActionActive('dragActive')) {
const moveNodes = this.$store.getters.getSelectedNodes.slice();
const selectedNodeNames = moveNodes.map((node: INodeUi) => node.name);

View File

@@ -676,12 +676,12 @@
const diffX = paintInfo.endStubX - paintInfo.startStubX;
const diffY = paintInfo.endStubY - paintInfo.startStubY;
const direction = diffY >= 0 ? 1 : -1; // vertical direction of loop, above or below source
const direction = -1; // vertical direction of loop, always below source
var midx = paintInfo.startStubX + ((paintInfo.endStubX - paintInfo.startStubX) * midpoint),
midy;
if (diffX < (-1 * loopbackMinimum)) {
if (diffY >= 0 || diffX < (-1 * loopbackMinimum)) {
// loop backward behavior
midy = paintInfo.startStubY - (diffX < 0 ? direction * loopbackVerticalLength : 0);
} else {

View File

@@ -753,6 +753,11 @@ export const store = new Vuex.Store({
return state.activeWorkflows;
},
workflowTriggerNodes: (state, getters) => {
return state.workflow.nodes.filter(node => {
return getters.nodeType(node.type).group.includes('trigger');
});
},
// Node-Index
getNodeIndex: (state) => (nodeName: string): number => {
return state.nodeIndex.indexOf(nodeName);

View File

@@ -1624,7 +1624,7 @@ export default mixins(
);
const nodes = [...document.querySelectorAll('.node-default')];
const onMouseMove = (e: MouseEvent) => {
const onMouseMove = (e: MouseEvent | TouchEvent) => {
if (!connection) {
return;
}
@@ -1639,7 +1639,8 @@ export default mixins(
const inputMargin = 24;
const intersecting = nodes.find((element: Element) => {
const {top, left, right, bottom} = element.getBoundingClientRect();
if (top <= e.pageY && bottom >= e.pageY && (left - inputMargin) <= e.pageX && right >= e.pageX) {
const [x, y] = CanvasHelpers.getMousePosition(e);
if (top <= y && bottom >= y && (left - inputMargin) <= x && right >= x) {
const nodeName = (element as HTMLElement).dataset['name'] as string;
const node = this.$store.getters.getNodeByName(nodeName) as INodeUi | null;
if (node) {
@@ -1664,7 +1665,7 @@ export default mixins(
}
};
const onMouseUp = (e: MouseEvent) => {
const onMouseUp = (e: MouseEvent | TouchEvent) => {
this.pullConnActive = false;
this.newNodeInsertPosition = this.getMousePositionWithinNodeView(e);
CanvasHelpers.resetConnectionAfterPull(connection);
@@ -1673,7 +1674,9 @@ export default mixins(
};
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
}

View File

@@ -52,7 +52,7 @@ export const CONNECTOR_FLOWCHART_TYPE = ['N8nCustom', {
stub: JSPLUMB_FLOWCHART_STUB + 10,
targetGap: 4,
alwaysRespectStubs: false,
loopbackVerticalLength: NODE_SIZE, // height of vertical segment when looping
loopbackVerticalLength: NODE_SIZE + GRID_SIZE, // height of vertical segment when looping
loopbackMinimum: LOOPBACK_MINIMUM, // minimum length before flowchart loops around
getEndpointOffset(endpoint: Endpoint) {
const indexOffset = 10; // stub offset between different endpoints of same node