mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-29 06:29:42 -08:00
support item labels and success path
This commit is contained in:
parent
0eae86874b
commit
571140deee
|
@ -61,6 +61,7 @@ import { workflowHelpers } from '@/components/mixins/workflowHelpers';
|
|||
|
||||
import {
|
||||
INodeTypeDescription,
|
||||
ITaskData,
|
||||
NodeHelpers,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
@ -76,8 +77,11 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext
|
|||
NodeIcon,
|
||||
},
|
||||
computed: {
|
||||
workflowDataItems () {
|
||||
const workflowResultDataNode = this.$store.getters.getWorkflowResultDataByNodeName(this.data.name);
|
||||
nodeRunData(): ITaskData[] {
|
||||
return this.$store.getters.getWorkflowResultDataByNodeName(this.data.name);
|
||||
},
|
||||
workflowDataItems (): Number {
|
||||
const workflowResultDataNode = this.nodeRunData;
|
||||
if (workflowResultDataNode === null) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -161,9 +165,15 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext
|
|||
this.setSubtitle();
|
||||
}
|
||||
},
|
||||
nodeRunData(newValue) {
|
||||
this.$emit('run', {name: this.data.name, data: newValue});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setSubtitle();
|
||||
setTimeout(() => {
|
||||
this.$emit('run', {name: this.data.name, data: this.nodeRunData});
|
||||
}, 0);
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -402,6 +412,10 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, workflowHelpers).ext
|
|||
z-index: 5;
|
||||
}
|
||||
|
||||
.jtk-connector.jtk-success {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.jtk-endpoint {
|
||||
z-index:5;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
@removeNode="removeNode"
|
||||
@runWorkflow="runWorkflow"
|
||||
@moved="onNodeMoved"
|
||||
@run="onNodeRun"
|
||||
:id="'node-' + getNodeIndex(nodeData.name)"
|
||||
:key="getNodeIndex(nodeData.name)"
|
||||
:name="nodeData.name"
|
||||
|
@ -132,7 +133,7 @@ import NodeCreator from '@/components/NodeCreator/NodeCreator.vue';
|
|||
import NodeSettings from '@/components/NodeSettings.vue';
|
||||
import RunData from '@/components/RunData.vue';
|
||||
|
||||
import { getLeftmostTopNode, getWorkflowCorners, scaleSmaller, scaleBigger, scaleReset, addOrRemoveMidpointArrow, addEndpointArrow, getDefaultOverlays, getIcon, getNewNodePosition } from './helpers';
|
||||
import { getLeftmostTopNode, getWorkflowCorners, scaleSmaller, scaleBigger, scaleReset, showOrHideMidpointArrow, addEndpointArrow, getDefaultOverlays, getIcon, getNewNodePosition, hideMidpointArrow } from './helpers';
|
||||
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { v4 as uuidv4} from 'uuid';
|
||||
|
@ -145,14 +146,14 @@ import {
|
|||
INodeIssues,
|
||||
INodeTypeDescription,
|
||||
INodeTypeNameVersion,
|
||||
NodeInputConnections,
|
||||
NodeHelpers,
|
||||
Workflow,
|
||||
IRun,
|
||||
ITaskData,
|
||||
INodeCredentialsDetails,
|
||||
INodeExecutionData,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
IConnectionsUi,
|
||||
ICredentialsResponse,
|
||||
IExecutionResponse,
|
||||
IN8nUISettings,
|
||||
|
@ -1329,7 +1330,7 @@ export default mixins(
|
|||
info.connection.setConnector(['Flowchart', { cornerRadius: 8, stub: JSPLUMB_FLOWCHART_STUB, gap: 5, alwaysRespectStubs: false}]);
|
||||
|
||||
addEndpointArrow(info.connection);
|
||||
addOrRemoveMidpointArrow(info.connection);
|
||||
showOrHideMidpointArrow(info.connection);
|
||||
|
||||
// @ts-ignore
|
||||
const sourceInfo = info.sourceEndpoint.getParameters();
|
||||
|
@ -1355,9 +1356,11 @@ export default mixins(
|
|||
const overlay = info.connection.getOverlay('connection-actions');
|
||||
overlay.setVisible(true);
|
||||
|
||||
const arrow = info.connection.getOverlay('midpoint-arrow');
|
||||
if (arrow) {
|
||||
arrow.setVisible(false);
|
||||
hideMidpointArrow(info.connection);
|
||||
|
||||
const itemsOverlay = info.connection.getOverlay('output-items-label');
|
||||
if (itemsOverlay) {
|
||||
itemsOverlay.setVisible(false);
|
||||
}
|
||||
});
|
||||
info.connection.bind('mouseout', (connection: IConnection) => {
|
||||
|
@ -1366,9 +1369,11 @@ export default mixins(
|
|||
overlay.setVisible(false);
|
||||
timer = undefined;
|
||||
|
||||
const arrow = info.connection.getOverlay('midpoint-arrow');
|
||||
if (arrow) {
|
||||
arrow.setVisible(true);
|
||||
showOrHideMidpointArrow(info.connection);
|
||||
|
||||
const itemsOverlay = info.connection.getOverlay('output-items-label');
|
||||
if (itemsOverlay) {
|
||||
itemsOverlay.setVisible(true);
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
@ -1722,7 +1727,128 @@ export default mixins(
|
|||
}) as Connection[];
|
||||
|
||||
[...incoming, ...outgoing].forEach((connection: Connection) => {
|
||||
addOrRemoveMidpointArrow(connection);
|
||||
showOrHideMidpointArrow(connection);
|
||||
});
|
||||
},
|
||||
onNodeRun ({name, data}: {name: string, data: ITaskData[] | null}) {
|
||||
const sourceIndex = this.$store.getters.getNodeIndex(name);
|
||||
const sourceId = `${NODE_NAME_PREFIX}${sourceIndex}`;
|
||||
|
||||
if (data === null || data.length === 0) {
|
||||
// @ts-ignore
|
||||
const outgoing = this.instance.getConnections({
|
||||
source: sourceId,
|
||||
}) as Connection[];
|
||||
|
||||
outgoing.forEach((connection: Connection) => {
|
||||
const arrow = connection.getOverlay('midpoint-arrow');
|
||||
if (arrow) {
|
||||
// @ts-ignore
|
||||
arrow.setLocation(0.5);
|
||||
}
|
||||
|
||||
connection.removeOverlay('output-items-label');
|
||||
connection.setPaintStyle({stroke: getStyleTokenValue('--color-foreground-dark')});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const nodeConnections = (this.$store.getters.outgoingConnectionsByNodeName(name) as INodeConnections).main;
|
||||
if (!nodeConnections) {
|
||||
return;
|
||||
}
|
||||
|
||||
const outputMap: {[sourceEndpoint: string]: {[targetId: string]: {[targetEndpoint: string]: {total: number, iterations: number}}}} = {};
|
||||
|
||||
data.forEach((run: ITaskData) => {
|
||||
if (!run.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
run.data.main.forEach((output: INodeExecutionData[] | null, i: number) => {
|
||||
nodeConnections[i]
|
||||
.map((conn: IConnection) => {
|
||||
const targetIndex = this.getNodeIndex(conn.node);
|
||||
const targetId = `${NODE_NAME_PREFIX}${targetIndex}`;
|
||||
|
||||
const sourceEndpoint = `${sourceIndex}-output${i}`;
|
||||
const targetEndpoint = `${targetIndex}-input${conn.index}`;
|
||||
|
||||
if (!outputMap[sourceEndpoint]) {
|
||||
outputMap[sourceEndpoint] = {};
|
||||
}
|
||||
|
||||
if (!outputMap[sourceEndpoint][targetId]) {
|
||||
outputMap[sourceEndpoint][targetId] = {};
|
||||
}
|
||||
|
||||
if (!outputMap[sourceEndpoint][targetId][targetEndpoint]) {
|
||||
outputMap[sourceEndpoint][targetId][targetEndpoint] = {
|
||||
total: 0,
|
||||
iterations: 0,
|
||||
};
|
||||
}
|
||||
|
||||
outputMap[sourceEndpoint][targetId][targetEndpoint].total += output ? output.length : 0;
|
||||
outputMap[sourceEndpoint][targetId][targetEndpoint].iterations += output ? 1 : 0;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Object.keys(outputMap).forEach((sourceEndpoint: string) => {
|
||||
Object.keys(outputMap[sourceEndpoint]).forEach((targetId: string) => {
|
||||
Object.keys(outputMap[sourceEndpoint][targetId]).forEach((targetEndpoint: string) => {
|
||||
// @ts-ignore
|
||||
const connections = this.instance.getConnections({
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
}) as Connection[];
|
||||
|
||||
const conn = connections.find((connection: Connection) => {
|
||||
// @ts-ignore
|
||||
const uuids = connection.getUuids();
|
||||
return uuids[0] === sourceEndpoint && uuids[1] === targetEndpoint;
|
||||
});
|
||||
|
||||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const output = outputMap[sourceEndpoint][targetId][targetEndpoint];
|
||||
if (!output || !output.total) {
|
||||
conn.setPaintStyle({stroke: getStyleTokenValue('--color-foreground-dark')});
|
||||
conn.removeOverlay('output-items-label');
|
||||
return;
|
||||
}
|
||||
|
||||
conn.setPaintStyle({stroke: getStyleTokenValue('--color-success')});
|
||||
|
||||
if (conn.getOverlay('output-items-label')) {
|
||||
conn.removeOverlay('output-items-label');
|
||||
}
|
||||
|
||||
let label = `${output.total}`;
|
||||
label = output.total > 1 ? `${label} items` : `${label} item`;
|
||||
label = output.iterations > 1 ? `${label} total` : label;
|
||||
|
||||
conn.addOverlay([
|
||||
'Label',
|
||||
{
|
||||
id: 'output-items-label',
|
||||
label,
|
||||
cssClass: 'connection-output-name-label',
|
||||
location: .5,
|
||||
},
|
||||
]);
|
||||
|
||||
const arrow = connections[0].getOverlay('midpoint-arrow');
|
||||
if (arrow) {
|
||||
// @ts-ignore
|
||||
arrow.setLocation(0.6);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
removeNode (nodeName: string) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { JSPLUMB_FLOWCHART_STUB } from "@/constants";
|
||||
import { INodeUi, IZoomConfig, XYPositon } from "@/Interface";
|
||||
import { Connection, OverlaySpec } from "jsplumb";
|
||||
|
||||
|
@ -95,6 +94,7 @@ export const getDefaultOverlays = (): OverlaySpec[] => ([
|
|||
width: 12,
|
||||
foldback: 1,
|
||||
length: 10,
|
||||
visible: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
|
@ -104,46 +104,10 @@ export const getDefaultOverlays = (): OverlaySpec[] => ([
|
|||
label: 'Drop connection<br />to create node',
|
||||
cssClass: 'drop-add-node-label',
|
||||
location: 0.5,
|
||||
visible: false,
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
export const addEndpointArrow = (connection: Connection) => {
|
||||
const hasArrow = !!connection.getOverlay('midpoint-arrow');
|
||||
if (!hasArrow) {
|
||||
connection.addOverlay([
|
||||
'Arrow',
|
||||
{
|
||||
id: 'endpoint-arrow',
|
||||
location: 1,
|
||||
width: 12,
|
||||
foldback: 1,
|
||||
length: 10,
|
||||
},
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
export const addOrRemoveMidpointArrow = (connection: Connection) => {
|
||||
const sourceEndpoint = connection.endpoints[0];
|
||||
const targetEndpoint = connection.endpoints[1];
|
||||
const requiresArrow = sourceEndpoint.anchor.lastReturnValue[0] >= targetEndpoint.anchor.lastReturnValue[0];
|
||||
|
||||
const hasArrow = !!connection.getOverlay('midpoint-arrow');
|
||||
|
||||
if (!requiresArrow) {
|
||||
if (hasArrow) {
|
||||
connection.removeOverlay('midpoint-arrow');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasArrow) {
|
||||
return;
|
||||
}
|
||||
|
||||
connection.addOverlay([
|
||||
[
|
||||
'Arrow',
|
||||
{
|
||||
id: 'midpoint-arrow',
|
||||
|
@ -151,10 +115,42 @@ export const addOrRemoveMidpointArrow = (connection: Connection) => {
|
|||
width: 12,
|
||||
foldback: 1,
|
||||
length: 10,
|
||||
visible: false,
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
export const addEndpointArrow = (connection: Connection) => {
|
||||
connection.addOverlay([
|
||||
'Arrow',
|
||||
{
|
||||
id: 'endpoint-arrow',
|
||||
location: 1,
|
||||
width: 12,
|
||||
foldback: 1,
|
||||
length: 10,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
export const hideMidpointArrow = (connection: Connection) => {
|
||||
const arrow = connection.getOverlay('midpoint-arrow');
|
||||
if (arrow) {
|
||||
arrow.setVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
export const showOrHideMidpointArrow = (connection: Connection) => {
|
||||
const sourceEndpoint = connection.endpoints[0];
|
||||
const targetEndpoint = connection.endpoints[1];
|
||||
const requiresArrow = sourceEndpoint.anchor.lastReturnValue[0] >= targetEndpoint.anchor.lastReturnValue[0];
|
||||
|
||||
const arrow = connection.getOverlay('midpoint-arrow');
|
||||
if (arrow) {
|
||||
arrow.setVisible(requiresArrow);
|
||||
}
|
||||
};
|
||||
|
||||
export const getIcon = (name: string): string => {
|
||||
if (name === 'trash') {
|
||||
return `<svg data-v-66d5c7e2="" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="trash" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-trash fa-w-14 Icon__medium_ctPPJ"><path data-v-66d5c7e2="" fill="currentColor" d="M432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zM53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32z" class=""></path></svg>`;
|
||||
|
|
Loading…
Reference in a new issue