feat: AI nodes usability fixes + Summarization Chain V2 (#7949)

Fixes:
- Refactor connection snapping when dragging and enable it also for
non-main connection types
- Fix propagation of errors from sub-nodes
- Fix chat scrolling when sending/receiving messages
- Prevent empty chat messages
- Fix sub-node selected styles
- Fix output names text overflow

Usability improvements:
- Auto-add manual chat trigger for agents & chain nodes
- Various labels and description updates
- Make the output parser input optional for Basic LLM Chain
- Summarization Chain V2 with a simplified document loader & text
chunking mode

#### How to test the change:
Example workflow showcasing different operation mode of the new
summarization chain:

[Summarization_V2.json](https://github.com/n8n-io/n8n/files/13599901/Summarization_V2.json)


## Issues fixed
Include links to Github issue or Community forum post or **Linear
ticket**:
> Important in order to close automatically and provide context to
reviewers
-
https://www.notion.so/n8n/David-Langchain-Posthog-notes-7a9294938420403095f4508f1a21d31d
- https://linear.app/n8n/issue/N8N-7070/ux-fixes-batch
- https://linear.app/n8n/issue/N8N-7071/ai-sub-node-bugs


## Review / Merge checklist
- [x] PR title and summary are descriptive. **Remember, the title
automatically goes into the changelog. Use `(no-changelog)` otherwise.**
([conventions](https://github.com/n8n-io/n8n/blob/master/.github/pull_request_title_conventions.md))
- [x] [Docs updated](https://github.com/n8n-io/n8n-docs) or follow-up
ticket created.
- [ ] Tests included.
> A bug is not considered fixed, unless a test is added to prevent it
from happening again. A feature is not complete without tests.
  >
> *(internal)* You can use Slack commands to trigger [e2e
tests](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#a39f9e5ba64a48b58a71d81c837e8227)
or [deploy test
instance](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#f6a177d32bde4b57ae2da0b8e454bfce)
or [deploy early access version on
Cloud](https://www.notion.so/n8n/Cloudbot-3dbe779836004972b7057bc989526998?pvs=4#fef2d36ab02247e1a0f65a74f6fb534e).

---------

Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Elias Meire <elias@meire.dev>
This commit is contained in:
oleg
2023-12-08 13:42:32 +01:00
committed by GitHub
parent dbd62a4992
commit dcf12867b3
32 changed files with 1235 additions and 436 deletions

View File

@@ -282,9 +282,9 @@ export const getInputNameOverlay = (
label.innerHTML += ' <strong style="color: var(--color-primary)">*</strong>';
}
label.classList.add('node-input-endpoint-label');
label.classList.add(`node-connection-type-${inputName ?? 'main'}`);
if (inputName !== NodeConnectionType.Main) {
label.classList.add('node-input-endpoint-label--data');
label.classList.add(`node-connection-type-${inputName}`);
}
return label;
},
@@ -317,9 +317,9 @@ export const getOutputNameOverlay = (
if (ep?.__meta?.endpointLabelLength) {
label.setAttribute('data-endpoint-label-length', ep?.__meta?.endpointLabelLength);
}
label.classList.add(`node-connection-type-${getScope(outputName) ?? 'main'}`);
if (outputName !== NodeConnectionType.Main) {
label.classList.add('node-output-endpoint-label--data');
label.classList.add(`node-connection-type-${getScope(outputName)}`);
}
if (category) {
label.classList.add(`node-connection-category-${category}`);
@@ -998,3 +998,61 @@ export const getFixedNodesList = <T extends { position: XYPosition }>(workflowNo
return nodes;
};
/**
* Calculates the intersecting distances of the mouse event coordinates with the given element's boundaries,
* adjusted by the specified offset.
*
* @param {Element} element - The DOM element to check against.
* @param {MouseEvent | TouchEvent} mouseEvent - The mouse or touch event with the coordinates.
* @param {number} offset - Offset to adjust the element's boundaries.
* @returns { {x: number | null, y: number | null} | null } Object containing intersecting distances along x and y axes or null if no intersection.
*/
export function calculateElementIntersection(
element: Element,
mouseEvent: MouseEvent | TouchEvent,
offset: number,
): { x: number | null; y: number | null } | null {
const { top, left, right, bottom } = element.getBoundingClientRect();
const [x, y] = getMousePosition(mouseEvent);
let intersectX: number | null = null;
let intersectY: number | null = null;
if (x >= left - offset && x <= right + offset) {
intersectX = Math.min(x - (left - offset), right + offset - x);
}
if (y >= top - offset && y <= bottom + offset) {
intersectY = Math.min(y - (top - offset), bottom + offset - y);
}
if (intersectX === null && intersectY === null) return null;
return { x: intersectX, y: intersectY };
}
/**
* Checks if the mouse event coordinates intersect with the given element's boundaries,
* adjusted by the specified offset.
*
* @param {Element} element - The DOM element to check against.
* @param {MouseEvent | TouchEvent} mouseEvent - The mouse or touch event with the coordinates.
* @param {number} offset - Offset to adjust the element's boundaries.
* @returns {boolean} True if the mouse coordinates intersect with the element.
*/
export function isElementIntersection(
element: Element,
mouseEvent: MouseEvent | TouchEvent,
offset: number,
): boolean {
const intersection = calculateElementIntersection(element, mouseEvent, offset);
if (intersection === null) {
return false;
}
const isWithinVerticalBounds = intersection.y !== null;
const isWithinHorizontalBounds = intersection.x !== null;
return isWithinVerticalBounds && isWithinHorizontalBounds;
}