mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-05 02:59:27 +02:00
fix(editor): Show error feedback when copying non-duplicatable triggers (#31104)
This commit is contained in:
parent
ec44980689
commit
151fd83e0a
|
|
@ -4815,6 +4815,11 @@ describe('useCanvasOperations', () => {
|
|||
canvasOperations.importWorkflowData(workflowDataToImport, 'paste'),
|
||||
).resolves.not.toThrow();
|
||||
expect(toast.showError).not.toHaveBeenCalled();
|
||||
expect(toast.showMessage).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
title: 'Could not insert node',
|
||||
message: `Only one '${EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE}' node is allowed in a workflow`,
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove connections for nodes filtered out during import', async () => {
|
||||
|
|
@ -5368,6 +5373,39 @@ describe('useCanvasOperations', () => {
|
|||
expect(duplicatedNodeIds).not.toContain('2');
|
||||
});
|
||||
|
||||
it('should show max node type error when duplicating nodes that exceed maxNodes limit', async () => {
|
||||
const toast = useToast();
|
||||
const nodeTypesStore = useNodeTypesStore();
|
||||
const nodeTypeDescription = mockNodeTypeDescription({
|
||||
name: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||
maxNodes: 1,
|
||||
});
|
||||
const node = createTestNode({
|
||||
id: '1',
|
||||
name: 'Execute Workflow Trigger',
|
||||
type: EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE,
|
||||
});
|
||||
|
||||
nodeTypesStore.nodeTypes = {
|
||||
[EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE]: { 1: nodeTypeDescription },
|
||||
};
|
||||
workflowDocumentStoreInstance.allNodes = [node];
|
||||
vi.spyOn(workflowDocumentStoreInstance, 'getNodesByIds').mockReturnValue([node]);
|
||||
vi.mocked(workflowDocumentStoreInstance.outgoingConnectionsByNodeName).mockReturnValue({});
|
||||
|
||||
const workflowObject = createTestWorkflowObject({ nodes: [], connections: {} });
|
||||
vi.mocked(workflowDocumentStoreInstance.createWorkflowObject).mockReturnValue(workflowObject);
|
||||
|
||||
const canvasOperations = useCanvasOperations();
|
||||
await canvasOperations.duplicateNodes(['1']);
|
||||
|
||||
expect(toast.showMessage).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
title: 'Could not insert node',
|
||||
message: `Only one '${EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE}' node is allowed in a workflow`,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not crash when TelemetryHelpers.generateNodesGraph throws error', async () => {
|
||||
const telemetry = useTelemetry();
|
||||
const nodeTypesStore = useNodeTypesStore();
|
||||
|
|
|
|||
|
|
@ -881,6 +881,17 @@ export function useCanvasOperations() {
|
|||
}
|
||||
}
|
||||
|
||||
function showMaxNodeTypeErrorToast(nodeTypeDescription: INodeTypeDescription) {
|
||||
toast.showMessage({
|
||||
type: 'error',
|
||||
title: i18n.baseText('nodeView.showMessage.showMaxNodeTypeError.title'),
|
||||
message: i18n.baseText('nodeView.showMessage.showMaxNodeTypeError.message', {
|
||||
adjustToNumber: nodeTypeDescription.maxNodes,
|
||||
interpolate: { nodeTypeDataDisplayName: nodeTypeDescription.displayName },
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function addNode(
|
||||
node: AddNodeDataWithTypeVersion,
|
||||
nodeTypeDescription: INodeTypeDescription,
|
||||
|
|
@ -2431,6 +2442,7 @@ export function useCanvasOperations() {
|
|||
trackHistory = false,
|
||||
viewport = DEFAULT_VIEWPORT_BOUNDARIES,
|
||||
setStateDirty = true,
|
||||
showMaxNodeTypeError = false,
|
||||
} = {},
|
||||
): Promise<WorkflowDataUpdate> {
|
||||
// Because nodes with the same name maybe already exist, it could
|
||||
|
|
@ -2456,6 +2468,7 @@ export function useCanvasOperations() {
|
|||
let oldName: string;
|
||||
let newName: string;
|
||||
const createNodes: INode[] = [];
|
||||
const skippedMaxNodeTypes = new Map<string, INodeTypeDescription>();
|
||||
|
||||
await nodeHelpers.loadNodesProperties(
|
||||
data.nodes.map((node) => ({ name: node.type, version: node.typeVersion })),
|
||||
|
|
@ -2469,6 +2482,12 @@ export function useCanvasOperations() {
|
|||
// add the name of the existing node
|
||||
// that this one gets linked up instead.
|
||||
nodeNameTable[node.name] = nodeTypesCount[node.type].nodeNames[0];
|
||||
if (showMaxNodeTypeError) {
|
||||
const nodeTypeDescription = nodeTypesStore.getNodeType(node.type, node.typeVersion);
|
||||
if (nodeTypeDescription) {
|
||||
skippedMaxNodeTypes.set(node.type, nodeTypeDescription);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// Node can be created but increment the
|
||||
|
|
@ -2491,6 +2510,10 @@ export function useCanvasOperations() {
|
|||
createNodes.push(node);
|
||||
});
|
||||
|
||||
if (showMaxNodeTypeError) {
|
||||
skippedMaxNodeTypes.forEach(showMaxNodeTypeErrorToast);
|
||||
}
|
||||
|
||||
// Get only the connections of the nodes that get created
|
||||
const newConnections: IConnections = {};
|
||||
const currentConnections = data.connections ?? {};
|
||||
|
|
@ -2800,6 +2823,7 @@ export function useCanvasOperations() {
|
|||
trackHistory,
|
||||
viewport,
|
||||
setStateDirty,
|
||||
showMaxNodeTypeError: source === 'paste' || source === 'duplicate',
|
||||
});
|
||||
|
||||
applyImportedNodeGroups(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user