mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
* N8N-3029 Add Node Type for Wokrflow Stickies/Notes * N8N-3029 Update Content, Update Aliasses * N8N-3030 Created N8N Sticky Component in Design System * N8N-3030 Fixed Code spaccing Sticky Component * N8N-3030 Fixed Code spaccing StickyStories Component * N8N-3030 Fixed Code spaccing Markdown Component * N8N-3030 Added Sticky Colors Pallete into Storybook, Update Color Variables for Sticky Component * N8N-3030 Added Unfocus Event * N8N-3030 Update Default Placeholder, Markdown Styles, Fixed Edit State, Added Text to EditState, Fixed Height of Area, Turned off Resize of textarea * N8N-3030 Update Sticky Overflow, Update Hover States, Updated Markdown Overflow * N8N-3030, N8N-3031 - Add Resize to Sticky, Created N8n-Resize component * N8N-3031 Fixed Importing Components in Editor-ui * N8N-3031 Fixed Resize Component, Fixed Gradient * N8N-3030, N8N-3031 Update Note Description * N8N-3032 Hotfix Building Storybook * N8N-3032 - Select Behaviour, Changes in Resize Component, Emit on Width/Height/Top/Left Change * N8N-3032 Update Resize Component to emmit left/top, Update Dynamic Resize on Selected Background * N8N-3032 Updated / Dragging vs Resizing, prevent open Modal for stickies * N8N-3032 Added ID props to n8n-sticky // dynamic id for multi resizing in NodeView * N8N-3033 Add dynamic size Tooltip on Sticky * N8N-3033 Updated Z-index for Sticky Component * N8N-3033 Updated N8N-Resize Component, Fixed SelectedBackround for Sticky Component * N8N-3033 Refactor * N8N-3033 Focus/Defocus on TextArea * N8N-3033 Fixed Resizing on NW Point * N8N-3030 Save content in vuex on input change * N8N-3033 Fixed Resizer, Save Width and Height in Vue * N8N-3033 Hide Sticky Footer on small height/width * N8N-3033 Fixed Resizer * N8N-3033 Dynamic Z-index for Stickies * N8N-3033 Dynamic Z-index for Stickies * N8N-3033 Removed static z-index for select sticky class * N8N-3034 Added Telemetry * N8N-3030 Formatter * N8N-3030 Format code * N8N-3030 Fixed Selecting Stickies * N8N-3033 Fixed Notifications * N8N-3030 Added new paddings for Default Stickies * N8N-3033 Prevent Scrolling NodeView when Sticky is in Edit mode and Mouse is Over the TextArea * N8N-3030 Prevent double clicking to switch state of Sticky component in Edit Mode * N8N-3033 Fixed Z-index of Stickies * N8N-3033 Prevent delete node when in EditMode * N8N-3030 Prevent Delete Button to delete the Sticky while in Edit Mode * N8N-3030 Change EditMode (emit) on keyboard shortucts, update Markdown Links & Images, Added new props * N8N-3030 Sticky Component - No padding when hiding footer text * N8N-3033 Fix Resizing enter into Edit Mode * N8N-3033 Selecting different nodes - exit the edit mode * N8N-3033 Auto Select Text in text-area by default - Sticky Component * N8N-3033 Prevent Default behaviour for CTRL + X, CTRL + A when Sticky is Active && inEditMode * N8N-3033 Refactor Resizer, Refactor Sticky, Update zIndex inEditMode * N8N-3033 Updated Default Text // Node-base, Storybook * N8N-3033 Add Resizing in EditMode - Components update * N8N-3033 Fixed Footer - Show/Hide on Resize in EditMode * N8N-3033 Fix ActiveSticky on Init * N8N-3033 Refactor Sticky in Vuex, Fixed Init Sticky Tweaks, Prevent Modal Openning, Save on Keyboard shortcuts * Stickies - Update Note node with new props * N8N-3030 Updated Default Note text, Update the Markdown Link * N8N-3030 CMD-C does not copy the text fix * N8N-3030 Fix Max Zoom / Zoom out shortcuts disabled in editState * N8N-3030 Z-index fixed during Edit Mode typing * N8N-3030 Prevent Autoselect Text in Stickies if the text is not default * N8N-3030 Fixed ReadOnly Bugs / Prevent showing Tooltip, Resizing * N8N-3030 Added Sticky Creator Button * N8N-3030 Update Icon / Sticky Creator Button * N8N-3033 Update Sticky Icon / StickyCreator Button * update package lock * 🔩 update note props * 🚿 clean props * 🔧 linting * 🔧 fix spacing * remove resize component * remove resize component * ✂ clean up sticky * revert back to height width * revert back to height/width * replace zindex property * replace default text property * use i18n to translate * update package lock * move resize * clean up how height/width are set * fix resize for sticky to support left/top * clean up resize * fix lasso/highlight bug * remove unused props * fix zoom to fit * fix padding for demo view * fix readonly * remove iseditable, use active state * clean up keyboard events * chang button size, no edit on insert * scale resizing correctly * make active on resize * fix select on resize/move * use outline icon * allow for multiple line breaks * fix multi line bug * fix edit mode outline * keep edit open as one resizes * respect multiple spaces * fix scrolling bug * clean up hover impl * clean up references to note * disable for rename * fix drifting while drag * fix mouse cursor on resize * fix sticky min height * refactor resize into component * fix pulling too far bug * fix delete/cut all bug * fix padding bottom * fix active change on resize * add transition to button * Fix sticky markdown click * add solid fa icon * update node graph, telemetry event * add snapping * change alt text * update package lock * fix bug in button hover * add back transition * clean up resize * add grid size as param * remove breaks * clean up markdown * lint fixes * fix spacing * clean up markdown colors * clean up classes in resize * clean up resize * update sticky story * fix spacing * clean up classes * revert change * revert change * revert change * clean up sticky component * remove unused component * remove unnessary data * remove unnessary data * clean up actions * clean up sticky size * clean up unnessary border style * fix bug * replace sticky note name * update description * remove support for multi spaces * update tracking name * update telemetry reqs * fix enter bug * update alt text * update sticky notes doc url * fix readonly bug * update class name * update quote marks Co-authored-by: SchnapsterDog <olivertrajceski@yahoo.com>
151 lines
4.5 KiB
TypeScript
151 lines
4.5 KiB
TypeScript
/* eslint-disable import/no-cycle */
|
|
import {
|
|
IConnection,
|
|
INode,
|
|
INodeNameIndex,
|
|
INodesGraph,
|
|
INodeGraphItem,
|
|
INodesGraphResult,
|
|
IWorkflowBase,
|
|
INodeTypes,
|
|
} from '.';
|
|
import { INodeType } from './Interfaces';
|
|
|
|
import { getInstance as getLoggerInstance } from './LoggerProxy';
|
|
|
|
const STICKY_NODE_TYPE = 'n8n-nodes-base.stickyNote';
|
|
|
|
export function getNodeTypeForName(workflow: IWorkflowBase, nodeName: string): INode | undefined {
|
|
return workflow.nodes.find((node) => node.name === nodeName);
|
|
}
|
|
|
|
export function isNumber(value: unknown): value is number {
|
|
return typeof value === 'number';
|
|
}
|
|
|
|
function getStickyDimensions(note: INode, stickyType: INodeType | undefined) {
|
|
const heightProperty = stickyType?.description.properties.find(
|
|
(property) => property.name === 'height',
|
|
);
|
|
const widthProperty = stickyType?.description.properties.find(
|
|
(property) => property.name === 'width',
|
|
);
|
|
|
|
const defaultHeight =
|
|
heightProperty && isNumber(heightProperty?.default) ? heightProperty.default : 0;
|
|
const defaultWidth =
|
|
widthProperty && isNumber(widthProperty?.default) ? widthProperty.default : 0;
|
|
|
|
const height: number = isNumber(note.parameters.height) ? note.parameters.height : defaultHeight;
|
|
const width: number = isNumber(note.parameters.width) ? note.parameters.width : defaultWidth;
|
|
|
|
return {
|
|
height,
|
|
width,
|
|
};
|
|
}
|
|
|
|
type XYPosition = [number, number];
|
|
|
|
function areOverlapping(
|
|
topLeft: XYPosition,
|
|
bottomRight: XYPosition,
|
|
targetPos: XYPosition,
|
|
): boolean {
|
|
return (
|
|
targetPos[0] > topLeft[0] &&
|
|
targetPos[1] > topLeft[1] &&
|
|
targetPos[0] < bottomRight[0] &&
|
|
targetPos[1] < bottomRight[1]
|
|
);
|
|
}
|
|
|
|
export function generateNodesGraph(
|
|
workflow: IWorkflowBase,
|
|
nodeTypes: INodeTypes,
|
|
): INodesGraphResult {
|
|
const nodesGraph: INodesGraph = {
|
|
node_types: [],
|
|
node_connections: [],
|
|
nodes: {},
|
|
notes: {},
|
|
};
|
|
const nodeNameAndIndex: INodeNameIndex = {};
|
|
|
|
try {
|
|
const notes = workflow.nodes.filter((node) => node.type === STICKY_NODE_TYPE);
|
|
const otherNodes = workflow.nodes.filter((node) => node.type !== STICKY_NODE_TYPE);
|
|
|
|
notes.forEach((stickyNote: INode, index: number) => {
|
|
const stickyType = nodeTypes.getByNameAndVersion(STICKY_NODE_TYPE, stickyNote.typeVersion);
|
|
const { height, width } = getStickyDimensions(stickyNote, stickyType);
|
|
|
|
const topLeft = stickyNote.position;
|
|
const bottomRight: [number, number] = [topLeft[0] + width, topLeft[1] + height];
|
|
const overlapping = Boolean(
|
|
otherNodes.find((node) => areOverlapping(topLeft, bottomRight, node.position)),
|
|
);
|
|
nodesGraph.notes[index] = {
|
|
overlapping,
|
|
position: topLeft,
|
|
height,
|
|
width,
|
|
};
|
|
});
|
|
|
|
otherNodes.forEach((node: INode, index: number) => {
|
|
nodesGraph.node_types.push(node.type);
|
|
const nodeItem: INodeGraphItem = {
|
|
type: node.type,
|
|
position: node.position,
|
|
};
|
|
|
|
if (node.type === 'n8n-nodes-base.httpRequest') {
|
|
try {
|
|
nodeItem.domain = new URL(node.parameters.url as string).hostname;
|
|
} catch (e) {
|
|
nodeItem.domain = node.parameters.url as string;
|
|
}
|
|
} else {
|
|
const nodeType = nodeTypes.getByNameAndVersion(node.type);
|
|
|
|
nodeType?.description.properties.forEach((property) => {
|
|
if (
|
|
property.name === 'operation' ||
|
|
property.name === 'resource' ||
|
|
property.name === 'mode'
|
|
) {
|
|
nodeItem[property.name] = property.default ? property.default.toString() : undefined;
|
|
}
|
|
});
|
|
|
|
nodeItem.operation = node.parameters.operation?.toString() ?? nodeItem.operation;
|
|
nodeItem.resource = node.parameters.resource?.toString() ?? nodeItem.resource;
|
|
nodeItem.mode = node.parameters.mode?.toString() ?? nodeItem.mode;
|
|
}
|
|
nodesGraph.nodes[`${index}`] = nodeItem;
|
|
nodeNameAndIndex[node.name] = index.toString();
|
|
});
|
|
|
|
const getGraphConnectionItem = (startNode: string, connectionItem: IConnection) => {
|
|
return { start: nodeNameAndIndex[startNode], end: nodeNameAndIndex[connectionItem.node] };
|
|
};
|
|
|
|
Object.keys(workflow.connections).forEach((nodeName) => {
|
|
const connections = workflow.connections[nodeName];
|
|
connections.main.forEach((element) => {
|
|
element.forEach((element2) => {
|
|
nodesGraph.node_connections.push(getGraphConnectionItem(nodeName, element2));
|
|
});
|
|
});
|
|
});
|
|
} catch (e) {
|
|
const logger = getLoggerInstance();
|
|
logger.warn(`Failed to generate nodes graph for workflowId: ${workflow.id as string | number}`);
|
|
logger.warn((e as Error).message);
|
|
logger.warn((e as Error).stack ?? '');
|
|
}
|
|
|
|
return { nodeGraph: nodesGraph, nameIndices: nodeNameAndIndex };
|
|
}
|