diff --git a/package.json b/package.json index ed573845c..408fc4504 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "@ollion/flow-lineage": "workspace:*", "@ollion/flow-log": "workspace:*", "@ollion/flow-md-editor": "workspace:*", - "@ollion/flow-product-icon": "1.14.0", + "@ollion/flow-product-icon": "1.16.0", "@ollion/flow-system-icon": "latest", "@ollion/flow-table": "workspace:*", "d3": "^7.6.1", diff --git a/packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart.ts b/packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart.ts index 2e80bd1fe..a4939e802 100644 --- a/packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart.ts +++ b/packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart.ts @@ -260,6 +260,7 @@ export class FTimeseriesChart extends FRoot { height="hug-content" max-width="320px" class="f-chart-tooltip hide" + data-theme="f-dark" ${ref(this.chartTooltip)} > diff --git a/packages/flow-lineage/package.json b/packages/flow-lineage/package.json index 82bd97566..02b304437 100644 --- a/packages/flow-lineage/package.json +++ b/packages/flow-lineage/package.json @@ -22,13 +22,14 @@ "dependencies": { "@ollion/flow-core": "workspace:*", "@ollion/flow-core-config": "workspace:*", - "d3": "^7.6.1", + "d3": "^7.8.4", + "d3-dag": "^1.1.0", "lit": "^3.1.0" }, "devDependencies": { "@custom-elements-manifest/analyzer": "^0.5.7", "@open-wc/testing": "^3.1.5", - "@types/d3": "^7.4.0", + "@types/d3": "^7.4.3", "@types/jest": "29.5.5", "@web/dev-server-esbuild": "^0.3.0", "@web/test-runner": "^0.13.30", diff --git a/packages/flow-lineage/src/components/f-dag/add-group.ts b/packages/flow-lineage/src/components/f-dag/add-group.ts new file mode 100644 index 000000000..02964fc46 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/add-group.ts @@ -0,0 +1,115 @@ +import { html } from "lit"; +import type { FDag } from "./f-dag"; +import type { FInput, FSelect, FTabNode } from "@ollion/flow-core"; + +export function addGroupPopover(this: FDag) { + const closeAddPopover = () => { + this.addGroupPopoverRef.open = false; + }; + + const addSelectionToGroup = (groupid: string) => { + this.selectedNodes.forEach(sn => { + sn.group = groupid; + }); + + this.addGroupPopoverRef.open = false; + + this.resetPlacements(); + this.selectedNodes = []; + this.addGroupButton.style.display = "none"; + this.requestUpdate(); + }; + + const addToNewGroup = () => { + const groupIdInput = this.querySelector("#new-group-id")!; + const groupLabelInput = this.querySelector("#new-group-label")!; + const parentGroupIfAny = this.selectedNodes[0].group; + + const isAllFromSameGroup = this.selectedNodes.every(sn => sn.group === parentGroupIfAny); + this.config.groups.push({ + id: groupIdInput.value as string, + label: groupLabelInput.value as string, + icon: "i-org", + group: isAllFromSameGroup && parentGroupIfAny ? parentGroupIfAny : undefined + }); + + addSelectionToGroup(groupIdInput.value as string); + }; + + const addToGroup = () => { + const groupDropdown = this.querySelector(`#f-group-dropdown`)!; + const groupid = groupDropdown.value as string; + + addSelectionToGroup(groupid); + }; + + const switchTab = (event: PointerEvent) => { + const tabNodeElement = event.currentTarget as FTabNode; + + this.querySelectorAll(`.gr-selection-tabs`).forEach(tab => { + tab.active = false; + }); + tabNodeElement.active = true; + }; + return html` + e.stopPropagation()}> + + + + Exisiting + + + + + Create New + + + + + + g.id)} + > + + + + + + + + + + + + + + + + + + + + `; +} + +export function handleAddGroup(this: FDag) { + this.addGroupPopoverRef.open = true; +} diff --git a/packages/flow-lineage/src/components/f-dag/background-svg.ts b/packages/flow-lineage/src/components/f-dag/background-svg.ts new file mode 100644 index 000000000..364db0559 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/background-svg.ts @@ -0,0 +1,22 @@ +import { html } from "lit"; + +export default function backgroundSVG() { + return html` + + + + + `; +} diff --git a/packages/flow-lineage/src/components/f-dag/compute-placement.ts b/packages/flow-lineage/src/components/f-dag/compute-placement.ts new file mode 100644 index 000000000..4cef6d810 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/compute-placement.ts @@ -0,0 +1,244 @@ +import type { FDag } from "./f-dag"; +import buildHierarchy from "./hierarchy-builder"; +import { + CustomPlacementByElement, + CustomPlacementBySection, + FDagElement, + FDagGroup, + HierarchyNode +} from "./types"; + +export default function computePlacement(this: FDag) { + this.groupsHTML = []; + this.nodesHTML = []; + + const { roots: rootNodes, customPlacements } = buildHierarchy(this.config); + + const positionNodes = ( + containerId: string, + elements: HierarchyNode[], + x: number, + y: number, + isCollapsed: boolean, + spaceX = 100, + spaceY = 100 + ) => { + const elementIds = elements.map(e => e.id); + const conatinerElementObject = this.getElement(containerId) as FDagGroup; + const layoutDirection = (() => { + if (containerId === "root") { + return this.config.layoutDirection; + } + if (conatinerElementObject.layoutDirection === "vertical") { + return "horizontal"; + } + return "vertical"; + })(); + const nodeLinks = this.config.links.filter( + l => elementIds.includes(l.from.elementId) && elementIds.includes(l.to.elementId) + ); + const roots = new Set(elements); + const nonroots = new Set(); + for (const link of nodeLinks) { + const fromElement = elements.find(e => e.id === link.from.elementId)!; + if (!nonroots.has(fromElement)) { + roots.add(fromElement); + } + if (!fromElement.next) { + fromElement.next = []; + } + + const toElement = elements.find(e => e.id === link.to.elementId)!; + if (roots.has(toElement)) { + roots.delete(toElement); + } + nonroots.add(toElement); + fromElement.next.push(toElement); + } + + const initialY = y; + const initialX = x; + let maxX = 0; + let maxY = 0; + const minX = x; + const minY = y; + let section = 0; + const calculateCords = (ns: HierarchyNode[]) => { + const nexts: HierarchyNode[] = []; + let maxWidth = this.defaultElementWidth; + let maxHeight = this.defaultElementHeight; + section += 1; + const nextSection = () => { + if (!isCollapsed) { + if (layoutDirection === "vertical") { + y += maxHeight + spaceY; + x = initialX; + } else { + x += maxWidth + spaceX; + y = initialY; + } + } + }; + + let currentNodeId: string | null; + const isElementPlacement = (elementObject: FDagElement) => + elementObject.placement && + (elementObject.placement as CustomPlacementByElement).elementId === currentNodeId; + const isSectionPlacement = (elementObject: FDagElement) => + elementObject.placement && + (elementObject.placement as CustomPlacementBySection).section === section && + containerId === "root"; + const placeElement = (n: HierarchyNode) => { + const elementObject = this.getElement(n.id); + if ( + !elementObject.placement || + isSectionPlacement(elementObject) || + isElementPlacement(elementObject) + ) { + const customPlacementsByElements = this.getCustomPlacementElementsByElementId( + elementObject.id, + customPlacements + ); + if (customPlacementsByElements.length > 0) { + currentNodeId = elementObject.id; + } + const beforeCustomElements = customPlacementsByElements.filter( + c => c?.placement?.position === "before" + ); + const afterCustomElements = customPlacementsByElements.filter( + c => c?.placement?.position === "after" + ); + for (const b of beforeCustomElements) { + if (b) placeElement(b); + } + + if (elementObject.x === undefined) { + elementObject.x = x; + } else { + x = elementObject.x; + } + if (elementObject.y === undefined) { + elementObject.y = y; + } else { + y = elementObject.y; + } + + if (n.type === "group" && n.children && n.children.length > 0) { + const isCollapseRequired = + isCollapsed || Boolean((elementObject as FDagGroup).collapsed); + const { width, height } = positionNodes( + n.id, + n.children, + isCollapseRequired ? x : x + 20, + isCollapseRequired ? y : y + 60, + isCollapseRequired, + (elementObject as FDagGroup).spacing?.x, + (elementObject as FDagGroup).spacing?.y + ); + if (isCollapsed) { + elementObject.hidden = true; + } else { + elementObject.hidden = false; + } + elementObject.width = width < 150 ? 150 : width; + elementObject.height = height + (isCollapseRequired ? 0 : 20); + } else if (isCollapsed) { + elementObject.hidden = true; + } else { + elementObject.hidden = false; + } + + if (!elementObject.width) { + elementObject.width = this.defaultElementWidth; + } + if (!elementObject.height) { + elementObject.height = this.defaultElementHeight; + } + + if (n.type === "group") { + this.groupsHTML.push(this.getNodeGroupTemplate(elementObject, "group")); + } else { + this.nodesHTML.push(this.getNodeGroupTemplate(elementObject)); + } + + if (x + elementObject.width > maxX) { + maxX = x + elementObject.width; + } + if (y + elementObject.height > maxY) { + maxY = y + elementObject.height; + } + + if (!isCollapsed) { + if (layoutDirection === "vertical") { + x += elementObject.width + spaceX; + } else { + y += elementObject.height + spaceY; + } + } + + if (elementObject.width > maxWidth) { + maxWidth = elementObject.width; + } + if (elementObject.height > maxHeight) { + maxHeight = elementObject.height; + } + + for (const b of afterCustomElements) { + if (b) placeElement(b); + } + currentNodeId = null; + if (n.next) nexts.push(...n.next); + } + }; + const customPlacementsElements = + containerId === "root" ? this.getCustomPlacementElements(section, customPlacements) : []; + + const beforeElements = + containerId === "root" + ? customPlacementsElements.filter(c => c?.placement?.position === "before") + : []; + const afterElements = + containerId === "root" + ? customPlacementsElements.filter(c => c?.placement?.position === "after") + : []; + for (const b of beforeElements) { + if (b) placeElement(b); + } + + if (beforeElements.length > 0) { + nextSection(); + maxHeight = this.defaultElementHeight; + maxWidth = this.defaultElementWidth; + } + + const skipTheseElements = [...beforeElements, ...afterElements].map(ba => ba?.id); + ns.filter(n => !skipTheseElements.includes(n.id)).forEach(placeElement); + + if (afterElements.length > 0) { + nextSection(); + maxHeight = this.defaultElementHeight; + maxWidth = this.defaultElementWidth; + } + for (const b of afterElements) { + if (b) placeElement(b); + } + nextSection(); + + if (nexts.length > 0) calculateCords(nexts); + }; + calculateCords(Array.from(roots)); + if (isCollapsed) { + return { + width: this.collapsedNodeWidth, + height: this.collapsedNodeHeight + }; + } + + return { + width: maxX - minX + 40, + height: maxY - minY + 60 + }; + }; + + positionNodes("root", rootNodes, 0, 0, false, this.config.spacing?.x, this.config.spacing?.y); +} diff --git a/packages/flow-lineage/src/components/f-dag/connect-link.ts b/packages/flow-lineage/src/components/f-dag/connect-link.ts new file mode 100644 index 000000000..b0eaeb800 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/connect-link.ts @@ -0,0 +1,330 @@ +import * as d3 from "d3"; +import type { FDag } from "./f-dag"; +import { CoOrdinates, FDagLink, FDagLinkDirection } from "./types"; +import curveStep from "./curve-steps"; + +export function startPlottingLine(this: FDag, event: MouseEvent) { + event.stopPropagation(); + this.allGroupsAndNodes?.forEach(n => { + n.style.pointerEvents = "none"; + }); + const circle = event.currentTarget as HTMLElement; + const elementId = circle.dataset.nodeId; + + const elementObject = this.getElement(elementId!); + let x1 = elementObject.x; + let y1 = elementObject.y; + + if (circle.classList.contains("right")) { + x1! += elementObject.width!; + y1! += event.offsetY; + } + if (circle.classList.contains("bottom")) { + y1! += elementObject.height!; + x1! += event.offsetX; + } + if (circle.classList.contains("left")) { + y1! += event.offsetY; + } + if (circle.classList.contains("top")) { + x1! += event.offsetX; + } + + const svg = d3.select(this.linksSVG); + + const direction = + circle.classList.contains("right") || circle.classList.contains("left") + ? "horizontal" + : "vertical"; + const link: FDagLink = { + from: { + x: x1, + y: y1, + elementId: circle.dataset.nodeId! + }, + to: { + x: x1, + y: y1, + elementId: `` + }, + direction + }; + + this.currentLine = svg + .append("path") + .datum(link) + .attr("class", "dag-line") + .attr("id", `${circle.dataset.nodeId}->`) + .attr("d", d => { + const points: CoOrdinates[] = []; + points.push({ + x: d.from.x, + y: d.from.y + }); + points.push({ + x: d.to.x, + y: d.to.y + }); + + return this.generatePath(points, d.direction); + }) + .attr("stroke", "var(--color-primary-default)"); + + this.currentArrow = svg + .append("text") + .datum(link) + .attr("class", "link-arrow") + .attr("id", function (d) { + return `${d.from.elementId}~arrow`; + }) + .attr("stroke", "var(--color-surface-default)") + .attr("stroke-width", "1px") + .attr("dy", 5.5) + .attr("dx", 2) + .append("textPath") + .attr("text-anchor", "end") + + .attr("xlink:href", function (_d) { + return `#${circle.dataset.nodeId}->`; + }) + .attr("startOffset", "100%") + .attr("fill", "var(--color-primary-default)") + .text("▶"); +} +export function updateLinePath(this: FDag, event: MouseEvent) { + if (event.buttons === 1 && this.currentLine) { + event.stopPropagation(); + this.currentLine.attr("d", d => { + d.to.x! += event.movementX * (1 / this.scale); + d.to.y! += event.movementY * (1 / this.scale); + + const points: CoOrdinates[] = []; + points.push({ + x: d.from.x, + y: d.from.y + }); + points.push({ + x: d.to.x, + y: d.to.y + }); + + return this.generatePath(points, d.direction); + }); + } else { + this.allGroupsAndNodes?.forEach(n => { + n.style.pointerEvents = "all"; + }); + this.currentLine?.remove(); + this.currentLine = undefined; + this.currentArrow?.remove(); + this.currentArrow = undefined; + } +} +export function dropLine(this: FDag, event: MouseEvent) { + const circle = event.currentTarget as HTMLElement; + + this.allGroupsAndNodes?.forEach(n => { + n.style.pointerEvents = "all"; + }); + if (this.currentLine) { + const linkElement = this.currentLine; + const fromNodeId = linkElement.attr("id").replace(/(->)$/, ""); + const toNodeId = circle.dataset.nodeId!; + + const elementObject = this.getElement(toNodeId); + let x2 = elementObject.x; + let y2 = elementObject.y; + + if (circle.classList.contains("right")) { + x2! += elementObject.width!; + y2! += event.offsetY; + } + if (circle.classList.contains("bottom")) { + y2! += elementObject.height!; + x2! += event.offsetX; + } + if (circle.classList.contains("left")) { + y2! += event.offsetY; + } + if (circle.classList.contains("top")) { + x2! += event.offsetX; + } + + this.currentLine + .attr("id", function () { + return linkElement.attr("id") + circle.dataset.nodeId; + }) + .attr("d", d => { + d.to.x = x2; + d.to.y = y2; + d.to.elementId = circle.dataset.nodeId!; + const points: CoOrdinates[] = []; + points.push({ + x: d.from.x, + y: d.from.y + }); + points.push({ + x: d.to.x, + y: d.to.y + }); + + return this.generatePath(points, d.direction); + }) + .attr("stroke", "var(--color-border-default)"); + if (this.currentArrow) { + this.currentArrow + .attr("xlink:href", function (_d) { + return `#${linkElement.attr("id")}`; + }) + .attr("fill", "var(--color-border-default)"); + } + + this.updateLink( + fromNodeId, + toNodeId, + linkElement.datum().from.x, + linkElement.datum().from.y, + linkElement.datum().to.x, + linkElement.datum().to.y, + linkElement.datum().direction + ); + + this.currentLine = undefined; + this.currentArrow = undefined; + } +} + +export function updateLink( + this: FDag, + fromNodeId: string, + toNodeId: string, + x1: number = 0, + y1: number = 0, + x2: number = 0, + y2: number = 0, + direction: FDagLinkDirection = "horizontal" +) { + let linkObject = this.config.links.find( + l => l.from.elementId === fromNodeId && l.to.elementId === toNodeId + ); + + if (!linkObject) { + linkObject = { + from: { + elementId: fromNodeId, + x: x1, + y: y1 + }, + to: { + elementId: toNodeId, + x: x2, + y: y2 + }, + direction + }; + + this.config.links.push(linkObject); + } else { + linkObject.from = { + elementId: fromNodeId, + x: x1, + y: y1 + }; + linkObject.to = { + elementId: toNodeId, + x: x2, + y: y2 + }; + } +} + +export function generatePath( + this: FDag, + points: CoOrdinates[], + linkDirection: FDagLinkDirection = "horizontal" +) { + const { x: sx, y: sy } = points[0]; + const { x: dx, y: dy } = points[1]; + + if ( + linkDirection === "vertical" && + sx !== undefined && + sy !== undefined && + dx !== undefined && + dy !== undefined + ) { + const points = [ + { + x: sx, + y: sy + }, + { + x: sx, + y: (sy + dy) / 2 + }, + { + x: dx, + y: (sy + dy) / 2 + }, + { + x: dx, + y: dy + } + ]; + const angle = Math.abs(dx - sx) >= 24 ? 12 : Math.abs(dx - sx) / 2; + if (sy > dy) { + const rVLine = d3 + .line() + .x(p => p.x!) + .y(p => p.y!) + //@ts-expect-error @todo vikas to check + .curve(curveStep.angle(angle, "vertical-reverse")); + return rVLine(points)!; + } + const vLine = d3 + .line() + .x(p => p.x!) + .y(p => p.y!) + //@ts-expect-error @todo vikas to check + .curve(curveStep.angle(angle, "vertical")); + return vLine(points)!; + } else if (sx !== undefined && sy !== undefined && dx !== undefined && dy !== undefined) { + const points = [ + { + x: sx, + y: sy + }, + { + x: (sx + dx) / 2, + y: sy + }, + { + x: (sx + dx) / 2, + y: dy + }, + { + x: dx, + y: dy + } + ]; + const angle = Math.abs(dy - sy) >= 24 ? 12 : Math.abs(dy - sy) / 2; + + if (sx > dx) { + const rHLine = d3 + .line() + .x(p => p.x!) + .y(p => p.y!) + //@ts-expect-error @todo vikas to check + .curve(curveStep.angle(angle, "horizontal-reverse")); + return rHLine(points)!; + } + const hLine = d3 + .line() + .x(p => p.x!) + .y(p => p.y!) + //@ts-expect-error @todo vikas to check + .curve(curveStep.angle(angle, "horizontal")); + return hLine(points)!; + } + return ``; +} diff --git a/packages/flow-lineage/src/components/f-dag/curve-steps.ts b/packages/flow-lineage/src/components/f-dag/curve-steps.ts new file mode 100644 index 000000000..7e247dfab --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/curve-steps.ts @@ -0,0 +1,140 @@ +class Step { + private _context: CanvasRenderingContext2D; + private _curve: number; + private _line: number; + private _x?: number; + private _y?: number; + private _point?: number; + private _lastX?: number; + private _lastY?: number; + private _direction?: CurveDirection; + + constructor(context: CanvasRenderingContext2D, curve: number, direction?: CurveDirection) { + this._context = context; + this._curve = curve; + this._line = NaN; + this._direction = direction; + } + + /** + * Initialize the area. + */ + areaStart() { + this._line = 0; + } + + /** + * End the area. + */ + areaEnd() { + this._line = NaN; + } + + /** + * Start a new line. + */ + lineStart() { + this._x = this._y = NaN; + this._point = 0; + } + + /** + * End the current line. + */ + lineEnd() { + if (this._x !== undefined && this._y !== undefined) { + this._context.lineTo(this._x, this._y); + } + } + + /** + * Add a point to the line. + * @param x - The x-coordinate of the point. + * @param y - The y-coordinate of the point. + */ + point(x: number, y: number) { + (x = +x), (y = +y); + switch (this._point) { + case 0: + this._point = 1; + this._context.moveTo(x, y); + break; + case 1: + this._point = 2; + this._lastX = x; + this._lastY = y; + if (this._direction === "vertical") { + this._context.lineTo(x, y - this._curve); + } else if (this._direction === "vertical-reverse") { + this._context.lineTo(x, y + this._curve); + } else if (this._direction === "horizontal-reverse") { + this._context.lineTo(x + this._curve, y); + } else { + this._context.lineTo(x - this._curve, y); + } + break; + default: { + if ( + this._lastX !== undefined && + this._lastY !== undefined && + (this._lastX !== x || this._lastY !== y) + ) { + let nextY = y; + let nextX = x; + if (y < this._lastY && this._lastX === x) { + nextY = this._lastY - this._curve; + this._context.arcTo(this._lastX, this._lastY, this._lastX, nextY, this._curve); + this._context.lineTo(x, y + this._curve); + } else if (y > this._lastY && this._lastX === x) { + nextY = this._lastY + this._curve; + this._context.arcTo(this._lastX, this._lastY, this._lastX, nextY, this._curve); + this._context.lineTo(x, y - this._curve); + } else if (x > this._lastX && this._lastY === y) { + nextX = this._lastX + this._curve; + this._context.arcTo(this._lastX, this._lastY, nextX, this._lastY, this._curve); + this._context.lineTo(x - this._curve, y); + } else if (x < this._lastX && this._lastY === y) { + nextX = this._lastX - this._curve; + this._context.arcTo(this._lastX, this._lastY, nextX, this._lastY, this._curve); + this._context.lineTo(x + this._curve, y); + } else { + this._context.lineTo(x, y); + } + } else { + this._context.lineTo(x, y); + } + this._lastX = x; + this._lastY = y; + break; + } + } + (this._x = x), (this._y = y); + } +} + +type CurveDirection = "horizontal" | "vertical" | "vertical-reverse" | "horizontal-reverse"; + +/** + * A factory function that creates a curved step function. + * @param angle - The angle for curves. + * @returns A function to create curved steps. + */ +function curvedStep(angle: number, direction?: CurveDirection) { + function createStep(context: CanvasRenderingContext2D) { + return new Step(context, angle, direction); + } + + /** + * Set a new angle for curves. + * @param angle - The new angle for curves. + * @returns A curved step function with the specified angle. + */ + createStep.angle = function (angle: number, direction?: CurveDirection) { + return curvedStep(+angle, direction); + }; + + return createStep; +} + +// Export the curvedStep function +export default curvedStep(12); diff --git a/packages/flow-lineage/src/components/f-dag/drag-nodes-and-groups.ts b/packages/flow-lineage/src/components/f-dag/drag-nodes-and-groups.ts new file mode 100644 index 000000000..e52121483 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/drag-nodes-and-groups.ts @@ -0,0 +1,225 @@ +import * as d3 from "d3"; +import type { CoOrdinates, FDagLink } from "./types"; +import type { FDag } from "./f-dag"; + +export function getTranslateValues(element: HTMLElement) { + const style = window.getComputedStyle(element); + const matrix = new DOMMatrixReadOnly(style.transform); + + // Extract translateX and translateY values + const translateX = matrix.m41; + const translateY = matrix.m42; + + return { translateX, translateY }; +} + +export function moveElement(this: FDag, nodeElement: HTMLElement, event: MouseEvent) { + let translateX = nodeElement.dataset.lastTranslateX + ? +nodeElement.dataset.lastTranslateX + : undefined; + let translateY = nodeElement.dataset.lastTranslateY + ? +nodeElement.dataset.lastTranslateY + : undefined; + if (!translateX || !translateY) { + const translate = getTranslateValues(nodeElement); + translateX = translate.translateX; + translateY = translate.translateY; + } + + const newTranslateX = translateX + event.movementX * (1 / this.scale); + const newTranslateY = translateY + event.movementY * (1 / this.scale); + nodeElement.style.setProperty("transform", `translate(${newTranslateX}px, ${newTranslateY}px)`); + + const elementObject = this.getElement(nodeElement.getAttribute("id")!); + elementObject.x = newTranslateX; + elementObject.y = newTranslateY; + + nodeElement.dataset.lastTranslateX = `${newTranslateX}`; + nodeElement.dataset.lastTranslateY = `${newTranslateY}`; + const fromLines = d3.selectAll( + `.dag-line[id^="${nodeElement.getAttribute("id")}->"]` + ); + + fromLines.datum(d => { + if (!d.from.x) { + d.from.x = 0; + } + if (!d.from.y) { + d.from.y = 0; + } + return { + ...d, + from: { + x: (d.from.x += event.movementX * (1 / this.scale)), + y: (d.from.y += event.movementY * (1 / this.scale)), + elementId: d.from.elementId + } + }; + }); + + fromLines.attr("d", d => { + const points: CoOrdinates[] = []; + points.push({ + x: d.from.x, + y: d.from.y + }); + points.push({ + x: d.to.x, + y: d.to.y + }); + + return this.generatePath(points, d.direction); + }); + + const toLines = d3.selectAll( + `.dag-line[id$="->${nodeElement.getAttribute("id")}"]` + ); + + toLines.datum(d => { + if (!d.to.x) { + d.to.x = 0; + } + if (!d.to.y) { + d.to.y = 0; + } + return { + ...d, + to: { + x: (d.to.x += event.movementX * (1 / this.scale)), + y: (d.to.y += event.movementY * (1 / this.scale)), + elementId: d.to.elementId + } + }; + }); + toLines.attr("d", d => { + const points: CoOrdinates[] = []; + + points.push({ + x: d.from.x, + y: d.from.y + }); + points.push({ + x: d.to.x, + y: d.to.y + }); + + return this.generatePath(points, d.direction).toString(); + }); +} + +export function dragNestedGroups(this: FDag, groupElement: HTMLElement, event: MouseEvent) { + if (groupElement.dataset.nodeType === "group") { + const groupNodes = this.querySelectorAll( + `[data-group="${groupElement.getAttribute("id")}"]` + ); + groupNodes.forEach(gn => { + this.moveElement(gn, event); + this.dragNestedGroups(gn, event); + }); + } +} +export function dragNode(this: FDag, event: MouseEvent) { + event.stopPropagation(); + if (event.buttons === 1 && this.currentLine === undefined) { + const nodeElement = event.currentTarget as HTMLElement; + nodeElement.style.zIndex = `3`; + nodeElement.classList.add("dragging"); + if (nodeElement) { + this.moveElement(nodeElement, event); + this.dragNestedGroups(nodeElement, event); + } + } +} + +export function updateNodePosition(this: FDag, event: MouseEvent) { + const nodeElement = event.currentTarget as HTMLElement; + const { + top: nodeTop, + height: nodeHeight, + left: nodeLeft, + width: nodeWidth + } = nodeElement.getBoundingClientRect(); + if (nodeElement.dataset.nodeType === "group") { + nodeElement.style.zIndex = `1`; + } else { + nodeElement.style.zIndex = `2`; + } + nodeElement.classList.remove("dragging"); + const allGroupsAndNodes = this.querySelectorAll(`[data-node-type="group"]`); + let insideGroup = false; + let placedIn: HTMLElement | undefined; + const lastGroup = nodeElement.dataset.group; + for (let index = 0; index < allGroupsAndNodes.length; index++) { + const group = allGroupsAndNodes.item(index); + const { top, height, left, width } = group.getBoundingClientRect(); + if ( + nodeTop > top && + nodeLeft > left && + nodeTop + nodeHeight < top + height && + nodeLeft + nodeWidth < left + width + ) { + insideGroup = true; + placedIn = group; + nodeElement.dataset.group = group.getAttribute("id")!; + } + } + + if (!insideGroup) { + delete nodeElement.dataset.group; + } else if (placedIn && lastGroup !== nodeElement.dataset.group) { + placedIn.classList.add("dropped"); + + setTimeout(() => { + placedIn?.classList.remove("dropped"); + }, 1000); + } + + let elementConfig; + if (nodeElement.dataset.nodeType === "group") { + elementConfig = this.config.groups.find(n => n.id === nodeElement.getAttribute("id")); + } else { + elementConfig = this.config.nodes.find(n => n.id === nodeElement.getAttribute("id")); + } + + if (elementConfig) { + elementConfig.group = nodeElement.dataset.group; + const { translateX, translateY } = getTranslateValues(nodeElement); + elementConfig.x = translateX; + elementConfig.y = translateY; + } + + const fromLines = d3.selectAll( + `.dag-line[id^="${nodeElement.getAttribute("id")}->"]` + ); + const toLines = d3.selectAll( + `.dag-line[id$="->${nodeElement.getAttribute("id")}"]` + ); + + // eslint-disable-next-line @typescript-eslint/no-this-alias + const that = this; + fromLines.each(function (d) { + that.updateLink( + d.from.elementId, + d.to.elementId, + d.from.x, + d.from.y, + d.to.x, + d.to.y, + d.direction + ); + }); + + toLines.each(function (d) { + that.updateLink( + d.from.elementId, + d.to.elementId, + d.from.x, + d.from.y, + d.to.x, + d.to.y, + d.direction + ); + }); + + console.log(this.config); +} diff --git a/packages/flow-lineage/src/components/f-dag/draw-links.ts b/packages/flow-lineage/src/components/f-dag/draw-links.ts new file mode 100644 index 000000000..a77791e7c --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/draw-links.ts @@ -0,0 +1,205 @@ +import * as d3 from "d3"; +import type { FDag } from "./f-dag"; +import { CoOrdinates, FDagLink } from "./types"; + +export default function drawLinks(this: FDag) { + const getConnectingPosition = ( + id: string, + side: "left" | "right" | "top" | "bottom", + size: number + ) => { + const element = this.querySelector(`#${id}`)!; + let connectionCount: number = Number(element.dataset[side]); + if (!connectionCount) { + connectionCount = 0; + } + let point = size / 2; + if (connectionCount % 2 !== 0) { + point = size / 2 - connectionCount * 12; + } + + element.dataset[side] = `${connectionCount + 1}`; + if (point > size || point < 0) { + return size / 2; + } + return point; + }; + + // cloning because d3 is not re-drawing links + const links = structuredClone(this.config.links); + const svg = d3.select(this.linksSVG); + svg.html(``); + svg + .selectAll("path.dag-line") + .data(links) + .join("path") + .attr("class", "dag-line") + .attr("id", d => { + return `${d.from.elementId}->${d.to.elementId}`; + }) + .attr("d", d => { + const points: CoOrdinates[] = []; + + if (!d.to.x && !d.to.y && !d.from.x && !d.from.y) { + const fromElement = this.getElement(d.from.elementId); + d.from.x = fromElement.x; + d.from.y = fromElement.y; + + const toElement = this.getElement(d.to.elementId); + d.to.x = toElement.x; + d.to.y = toElement.y; + + const fromWidth = fromElement.hidden ? this.collapsedNodeWidth : fromElement.width; + const fromHeight = fromElement.hidden ? this.collapsedNodeHeight : fromElement.height; + const toWidth = toElement.hidden ? this.collapsedNodeWidth : toElement.width; + const toHeight = toElement.hidden ? this.collapsedNodeHeight : toElement.height; + + if (this.config.layoutDirection === "horizontal") { + d.direction = "horizontal"; + if (d.to.x! > d.from.x!) { + d.from.x! += fromWidth!; + d.from.y! += getConnectingPosition(d.from.elementId, "right", fromHeight!); + d.to.y! += getConnectingPosition(d.to.elementId, "left", toHeight!); + } else { + d.from.y! += getConnectingPosition(d.from.elementId, "left", fromHeight!); + d.to.x! += toWidth!; + d.to.y! += getConnectingPosition(d.to.elementId, "right", fromHeight!); + } + } else { + d.direction = "vertical"; + if (d.to.y! > d.from.y!) { + d.from.x! += getConnectingPosition(d.from.elementId, "bottom", fromWidth!); + d.from.y! += fromHeight!; + d.to.x! += getConnectingPosition(d.to.elementId, "top", toWidth!); + } else { + d.from.x! += getConnectingPosition(d.from.elementId, "top", fromWidth!); + d.to.x! += getConnectingPosition(d.to.elementId, "bottom", toWidth!); + d.to.y! += toHeight!; + } + } + } + if (!d.direction) { + if (this.config.layoutDirection === "horizontal") { + d.direction = "horizontal"; + } else { + d.direction = "vertical"; + } + } + points.push({ + x: d.from.x, + y: d.from.y + }); + points.push({ + x: d.to.x, + y: d.to.y + }); + + return this.generatePath(points, d.direction)!.toString(); + }) + .attr("stroke", d => { + const fromElement = this.getElement(d.from.elementId); + + const toElement = this.getElement(d.to.elementId); + if (fromElement.hidden || toElement.hidden) { + return "var(--color-border-secondary)"; + } + return "var(--color-border-default)"; + }) + .attr("stroke-dasharray", d => { + const fromElement = this.getElement(d.from.elementId); + + const toElement = this.getElement(d.to.elementId); + if (fromElement.hidden || toElement.hidden) { + return "4 4"; + } + return "0"; + }); + + svg + .selectAll("text.link-arrow") + .data(links) + .join("text") + .attr("class", "link-arrow") + .attr("id", function (d) { + return `${d.from.elementId}~arrow`; + }) + .attr("stroke", "var(--color-surface-default)") + .attr("stroke-width", "1px") + .attr("dy", 5.5) + .attr("dx", 2) + .append("textPath") + .attr("text-anchor", "end") + + .attr("xlink:href", function (d) { + return `#${d.from.elementId}->${d.to.elementId}`; + }) + .attr("startOffset", "100%") + .attr("fill", d => { + const fromElement = this.getElement(d.from.elementId); + + const toElement = this.getElement(d.to.elementId); + if (fromElement.hidden || toElement.hidden) { + return "var(--color-border-secondary)"; + } + return "var(--color-border-default)"; + }) + + .text("▶"); + + const defs = svg.append("defs"); + const lg = defs + .append("linearGradient") + .attr("id", "animate-gradient") //unique id for reference + .attr("gradientUnits", "userSpaceOnUse") + .attr("x1", "0%") + .attr("y1", "0%") + .attr("x2", "100%") + .attr("y2", "100%") + .attr("spreadMethod", "reflect"); + + const co = [ + "var(--color-primary-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-primary-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-primary-default)", + "var(--color-primary-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-primary-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-border-default)", + "var(--color-primary-default)" + ]; + + lg.selectAll(".stop") + .data(co) + .enter() + .append("stop") + // .attr("offset", function (d, i) { return i / (co.length - 1); }) + .attr("offset", function (d, i) { + return i / (co.length - 1); + }) + .attr("stop-color", function (d) { + return d; + }); + + lg.append("animate") + .attr("attributeName", "x1") + .attr("values", "0%;200%") //let x1 run to 200% instead of 100% + .attr("dur", "4s") + .attr("repeatCount", "indefinite"); + // .attr("begin", '6s'); + + lg.append("animate") + .attr("attributeName", "x2") + .attr("values", "100%;300%") //let x2 run to 300% instead of 200% + .attr("dur", "4s") + .attr("repeatCount", "indefinite"); +} diff --git a/packages/flow-lineage/src/components/f-dag/f-dag-global.scss b/packages/flow-lineage/src/components/f-dag/f-dag-global.scss new file mode 100644 index 000000000..547975d8d --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/f-dag-global.scss @@ -0,0 +1,207 @@ +@keyframes node-bg-spin { + to { + --border-angle: 1turn; + } +} +f-dag { + display: flex; + overflow: auto; + position: relative; + + foreignObject { + overflow: visible; + } + + foreignObject { + cursor: pointer; + overflow: visible; + > * { + position: fixed !important; + } + * { + transform-origin: 0% 0%; + } + } + .dag-node-label { + font-size: 24px; + font-weight: 600; + } + .main-svg { + position: absolute; + width: 100%; + height: 100%; + z-index: 10; + pointer-events: none; + overflow: visible; + } + .dag-line { + fill: none; + } + .dag-node { + overflow: visible; + user-select: none; + position: absolute; + box-shadow: 0; + transition: box-shadow 1s; + + &.hidden { + visibility: hidden; + pointer-events: none; + * { + pointer-events: none; + } + .circle { + pointer-events: none !important; + } + } + &:active { + cursor: grabbing; + } + .group-content { + pointer-events: none; + } + .expander { + position: absolute; + + pointer-events: all; + + height: 28px; + width: 28px; + &.right-bottom { + right: -12px; + bottom: -12px; + cursor: se-resize; + } + } + .circle { + border: 1px solid transparent; + position: absolute; + cursor: crosshair; + pointer-events: all; + &:hover { + border: 1px solid var(--color-primary-default); + background-color: var(--color-primary-surface); + } + &.left { + right: 100%; + top: 10%; + height: 80%; + width: 8px; + } + &.right { + left: 100%; + top: 10%; + height: 80%; + width: 8px; + } + &.top { + bottom: 100%; + left: 10%; + height: 8px; + width: 80%; + } + &.bottom { + top: 100%; + left: 10%; + height: 8px; + width: 80%; + } + } + + &.selected { + &::before { + content: ""; + position: absolute; + top: -4px; + bottom: -4px; + left: -4px; + right: -4px; + border: 1px solid var(--color-primary-default); + border-radius: 4px; + } + } + + &.dragging { + &::before { + content: ""; + position: absolute; + top: -4px; + bottom: -4px; + left: -4px; + right: -4px; + border: 1px solid var(--color-primary-default); + border-radius: 4px; + } + } + &.dropped { + box-shadow: 0 0 15px var(--color-primary-default); + } + &[data-effect="pulse"] > *:not(.circle, f-text) { + box-shadow: 0 0 0 0 var(--color-danger-default); + animation: pulse-danger 2s infinite; + background: var(--color-danger-surface); + + @keyframes pulse-danger { + 0% { + box-shadow: 0 0 0 0 var(--color-danger-default); + } + + 70% { + box-shadow: 0 0 0 12px transparent; + } + + 100% { + box-shadow: 0 0 0 0 transparent; + } + } + } + } + .d-dag-root { + cursor: pointer; + &:active { + cursor: grabbing; + } + } + .dag-view-port { + overflow: visible; + } + .background-svg { + rect { + pointer-events: none; + } + } + .f-add-group, + .f-link-to { + z-index: 12; + } + // @keyframes dash { + // to { + // stroke-dashoffset: 100; + // } + // } + // path { + // stroke-dasharray: 10; + // animation: dash 5s linear infinite reverse; + // } +} + +f-div[direction="column"] { + > f-dag { + width: 100%; + flex: 1 0 auto; + } +} + +f-div[direction="row"] { + > f-dag { + flex: 1 0; + max-width: 100%; + height: 100%; + } +} + +@property --border-angle { + syntax: ""; + inherits: true; + initial-value: 0turn; +} diff --git a/packages/flow-lineage/src/components/f-dag/f-dag.ts b/packages/flow-lineage/src/components/f-dag/f-dag.ts new file mode 100644 index 000000000..ffff58c09 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/f-dag.ts @@ -0,0 +1,441 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { FButton, FDiv, flowElement, FPopover, FRoot } from "@ollion/flow-core"; +import { injectCss } from "@ollion/flow-core-config"; +import globalStyle from "./f-dag-global.scss?inline"; +import { html, PropertyValueMap, unsafeCSS } from "lit"; +import * as d3 from "d3"; +import { eventOptions, property, query, queryAll } from "lit/decorators.js"; + +import { + dragNestedGroups, + dragNode, + getTranslateValues, + moveElement, + updateNodePosition +} from "./drag-nodes-and-groups"; +import type { + CustomPlacementByElement, + CustomPlacementBySection, + FDagConfig, + FDagGroup, + FDagLink, + FDagNode, + HierarchyNode +} from "./types"; +import { + dropLine, + generatePath, + startPlottingLine, + updateLinePath, + updateLink +} from "./connect-link"; +import { Keyed } from "lit/directives/keyed.js"; +import { DirectiveResult } from "lit/directive.js"; +import computePlacement from "./compute-placement"; +import { addGroupPopover, handleAddGroup } from "./add-group"; +import getNodeGroupTemplate from "./get-node-group-template"; +import drawLinks from "./draw-links"; +import backgroundSVG from "./background-svg"; +import getNodeGroupActions from "./node-group-actions"; +import { linkTo } from "./link-to"; + +injectCss("f-dag", globalStyle); + +@flowElement("f-dag") +export class FDag extends FRoot { + /** + * css loaded from scss file + */ + static styles = [unsafeCSS(globalStyle)]; + readonly required = ["config"]; + + @property({ type: Object, reflect: false }) + config!: FDagConfig; + + /** + * Holds all groups and nodes + */ + @queryAll(`.dag-node`) + allGroupsAndNodes?: HTMLElement[]; + + /** + * Holds all nodes + */ + @queryAll(`.dag-node[data-node-type="node"]`) + allNodes?: HTMLElement[]; + + /** + * Holds reference of view port and required elements + */ + @query(`.dag-view-port`) + dagViewPort!: FDiv; + @query(`#nodeActions`) + nodeActions!: HTMLElement; + @query(`.background-pattern`) + backgroundPattern!: HTMLElement; + @query(`#d-dag-links`) + linksSVG!: SVGSVGElement; + @query(`#add-group`) + addGroupButton!: FButton; + @query(`#link-to`) + linkToButton!: FButton; + @query(`#add-group-popover`) + addGroupPopoverRef!: FPopover; + + createRenderRoot() { + return this; + } + + scale = 1; + viewPortTranslate = { + x: 0, + y: 0 + }; + + get defaultElementWidth(): number { + return this.config.defaultNodeSize?.width ?? 50; + } + get defaultElementHeight(): number { + return this.config.defaultNodeSize?.height ?? 50; + } + + currentLine?: d3.Selection; + currentArrow?: d3.Selection; + + collapsedNodeWidth = 100; + collapsedNodeHeight = 34; + + groupsHTML: DirectiveResult[] = []; + nodesHTML: DirectiveResult[] = []; + + currentClickedNode?: { + element: HTMLElement; + node: FDagNode | FDagGroup; + }; + + selectedNodes: (FDagNode | FDagGroup)[] = []; + + /** + * Node utils + */ + moveElement = moveElement; + dragNestedGroups = dragNestedGroups; + dragNode = dragNode; + updateNodePosition = updateNodePosition; + computePlacement = computePlacement; + getNodeGroupActions = getNodeGroupActions; + + /** + * Add Group utils + */ + addGroupPopover = addGroupPopover; + handleAddGroup = handleAddGroup; + + getNodeGroupTemplate = getNodeGroupTemplate; + + /** + * Link utils + */ + + startPlottingLine = startPlottingLine; + updateLinePath = updateLinePath; + dropLine = dropLine; + updateLink = updateLink; + generatePath = generatePath; + drawLinks = drawLinks; + linkTo = linkTo; + + getElement(id: string): FDagNode | FDagGroup { + return [...this.config.nodes, ...this.config.groups].find(n => n.id === id)!; + } + + getCustomPlacementElements(section: number, customPlacements: Map) { + const nodes = this.config.nodes + .filter(n => n.placement && (n.placement as CustomPlacementBySection).section === section) + .map(n => customPlacements.get(n.id)); + const groups = this.config.groups + .filter(n => n.placement && (n.placement as CustomPlacementBySection).section === section) + .map(n => customPlacements.get(n.id)); + + return [...nodes, ...groups]; + } + + getCustomPlacementElementsByElementId( + elementId: string, + customPlacements: Map + ) { + const nodes = this.config.nodes + .filter(n => n.placement && (n.placement as CustomPlacementByElement).elementId === elementId) + .map(n => customPlacements.get(n.id)); + const groups = this.config.groups + .filter(n => n.placement && (n.placement as CustomPlacementByElement).elementId === elementId) + .map(n => customPlacements.get(n.id)); + + return [...nodes, ...groups]; + } + + deleteNode(id: string) { + const nodeIndex = this.config.nodes.findIndex(e => e.id === id); + if (nodeIndex > -1) { + this.config.nodes.splice(nodeIndex, 1); + } + + this.config.links = this.config.links.filter( + l => !(l.from.elementId === id || l.to.elementId === id) + ); + } + + deleteGroup(id: string) { + this.config.groups + .filter(g => g.group === id) + .forEach(g => { + this.deleteGroup(g.id); + }); + this.config.nodes + .filter(n => n.group === id) + .forEach(n => { + this.deleteNode(n.id); + }); + const groupIndex = this.config.groups.findIndex(e => e.id === id); + if (groupIndex > -1) { + this.config.groups.splice(groupIndex, 1); + } + + this.config.links = this.config.links.filter( + l => !(l.from.elementId === id || l.to.elementId === id) + ); + } + + deleteElement() { + const nodeType = this.currentClickedNode?.element.dataset.nodeType; + if (nodeType === "node") { + this.deleteNode(this.currentClickedNode!.node.id); + } + if (nodeType === "group") { + this.deleteGroup(this.currentClickedNode!.node.id); + } + + this.requestUpdate(); + } + + protected willUpdate(changedProperties: PropertyValueMap | Map): void { + super.willUpdate(changedProperties); + this.computePlacement(); + } + handleZoom(event: WheelEvent) { + // const chartContainer = event.currentTarget as HTMLElement; + this.scale += event.deltaY * -0.01; + + // Restrict scale + this.scale = Math.min(Math.max(0.4, this.scale), 4); + + // Apply scale transform + + this.dagViewPort.style.transform = `scale(${this.scale}) translate(${this.viewPortTranslate.x}px,${this.viewPortTranslate.y}px)`; + this.backgroundPattern.setAttribute("width", `${24 * this.scale}`); + this.backgroundPattern.setAttribute("height", `${24 * this.scale}`); + } + + @eventOptions({ capture: true }) + dragLine(event: MouseEvent) { + this.updateLinePath(event); + } + + getAllSubElements(g: FDagGroup): FDagGroup[] { + const subGroups = this.config.groups.filter(gr => gr.group === g.id); + const childNodes = this.config.nodes.filter(gr => gr.group === g.id); + const nestedSubGroups = subGroups.map(sg => this.getAllSubElements(sg)); + + return [...subGroups, ...childNodes, ...nestedSubGroups.flat()]; + } + + toggleGroup(g: FDagGroup) { + g.collapsed = !g.collapsed; + g.width = undefined; + g.height = undefined; + + const subElements = this.getAllSubElements(g); + + subElements.forEach(e => { + e.x = undefined; + e.y = undefined; + }); + + this.config.links.forEach(l => { + l.from.x = undefined; + l.from.y = undefined; + l.to.x = undefined; + l.to.y = undefined; + }); + this.requestUpdate(); + } + + highlightConnections(event: PointerEvent) { + event.stopPropagation(); + const clickedNodeId = (event.currentTarget as HTMLElement).getAttribute("id"); + const nodePaths = this.querySelectorAll( + `[id^="${clickedNodeId}->"],[id$="->${clickedNodeId}"]` + ); + if (nodePaths.length > 0) { + const allPaths = this.querySelectorAll(`.dag-line`); + for (const pl of allPaths) { + pl.setAttribute("stroke-opacity", "0.4"); + pl.setAttribute("stroke", "var(--color-border-default)"); + pl.setAttribute("stroke-width", "1px"); + } + + // console.log(allPaths); + + nodePaths.forEach(p => { + p.setAttribute("stroke", "url(#animate-gradient)"); + p.setAttribute("stroke-width", "2px"); + p.setAttribute("stroke-opacity", "1"); + }); + } else { + const allPaths = this.querySelectorAll(`.dag-line`); + for (const pl of allPaths) { + pl.setAttribute("stroke-opacity", "1"); + pl.setAttribute("stroke", "var(--color-border-default)"); + pl.setAttribute("stroke-width", "1px"); + } + } + } + + resetPlacements() { + this.config.nodes.forEach(n => { + n.x = undefined; + n.y = undefined; + }); + this.config.groups.forEach(n => { + n.x = undefined; + n.y = undefined; + }); + + this.config.links.forEach(l => { + l.from.x = undefined; + l.from.y = undefined; + l.to.x = undefined; + l.to.y = undefined; + }); + } + + expandGroup(event: MouseEvent) { + event.stopPropagation(); + if (event.buttons === 1) { + const groupid = (event.currentTarget as HTMLElement).dataset.nodeId!; + const groupObj = this.getElement(groupid); + + groupObj.width! += event.movementX; + groupObj.height! += event.movementY; + + const groupElement = (event.currentTarget as HTMLElement).parentElement! as FDiv; + groupElement.width = `${groupObj.width!}px`; + groupElement.height = `${groupObj.height!}px`; + } + } + + handleNodeClick(event: PointerEvent) { + event.preventDefault(); + event.stopPropagation(); + + const nodeElement = event.currentTarget as HTMLElement; + const { translateX, translateY } = getTranslateValues(nodeElement); + + const nodeObject = this.getElement(nodeElement.getAttribute("id")!); + + this.currentClickedNode = { + node: nodeObject, + element: nodeElement + }; + + this.nodeActions.style.top = `${translateY - 26}px`; + this.nodeActions.style.left = `${translateX}px`; + this.nodeActions.style.display = "flex"; + + if (nodeElement.dataset.nodeType === "node") { + this.nodeActions.querySelector("#ungroup-action")!.style.display = "none"; + } else { + this.nodeActions.querySelector("#ungroup-action")!.style.display = "flex"; + } + } + + handleViewPortClick() { + this.nodeActions.style.display = "none"; + const allPaths = this.querySelectorAll(`.dag-line`); + for (const pl of allPaths) { + pl.setAttribute("stroke-opacity", "1"); + pl.setAttribute("stroke", "var(--color-border-default)"); + pl.setAttribute("stroke-width", "1px"); + } + } + + openBulkLinkTo() { + const linkToPopOver = this.querySelector(`#link-to-popover`)!; + linkToPopOver.target = this.linkToButton; + linkToPopOver.open = true; + } + + render() { + return html` + + + ${this.addGroupPopover()} ${this.linkTo()}${backgroundSVG()} + + ${this.groupsHTML.reverse()}${this.nodesHTML.reverse()} + + ${this.getNodeGroupActions()} + + `; + } + protected updated(changedProperties: PropertyValueMap | Map): void { + super.updated(changedProperties); + + this.drawLinks(); + + this.onmousemove = (event: MouseEvent) => { + if (event.buttons === 1) { + this.viewPortTranslate.x += event.movementX * (1 / this.scale); + this.viewPortTranslate.y += event.movementY * (1 / this.scale); + this.backgroundPattern.setAttribute( + "patternTransform", + `translate(${this.viewPortTranslate.x * this.scale},${ + this.viewPortTranslate.y * this.scale + })` + ); + this.dagViewPort.style.transform = `scale(${this.scale}) translate(${this.viewPortTranslate.x}px,${this.viewPortTranslate.y}px)`; + } + }; + } +} + +/** + * Required for typescript + */ +declare global { + interface HTMLElementTagNameMap { + "f-dag": FDag; + } +} diff --git a/packages/flow-lineage/src/components/f-dag/get-node-group-template.ts b/packages/flow-lineage/src/components/f-dag/get-node-group-template.ts new file mode 100644 index 000000000..5e9c56c78 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/get-node-group-template.ts @@ -0,0 +1,142 @@ +import type { FDag } from "./f-dag"; +import { FDagGroup, FDagNode } from "./types"; +import { keyed } from "lit/directives/keyed.js"; +import { ifDefined } from "lit/directives/if-defined.js"; +import { html } from "lit"; + +export default function getNodeGroupTemplate( + this: FDag, + element: FDagNode | FDagGroup, + type: "node" | "group" = "node" +) { + if (type === "node") { + const n = element as FDagNode; + // to force re-redner + const nKey = new Date().getTime(); + const width = n.hidden ? this.collapsedNodeWidth : n.width; + const height = n.hidden ? this.collapsedNodeHeight : n.height; + return keyed( + nKey, + html` + ${(() => { + if (n.template) { + return n.template(n); + } + if (this.config.nodeTemplate) { + return this.config.nodeTemplate(n); + } + return html` + ${n.label}`; + })()} + ${["left", "right", "top", "bottom"].map(side => { + return html``; + })} + + ${n.label} + + ` + ); + } else { + const g = element as FDagGroup; + // to force re-redner + const gKey = new Date().getTime(); + return keyed( + gKey, + html` + + + ${g.label} + e.stopPropagation()} + @click=${() => this.toggleGroup(g)} + > + + + + + ${["left", "right", "top", "bottom"].map(side => { + return html``; + })} + ${["right-bottom"].map(side => { + return html``; + })} + ` + ); + } +} diff --git a/packages/flow-lineage/src/components/f-dag/hierarchy-builder.ts b/packages/flow-lineage/src/components/f-dag/hierarchy-builder.ts new file mode 100644 index 000000000..f25f3b3d6 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/hierarchy-builder.ts @@ -0,0 +1,79 @@ +import type { FDagConfig, FDagElement, FDagGroup, HierarchyNode } from "./types"; + +export default function buildHierarchy(config: FDagConfig) { + const nodesMap = new Map(); + const customPlacementMap = new Map(); + const groupMap = new Map(); + + config.groups.forEach(group => { + groupMap.set(group.id, group); + }); + + config.nodes.forEach(node => { + if (node.group && node.placement) { + node.placement = undefined; + } + nodesMap.set(node.id, { + id: node.id, + group: node.group, + width: node.width, + type: "node", + height: node.height, + placement: node.placement, + children: [] + }); + if (node.placement) { + customPlacementMap.set(node.id, nodesMap.get(node.id)!); + } + }); + + const roots: HierarchyNode[] = []; + + nodesMap.forEach(node => { + if (!node.group) { + roots.push(node); + } + }); + + function addGroupToHierarchy(group: FDagGroup, parent?: HierarchyNode): void { + if (group.group && group.placement) { + group.placement = undefined; + } + const groupNode: HierarchyNode = { + id: group.id, + type: "group", + placement: group.placement, + children: [] + }; + + if (group.placement) { + customPlacementMap.set(group.id, groupNode); + } + + config.nodes.forEach(node => { + if (node.group === group.id) { + groupNode.children.push(nodesMap.get(node.id)!); + } + }); + + if (parent) { + parent.children.push(groupNode); + } else { + roots.push(groupNode); + } + + config.groups.forEach(subGroup => { + if (subGroup.group === group.id) { + addGroupToHierarchy(subGroup, groupNode); + } + }); + } + + config.groups.forEach(group => { + if (!group.group) { + addGroupToHierarchy(group); + } + }); + + return { roots, customPlacements: customPlacementMap }; +} diff --git a/packages/flow-lineage/src/components/f-dag/link-to.ts b/packages/flow-lineage/src/components/f-dag/link-to.ts new file mode 100644 index 000000000..7e5f2adab --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/link-to.ts @@ -0,0 +1,97 @@ +import { FormBuilderField } from "@ollion/flow-form-builder"; +import { FDag } from "./f-dag"; +import { html } from "lit"; +import { FPopover } from "@ollion/flow-core"; + +export function linkTo(this: FDag) { + const linkToFormFields: FormBuilderField = { + type: "object", + + direction: "vertical", + fields: { + groups: { + type: "select", + placeholder: "Select Groups", + selection: "multiple", + options: this.config.groups.map(g => g.id) + }, + nodes: { + type: "select", + placeholder: "Select Nodes", + selection: "multiple", + options: this.config.nodes.map(n => n.id) + } + } + }; + let values: { groups?: string[]; nodes?: string[] } = { + groups: [], + nodes: [] + }; + const handleInput = (event: CustomEvent<{ groups?: string[]; nodes?: string[] }>) => { + values = event.detail; + }; + const handleLinkTo = () => { + if (this.selectedNodes.length > 0) { + for (const currentNode of this.selectedNodes) { + const { groups, nodes } = values; + [...(groups ?? []), ...(nodes ?? [])].forEach(linkTo => { + this.config.links.push({ + from: { + elementId: currentNode.id + }, + to: { + elementId: linkTo + } + }); + }); + } + this.selectedNodes = []; + this.linkToButton.style.display = "none"; + this.addGroupButton.style.display = "none"; + } else { + const currentNode = this.currentClickedNode!.node; + + const { groups, nodes } = values; + [...(groups ?? []), ...(nodes ?? [])].forEach(linkTo => { + this.config.links.push({ + from: { + elementId: currentNode.id + }, + to: { + elementId: linkTo + } + }); + }); + } + const linkToPopOver = this.querySelector(`#link-to-popover`)!; + + linkToPopOver.open = false; + this.requestUpdate(); + }; + const handleClose = () => { + const linkToPopOver = this.querySelector(`#link-to-popover`)!; + + linkToPopOver.open = false; + }; + return html` + + e.stopPropagation()} direction="column"> + + Select Groups Or Nodes + + + + + + + + + + `; +} diff --git a/packages/flow-lineage/src/components/f-dag/node-group-actions.ts b/packages/flow-lineage/src/components/f-dag/node-group-actions.ts new file mode 100644 index 000000000..b4a4e2957 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/node-group-actions.ts @@ -0,0 +1,115 @@ +import { html } from "lit"; +import type { FDag } from "./f-dag"; +import type { FPopover } from "@ollion/flow-core"; + +export default function getNodeGroupActions(this: FDag) { + const selectNode = (event: PointerEvent) => { + event.stopPropagation(); + + if (this.currentClickedNode) { + const nodeElement = this.currentClickedNode.element; + nodeElement.classList.add("selected"); + this.nodeActions.style.display = "none"; + + this.selectedNodes.push(this.currentClickedNode.node); + this.addGroupButton.style.display = "flex"; + this.linkToButton.style.display = "flex"; + } + }; + + const unGroup = () => { + const id = this.currentClickedNode!.node.id; + this.config.groups + .filter(g => g.group === id) + .forEach(g => { + g.group = undefined; + }); + this.config.nodes + .filter(n => n.group === id) + .forEach(n => { + n.group = undefined; + }); + const groupIndex = this.config.groups.findIndex(e => e.id === id); + if (groupIndex > -1) { + this.config.groups.splice(groupIndex, 1); + } + + this.config.links = this.config.links.filter( + l => !(l.from.elementId === id || l.to.elementId === id) + ); + this.requestUpdate(); + }; + + const openLinkTo = () => { + const linkToPopOver = this.querySelector(`#link-to-popover`)!; + linkToPopOver.target = this.currentClickedNode!.element; + linkToPopOver.open = true; + }; + + const unlink = () => { + const nodeId = this.currentClickedNode!.node.id; + this.config.links = this.config.links.filter( + l => l.from.elementId !== nodeId && l.to.elementId !== nodeId + ); + this.requestUpdate(); + }; + return html` `; +} diff --git a/packages/flow-lineage/src/components/f-dag/types.ts b/packages/flow-lineage/src/components/f-dag/types.ts new file mode 100644 index 000000000..424e02ab7 --- /dev/null +++ b/packages/flow-lineage/src/components/f-dag/types.ts @@ -0,0 +1,81 @@ +import { HTMLTemplateResult } from "lit"; + +export type CoOrdinates = { + x?: number; + y?: number; +}; + +export type CustomPlacementBySection = { + section: number; + position: "before" | "after"; +}; +export type CustomPlacementByElement = { + elementId: string; + position: "before" | "after"; +}; +export type CustomPlacement = CustomPlacementBySection | CustomPlacementByElement; +export type FDagElement = { + id: string; + label: string; + icon: string; + group?: string; + placement?: CustomPlacement; + hidden?: boolean; + effect?: "pulse" | "loading"; +} & CoOrdinates; + +export type FDagNode = { + height?: number; + width?: number; + template?: (node: FDagNode) => HTMLTemplateResult; +} & FDagElement; + +export type FDagGroup = { + height?: number; + width?: number; + spacing?: { + x: number; + y: number; + }; + layoutDirection?: "horizontal" | "vertical"; + collapsed?: boolean; +} & FDagElement; + +export type FDagLinkDirection = "horizontal" | "vertical"; +export type FDagLink = { + from: CoOrdinates & { elementId: string }; + to: CoOrdinates & { elementId: string }; + direction?: FDagLinkDirection; +}; + +export type FDagConfig = { + nodes: FDagNode[]; + links: FDagLink[]; + groups: FDagGroup[]; + spacing?: { + x: number; + y: number; + }; + defaultNodeSize?: { + width: number; + height: number; + }; + nodeTemplate?: (node: FDagNode) => HTMLTemplateResult; + layoutDirection?: "horizontal" | "vertical"; +}; + +export type FDagComputedNode = { + next: FDagComputedNode[]; +} & FDagElement; + +// Renders attribute names of parent element to textContent +export type HierarchyNode = { + id: string; + height?: number; + width?: number; + group?: string; + type: "group" | "node"; + placement?: CustomPlacement; + children: HierarchyNode[]; + next?: HierarchyNode[]; +}; diff --git a/packages/flow-lineage/src/index.ts b/packages/flow-lineage/src/index.ts index a1c5d1af3..8bb0ed0d8 100644 --- a/packages/flow-lineage/src/index.ts +++ b/packages/flow-lineage/src/index.ts @@ -1,5 +1,8 @@ export * from "./components/f-lineage/f-lineage"; export * from "./components/f-lineage/lineage-types"; +export * from "./components/f-dag/f-dag"; +export * from "./components/f-dag/types"; + import { version } from "./../package.json"; console.log( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89cbd96ef..72d9be020 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@ollion/flow-aws-icon': specifier: latest - version: 1.9.1(@ollion/flow-core-config@packages+flow-core-config) + version: 1.9.1(@ollion/flow-core-config@1.1.3) '@ollion/flow-code-editor': specifier: workspace:* version: link:packages/flow-code-editor @@ -25,7 +25,7 @@ importers: version: link:packages/flow-form-builder '@ollion/flow-gcp-icon': specifier: latest - version: 1.8.1(@ollion/flow-core-config@packages+flow-core-config) + version: 1.8.1(@ollion/flow-core-config@1.1.3) '@ollion/flow-lineage': specifier: workspace:* version: link:packages/flow-lineage @@ -36,11 +36,11 @@ importers: specifier: workspace:* version: link:packages/flow-md-editor '@ollion/flow-product-icon': - specifier: 1.14.0 - version: 1.14.0(@ollion/flow-core-config@packages+flow-core-config) + specifier: 1.16.0 + version: 1.16.0(@ollion/flow-core-config@1.1.3) '@ollion/flow-system-icon': specifier: latest - version: 1.16.1(@ollion/flow-core-config@packages+flow-core-config) + version: 1.16.1(@ollion/flow-core-config@1.1.3) '@ollion/flow-table': specifier: workspace:* version: link:packages/flow-table @@ -74,7 +74,7 @@ importers: version: 7.6.7 '@storybook/addon-essentials': specifier: ^7.5.3 - version: 7.6.7(react-dom@18.2.0)(react@18.2.0) + version: 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-links': specifier: ^7.5.3 version: 7.6.7(react@18.2.0) @@ -86,13 +86,13 @@ importers: version: 7.6.7 '@storybook/blocks': specifier: ^7.5.3 - version: 7.6.7(react-dom@18.2.0)(react@18.2.0) + version: 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/web-components': specifier: ^7.5.3 - version: 7.6.7(lit@3.1.1)(react-dom@18.2.0)(react@18.2.0) + version: 7.6.7(lit@3.1.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/web-components-vite': specifier: ^7.5.3 - version: 7.6.7(lit@3.1.1)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(vite@4.5.1) + version: 7.6.7(lit@3.1.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.3.3)(vite@4.5.1(@types/node@18.19.6)(sass@1.69.7)) '@types/d3': specifier: 7.4.3 version: 7.4.3 @@ -107,7 +107,7 @@ importers: version: 3.0.0 '@typescript-eslint/eslint-plugin': specifier: ^6.7.5 - version: 6.18.1(@typescript-eslint/parser@6.18.1)(eslint@8.56.0)(typescript@5.3.3) + version: 6.18.1(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: ^6.7.5 version: 6.18.1(eslint@8.56.0)(typescript@5.3.3) @@ -128,13 +128,13 @@ importers: version: 8.0.3 lint-staged: specifier: ^14.0.1 - version: 14.0.1 + version: 14.0.1(enquirer@2.4.1) lit-html: specifier: ^3.1.0 version: 3.1.1 loki: specifier: ^0.32.0 - version: 0.32.0 + version: 0.32.0(@types/react@18.2.47) prettier: specifier: ^3.0.3 version: 3.0.3 @@ -155,7 +155,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) packages/custom-elements-manifest-to-types: dependencies: @@ -180,10 +180,10 @@ importers: version: 0.19.11 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2) + version: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) ts-jest: specifier: ^29.1.1 - version: 29.1.1(@babel/core@7.23.7)(esbuild@0.19.11)(jest@29.7.0)(typescript@5.3.3) + version: 29.1.1(@babel/core@7.23.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.7))(esbuild@0.19.11)(jest@29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)))(typescript@5.3.3) ts-node: specifier: ^10.8.2 version: 10.9.2(@types/node@18.19.6)(typescript@5.3.3) @@ -238,7 +238,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) web-component-analyzer: specifier: ^2.0.0-next.4 version: 2.0.0 @@ -332,7 +332,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) vue: specifier: 2.6.14 version: 2.6.14 @@ -351,7 +351,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) packages/flow-dashboard: dependencies: @@ -412,7 +412,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) web-component-analyzer: specifier: ^2.0.0-next.4 version: 2.0.0 @@ -470,7 +470,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) web-component-analyzer: specifier: ^2.0.0-next.4 version: 2.0.0 @@ -484,8 +484,11 @@ importers: specifier: workspace:* version: link:../flow-core-config d3: - specifier: ^7.6.1 + specifier: ^7.8.4 version: 7.8.5 + d3-dag: + specifier: ^1.1.0 + version: 1.1.0 lit: specifier: ^3.1.0 version: 3.1.1 @@ -497,7 +500,7 @@ importers: specifier: ^3.1.5 version: 3.2.2 '@types/d3': - specifier: ^7.4.0 + specifier: ^7.4.3 version: 7.4.3 '@types/jest': specifier: 29.5.5 @@ -525,7 +528,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) vue: specifier: 2.6.14 version: 2.6.14 @@ -586,7 +589,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) web-component-analyzer: specifier: ^2.0.0-next.4 version: 2.0.0 @@ -641,7 +644,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) web-component-analyzer: specifier: ^2.0.0-next.4 version: 2.0.0 @@ -690,7 +693,7 @@ importers: version: 5.3.3 vite: specifier: ^4.4.11 - version: 4.5.1(sass@1.69.7) + version: 4.5.1(@types/node@18.19.6)(sass@1.69.7) web-component-analyzer: specifier: ^2.0.0-next.4 version: 2.0.0 @@ -2125,13 +2128,16 @@ packages: peerDependencies: '@ollion/flow-core-config': '*' + '@ollion/flow-core-config@1.1.3': + resolution: {integrity: sha512-Im5UNwO+/KHkD+gAMvE1OicpLmTbof3qnxJj1vHSay+7MfzAbeuZH5YaTK7cChJ6ocBaR99vS4XGKrBs10/z6Q==} + '@ollion/flow-gcp-icon@1.8.1': resolution: {integrity: sha512-JAdA6ffgyrQ4HDyXZRfcmsV7iZRKViY9JqHLU0C67ntOtnm7L62AVQywzPkjeSgZhIeyp5F0WVuWvAhKSyehHw==} peerDependencies: '@ollion/flow-core-config': '*' - '@ollion/flow-product-icon@1.14.0': - resolution: {integrity: sha512-qPgwBGKnEIUNTxdNT12rpavenKfjF/SZ9Gee8iOtqVZ1dNrybUnMbSmyekzt2k/DUFubgKvFtga+lRy1cp8XpQ==} + '@ollion/flow-product-icon@1.16.0': + resolution: {integrity: sha512-/scX3x3eA0pL7mqY0IBQgCN1Bwk8U9/pndEGIFvFDOFhKMTJsDeh0Z8cFQqngj3fKh+ezAu9mXfH3y1D4EZKlg==} peerDependencies: '@ollion/flow-core-config': '*' @@ -4049,6 +4055,9 @@ packages: resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} engines: {node: '>=12'} + d3-dag@1.1.0: + resolution: {integrity: sha512-N8IxsIHcUaIxLrV3cElTC47kVJGFiY3blqSuJubQhyhYBJs0syfFPTnRSj2Cq0LBxxi4mzJmcqCvHIv9sPdILQ==} + d3-delaunay@6.0.4: resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} engines: {node: '>=12'} @@ -4892,6 +4901,10 @@ packages: resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==} engines: {node: '>=12.17'} + get-own-enumerable-keys@1.0.0: + resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} + engines: {node: '>=14.16'} + get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -5287,6 +5300,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-obj@3.0.0: + resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} + engines: {node: '>=12'} + is-path-cwd@2.2.0: resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} engines: {node: '>=6'} @@ -5311,6 +5328,10 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} + is-regexp@3.1.0: + resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} + engines: {node: '>=12'} + is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} @@ -5403,6 +5424,9 @@ packages: engines: {node: '>=10'} hasBin: true + javascript-lp-solver@0.4.24: + resolution: {integrity: sha512-5edoDKnMrt/u3M6GnZKDDIPxOyFOg+WrwDv8mjNiMC2DePhy2H9/FFQgf4ggywaXT1utvkxusJcjQUER72cZmA==} + jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6488,6 +6512,10 @@ packages: resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} engines: {node: '>=0.6'} + quadprog@1.6.1: + resolution: {integrity: sha512-fN5Jkcjlln/b3pJkseDKREf89JkKIyu6cKIVXisgL6ocKPQ0yTp9n6NZUAq3otEPPw78WZMG9K0o9WsfKyMWJw==} + engines: {node: '>=8.x'} + querystring@0.2.0: resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} engines: {node: '>=0.4.x'} @@ -7022,6 +7050,10 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-object@5.0.0: + resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} + engines: {node: '>=14.16'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -9048,7 +9080,7 @@ snapshots: '@floating-ui/core': 1.5.3 '@floating-ui/utils': 0.2.1 - '@floating-ui/react-dom@2.0.5(react-dom@18.2.0)(react@18.2.0)': + '@floating-ui/react-dom@2.0.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/dom': 1.5.4 react: 18.2.0 @@ -9104,7 +9136,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2)': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -9118,7 +9150,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -9332,7 +9364,7 @@ snapshots: dependencies: '@loki/browser': 0.32.0 - '@loki/runner@0.32.0': + '@loki/runner@0.32.0(@types/react@18.2.47)': dependencies: '@loki/core': 0.32.0 '@loki/diff-graphics-magick': 0.32.0 @@ -9349,7 +9381,7 @@ snapshots: cosmiconfig: 7.1.0 fs-extra: 9.1.0 import-jsx: 4.0.1 - ink: 3.2.0(react@17.0.2) + ink: 3.2.0(@types/react@18.2.47)(react@17.0.2) minimist: 1.2.8 ramda: 0.27.2 react: 17.0.2 @@ -9480,21 +9512,25 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.16.0 - '@ollion/flow-aws-icon@1.9.1(@ollion/flow-core-config@packages+flow-core-config)': + '@ollion/flow-aws-icon@1.9.1(@ollion/flow-core-config@1.1.3)': + dependencies: + '@ollion/flow-core-config': 1.1.3 + + '@ollion/flow-core-config@1.1.3': dependencies: - '@ollion/flow-core-config': link:packages/flow-core-config + rxjs: 7.8.1 - '@ollion/flow-gcp-icon@1.8.1(@ollion/flow-core-config@packages+flow-core-config)': + '@ollion/flow-gcp-icon@1.8.1(@ollion/flow-core-config@1.1.3)': dependencies: - '@ollion/flow-core-config': link:packages/flow-core-config + '@ollion/flow-core-config': 1.1.3 - '@ollion/flow-product-icon@1.14.0(@ollion/flow-core-config@packages+flow-core-config)': + '@ollion/flow-product-icon@1.16.0(@ollion/flow-core-config@1.1.3)': dependencies: - '@ollion/flow-core-config': link:packages/flow-core-config + '@ollion/flow-core-config': 1.1.3 - '@ollion/flow-system-icon@1.16.1(@ollion/flow-core-config@packages+flow-core-config)': + '@ollion/flow-system-icon@1.16.1(@ollion/flow-core-config@1.1.3)': dependencies: - '@ollion/flow-core-config': link:packages/flow-core-config + '@ollion/flow-core-config': 1.1.3 '@ollion/prettier-config@2.1.0(prettier@3.0.3)': dependencies: @@ -9545,9 +9581,10 @@ snapshots: progress: 2.0.3 proxy-agent: 6.3.0 tar-fs: 3.0.4 - typescript: 5.3.3 unbzip2-stream: 1.4.3 yargs: 17.7.1 + optionalDependencies: + typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -9559,234 +9596,288 @@ snapshots: dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-arrow@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-arrow@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-collection@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-collection@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-compose-refs@1.0.1(react@18.2.0)': + '@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-context@1.0.1(react@18.2.0)': + '@radix-ui/react-context@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-direction@1.0.1(react@18.2.0)': + '@radix-ui/react-direction@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-dismissable-layer@1.0.4(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-dismissable-layer@1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) - '@radix-ui/react-use-escape-keydown': 1.0.3(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-focus-guards@1.0.1(react@18.2.0)': + '@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-focus-scope@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-focus-scope@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-id@1.0.1(react@18.2.0)': + '@radix-ui/react-id@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-popper@1.1.2(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-popper@1.1.2(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@floating-ui/react-dom': 2.0.5(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-arrow': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) - '@radix-ui/react-use-rect': 1.0.1(react@18.2.0) - '@radix-ui/react-use-size': 1.0.1(react@18.2.0) + '@floating-ui/react-dom': 2.0.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-arrow': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.47)(react@18.2.0) '@radix-ui/rect': 1.0.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-portal@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-portal@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-primitive@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-primitive@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-roving-focus@1.0.4(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-roving-focus@1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(react@18.2.0) - '@radix-ui/react-id': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-collection': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-select@1.2.2(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-select@1.2.2(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.4(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-focus-guards': 1.0.1(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(react@18.2.0) - '@radix-ui/react-popper': 1.1.2(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) - '@radix-ui/react-use-previous': 1.0.1(react@18.2.0) - '@radix-ui/react-visually-hidden': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collection': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-popper': 1.1.2(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-portal': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.47)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-separator@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-separator@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-slot@1.0.2(react@18.2.0)': + '@radix-ui/react-slot@1.0.2(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-toggle-group@1.0.4(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-toggle-group@1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-toggle': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-toggle': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-toggle@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-toggle@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-toolbar@1.0.4(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-toolbar@1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-separator': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-toggle-group': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.47)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-separator': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-toggle-group': 1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-use-callback-ref@1.0.1(react@18.2.0)': + '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-use-controllable-state@1.0.1(react@18.2.0)': + '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-use-escape-keydown@1.0.3(react@18.2.0)': + '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-use-layout-effect@1.0.1(react@18.2.0)': + '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-use-previous@1.0.1(react@18.2.0)': + '@radix-ui/react-use-previous@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-use-rect@1.0.1(react@18.2.0)': + '@radix-ui/react-use-rect@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 '@radix-ui/rect': 1.0.1 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-use-size@1.0.1(react@18.2.0)': + '@radix-ui/react-use-size@1.0.1(@types/react@18.2.47)(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.47)(react@18.2.0) react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.47 - '@radix-ui/react-visually-hidden@1.0.3(react-dom@18.2.0)(react@18.2.0)': + '@radix-ui/react-visually-hidden@1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 '@radix-ui/rect@1.0.1': dependencies: @@ -9810,6 +9901,7 @@ snapshots: is-builtin-module: 3.2.1 is-module: 1.0.0 resolve: 1.22.8 + optionalDependencies: rollup: 3.29.4 '@rollup/pluginutils@3.1.0(rollup@2.79.1)': @@ -9824,6 +9916,7 @@ snapshots: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 + optionalDependencies: rollup: 3.29.4 '@sideway/address@4.1.4': @@ -9864,9 +9957,9 @@ snapshots: memoizerific: 1.11.3 ts-dedent: 2.2.0 - '@storybook/addon-controls@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/addon-controls@7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@storybook/blocks': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/blocks': 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) lodash: 4.17.21 ts-dedent: 2.2.0 transitivePeerDependencies: @@ -9877,13 +9970,13 @@ snapshots: - react-dom - supports-color - '@storybook/addon-docs@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/addon-docs@7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@jest/transform': 29.7.0 '@mdx-js/react': 2.3.0(react@18.2.0) - '@storybook/blocks': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/blocks': 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/client-logger': 7.6.7 - '@storybook/components': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/components': 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/csf-plugin': 7.6.7 '@storybook/csf-tools': 7.6.7 '@storybook/global': 5.0.0 @@ -9891,8 +9984,8 @@ snapshots: '@storybook/node-logger': 7.6.7 '@storybook/postinstall': 7.6.7 '@storybook/preview-api': 7.6.7 - '@storybook/react-dom-shim': 7.6.7(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/react-dom-shim': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@storybook/theming': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/types': 7.6.7 fs-extra: 11.2.0 react: 18.2.0 @@ -9906,19 +9999,19 @@ snapshots: - encoding - supports-color - '@storybook/addon-essentials@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/addon-essentials@7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@storybook/addon-actions': 7.6.7 '@storybook/addon-backgrounds': 7.6.7 - '@storybook/addon-controls': 7.6.7(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-docs': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-controls': 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@storybook/addon-docs': 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/addon-highlight': 7.6.7 '@storybook/addon-measure': 7.6.7 '@storybook/addon-outline': 7.6.7 '@storybook/addon-toolbars': 7.6.7 '@storybook/addon-viewport': 7.6.7 '@storybook/core-common': 7.6.7 - '@storybook/manager-api': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/node-logger': 7.6.7 '@storybook/preview-api': 7.6.7 react: 18.2.0 @@ -9942,8 +10035,9 @@ snapshots: dependencies: '@storybook/csf': 0.1.2 '@storybook/global': 5.0.0 - react: 18.2.0 ts-dedent: 2.2.0 + optionalDependencies: + react: 18.2.0 '@storybook/addon-mdx-gfm@7.6.7': dependencies: @@ -9975,18 +10069,18 @@ snapshots: dependencies: memoizerific: 1.11.3 - '@storybook/blocks@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/blocks@7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@storybook/channels': 7.6.7 '@storybook/client-logger': 7.6.7 - '@storybook/components': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/components': 7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/core-events': 7.6.7 '@storybook/csf': 0.1.2 '@storybook/docs-tools': 7.6.7 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/preview-api': 7.6.7 - '@storybook/theming': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/types': 7.6.7 '@types/lodash': 4.14.202 color-convert: 2.0.1 @@ -9996,7 +10090,7 @@ snapshots: memoizerific: 1.11.3 polished: 4.2.2 react: 18.2.0 - react-colorful: 5.6.1(react-dom@18.2.0)(react@18.2.0) + react-colorful: 5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-dom: 18.2.0(react@18.2.0) telejson: 7.2.0 tocbot: 4.25.0 @@ -10030,7 +10124,7 @@ snapshots: - encoding - supports-color - '@storybook/builder-vite@7.6.7(typescript@5.3.3)(vite@4.5.1)': + '@storybook/builder-vite@7.6.7(typescript@5.3.3)(vite@4.5.1(@types/node@18.19.6)(sass@1.69.7))': dependencies: '@storybook/channels': 7.6.7 '@storybook/client-logger': 7.6.7 @@ -10048,8 +10142,9 @@ snapshots: fs-extra: 11.2.0 magic-string: 0.30.5 rollup: 3.29.4 + vite: 4.5.1(@types/node@18.19.6)(sass@1.69.7) + optionalDependencies: typescript: 5.3.3 - vite: 4.5.1(sass@1.69.7) transitivePeerDependencies: - encoding - supports-color @@ -10093,7 +10188,7 @@ snapshots: get-port: 5.1.1 giget: 1.2.1 globby: 11.1.0 - jscodeshift: 0.15.1(@babel/preset-env@7.23.8) + jscodeshift: 0.15.1(@babel/preset-env@7.23.8(@babel/core@7.23.7)) leven: 3.1.0 ora: 5.4.1 prettier: 2.8.8 @@ -10128,26 +10223,26 @@ snapshots: '@types/cross-spawn': 6.0.6 cross-spawn: 7.0.3 globby: 11.1.0 - jscodeshift: 0.15.1(@babel/preset-env@7.23.8) + jscodeshift: 0.15.1(@babel/preset-env@7.23.8(@babel/core@7.23.7)) lodash: 4.17.21 prettier: 2.8.8 recast: 0.23.4 transitivePeerDependencies: - supports-color - '@storybook/components@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/components@7.6.7(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@radix-ui/react-select': 1.2.2(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-toolbar': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-select': 1.2.2(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-toolbar': 1.0.4(@types/react@18.2.47)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/client-logger': 7.6.7 '@storybook/csf': 0.1.2 '@storybook/global': 5.0.0 - '@storybook/theming': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/types': 7.6.7 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - use-resize-observer: 9.1.0(react-dom@18.2.0)(react@18.2.0) + use-resize-observer: 9.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' @@ -10286,7 +10381,7 @@ snapshots: '@storybook/global@5.0.0': {} - '@storybook/manager-api@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/manager-api@7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@storybook/channels': 7.6.7 '@storybook/client-logger': 7.6.7 @@ -10294,7 +10389,7 @@ snapshots: '@storybook/csf': 0.1.2 '@storybook/global': 5.0.0 '@storybook/router': 7.6.7 - '@storybook/theming': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/types': 7.6.7 dequal: 2.0.3 lodash: 4.17.21 @@ -10333,7 +10428,7 @@ snapshots: '@storybook/preview@7.6.7': {} - '@storybook/react-dom-shim@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/react-dom-shim@7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -10366,7 +10461,7 @@ snapshots: - encoding - supports-color - '@storybook/theming@7.6.7(react-dom@18.2.0)(react@18.2.0)': + '@storybook/theming@7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) '@storybook/client-logger': 7.6.7 @@ -10382,12 +10477,12 @@ snapshots: '@types/express': 4.17.21 file-system-cache: 2.3.0 - '@storybook/web-components-vite@7.6.7(lit@3.1.1)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(vite@4.5.1)': + '@storybook/web-components-vite@7.6.7(lit@3.1.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.3.3)(vite@4.5.1(@types/node@18.19.6)(sass@1.69.7))': dependencies: - '@storybook/builder-vite': 7.6.7(typescript@5.3.3)(vite@4.5.1) + '@storybook/builder-vite': 7.6.7(typescript@5.3.3)(vite@4.5.1(@types/node@18.19.6)(sass@1.69.7)) '@storybook/core-server': 7.6.7 '@storybook/node-logger': 7.6.7 - '@storybook/web-components': 7.6.7(lit@3.1.1)(react-dom@18.2.0)(react@18.2.0) + '@storybook/web-components': 7.6.7(lit@3.1.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) magic-string: 0.30.5 transitivePeerDependencies: - '@preact/preset-vite' @@ -10402,13 +10497,13 @@ snapshots: - vite - vite-plugin-glimmerx - '@storybook/web-components@7.6.7(lit@3.1.1)(react-dom@18.2.0)(react@18.2.0)': + '@storybook/web-components@7.6.7(lit@3.1.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@storybook/client-logger': 7.6.7 '@storybook/core-client': 7.6.7 '@storybook/docs-tools': 7.6.7 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.6.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.6.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/preview-api': 7.6.7 '@storybook/types': 7.6.7 lit: 3.1.1 @@ -10825,7 +10920,7 @@ snapshots: '@types/yoga-layout@1.9.2': {} - '@typescript-eslint/eslint-plugin@6.18.1(@typescript-eslint/parser@6.18.1)(eslint@8.56.0)(typescript@5.3.3)': + '@typescript-eslint/eslint-plugin@6.18.1(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3)': dependencies: '@eslint-community/regexpp': 4.10.0 '@typescript-eslint/parser': 6.18.1(eslint@8.56.0)(typescript@5.3.3) @@ -10840,6 +10935,7 @@ snapshots: natural-compare: 1.4.0 semver: 7.5.4 ts-api-utils: 1.0.3(typescript@5.3.3) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -10852,6 +10948,7 @@ snapshots: '@typescript-eslint/visitor-keys': 6.18.1 debug: 4.3.4 eslint: 8.56.0 + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -10873,6 +10970,7 @@ snapshots: debug: 4.3.4 eslint: 8.56.0 ts-api-utils: 1.0.3(typescript@5.3.3) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -10890,6 +10988,7 @@ snapshots: is-glob: 4.0.3 semver: 7.5.4 tsutils: 3.21.0(typescript@5.3.3) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -10904,6 +11003,7 @@ snapshots: minimatch: 9.0.3 semver: 7.5.4 ts-api-utils: 1.0.3(typescript@5.3.3) + optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color @@ -12140,13 +12240,13 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - create-jest@29.7.0(@types/node@18.19.6)(ts-node@10.9.2): + create-jest@29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -12234,6 +12334,13 @@ snapshots: dependencies: d3-array: 3.2.4 + d3-dag@1.1.0: + dependencies: + d3-array: 3.2.4 + javascript-lp-solver: 0.4.24 + quadprog: 1.6.1 + stringify-object: 5.0.0 + d3-delaunay@6.0.4: dependencies: delaunator: 5.0.0 @@ -13129,7 +13236,7 @@ snapshots: flow-parser@0.226.0: {} follow-redirects@1.15.4(debug@4.3.4): - dependencies: + optionalDependencies: debug: 4.3.4 for-each@0.3.3: @@ -13219,6 +13326,8 @@ snapshots: get-npm-tarball-url@2.1.0: {} + get-own-enumerable-keys@1.0.0: {} + get-package-type@0.1.0: {} get-port@5.1.1: {} @@ -13507,7 +13616,7 @@ snapshots: inherits@2.0.4: {} - ink@3.2.0(react@17.0.2): + ink@3.2.0(@types/react@18.2.47)(react@17.0.2): dependencies: ansi-escapes: 4.3.2 auto-bind: 4.0.0 @@ -13533,6 +13642,8 @@ snapshots: wrap-ansi: 6.2.0 ws: 7.5.9 yoga-layout-prebuilt: 1.10.0 + optionalDependencies: + '@types/react': 18.2.47 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -13644,6 +13755,8 @@ snapshots: is-number@7.0.0: {} + is-obj@3.0.0: {} + is-path-cwd@2.2.0: {} is-path-inside@3.0.3: {} @@ -13661,6 +13774,8 @@ snapshots: call-bind: 1.0.5 has-tostringtag: 1.0.0 + is-regexp@3.1.0: {} + is-shared-array-buffer@1.0.2: dependencies: call-bind: 1.0.5 @@ -13761,6 +13876,8 @@ snapshots: filelist: 1.0.4 minimatch: 3.1.2 + javascript-lp-solver@0.4.24: {} + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -13793,16 +13910,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@18.19.6)(ts-node@10.9.2): + jest-cli@29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2) + create-jest: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -13812,12 +13929,11 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@18.19.6)(ts-node@10.9.2): + jest-config@29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)): dependencies: '@babel/core': 7.23.7 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 18.19.6 babel-jest: 29.7.0(@babel/core@7.23.7) chalk: 4.1.2 ci-info: 3.9.0 @@ -13837,6 +13953,8 @@ snapshots: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 18.19.6 ts-node: 10.9.2(@types/node@18.19.6)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros @@ -13919,7 +14037,7 @@ snapshots: jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - dependencies: + optionalDependencies: jest-resolve: 29.7.0 jest-regex-util@29.6.3: {} @@ -14057,12 +14175,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@18.19.6)(ts-node@10.9.2): + jest@29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2) + jest-cli: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -14090,7 +14208,7 @@ snapshots: dependencies: argparse: 2.0.1 - jscodeshift@0.15.1(@babel/preset-env@7.23.8): + jscodeshift@0.15.1(@babel/preset-env@7.23.8(@babel/core@7.23.7)): dependencies: '@babel/core': 7.23.7 '@babel/parser': 7.23.6 @@ -14099,7 +14217,6 @@ snapshots: '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) - '@babel/preset-env': 7.23.8(@babel/core@7.23.7) '@babel/preset-flow': 7.23.3(@babel/core@7.23.7) '@babel/preset-typescript': 7.23.3(@babel/core@7.23.7) '@babel/register': 7.23.7(@babel/core@7.23.7) @@ -14113,6 +14230,8 @@ snapshots: recast: 0.23.4 temp: 0.8.4 write-file-atomic: 2.4.3 + optionalDependencies: + '@babel/preset-env': 7.23.8(@babel/core@7.23.7) transitivePeerDependencies: - supports-color @@ -14244,14 +14363,14 @@ snapshots: lines-and-columns@1.2.4: {} - lint-staged@14.0.1: + lint-staged@14.0.1(enquirer@2.4.1): dependencies: chalk: 5.3.0 commander: 11.0.0 debug: 4.3.4 execa: 7.2.0 lilconfig: 2.1.0 - listr2: 6.6.1 + listr2: 6.6.1(enquirer@2.4.1) micromatch: 4.0.5 pidtree: 0.6.0 string-argv: 0.3.2 @@ -14260,7 +14379,7 @@ snapshots: - enquirer - supports-color - listr2@6.6.1: + listr2@6.6.1(enquirer@2.4.1): dependencies: cli-truncate: 3.1.0 colorette: 2.0.20 @@ -14268,6 +14387,8 @@ snapshots: log-update: 5.0.1 rfdc: 1.3.0 wrap-ansi: 8.1.0 + optionalDependencies: + enquirer: 2.4.1 lit-element@4.0.3: dependencies: @@ -14341,12 +14462,12 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 8.1.0 - loki@0.32.0: + loki@0.32.0(@types/react@18.2.47): dependencies: '@loki/integration-react': 0.32.0 '@loki/integration-react-native': 0.32.0 '@loki/integration-vue': 0.32.0 - '@loki/runner': 0.32.0 + '@loki/runner': 0.32.0(@types/react@18.2.47) '@loki/target-chrome-app': 0.32.0 '@loki/target-chrome-docker': 0.32.0 '@loki/target-native-android-emulator': 0.32.0 @@ -15224,8 +15345,9 @@ snapshots: cross-fetch: 4.0.0 debug: 4.3.4 devtools-protocol: 0.0.1147663 - typescript: 5.3.3 ws: 8.13.0 + optionalDependencies: + typescript: 5.3.3 transitivePeerDependencies: - bufferutil - encoding @@ -15242,6 +15364,8 @@ snapshots: dependencies: side-channel: 1.0.4 + quadprog@1.6.1: {} + querystring@0.2.0: {} queue-microtask@1.2.3: {} @@ -15275,7 +15399,7 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - react-colorful@5.6.1(react-dom@18.2.0)(react@18.2.0): + react-colorful@5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -15303,27 +15427,33 @@ snapshots: react: 17.0.2 scheduler: 0.20.2 - react-remove-scroll-bar@2.3.4(react@18.2.0): + react-remove-scroll-bar@2.3.4(@types/react@18.2.47)(react@18.2.0): dependencies: react: 18.2.0 - react-style-singleton: 2.2.1(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.47)(react@18.2.0) tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.47 - react-remove-scroll@2.5.5(react@18.2.0): + react-remove-scroll@2.5.5(@types/react@18.2.47)(react@18.2.0): dependencies: react: 18.2.0 - react-remove-scroll-bar: 2.3.4(react@18.2.0) - react-style-singleton: 2.2.1(react@18.2.0) + react-remove-scroll-bar: 2.3.4(@types/react@18.2.47)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.47)(react@18.2.0) tslib: 2.6.2 - use-callback-ref: 1.3.1(react@18.2.0) - use-sidecar: 1.1.2(react@18.2.0) + use-callback-ref: 1.3.1(@types/react@18.2.47)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.47)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.47 - react-style-singleton@2.2.1(react@18.2.0): + react-style-singleton@2.2.1(@types/react@18.2.47)(react@18.2.0): dependencies: get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.47 react@17.0.2: dependencies: @@ -15834,6 +15964,12 @@ snapshots: dependencies: safe-buffer: 5.2.1 + stringify-object@5.0.0: + dependencies: + get-own-enumerable-keys: 1.0.0 + is-obj: 3.0.0 + is-regexp: 3.1.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -16013,13 +16149,11 @@ snapshots: ts-dedent@2.2.0: {} - ts-jest@29.1.1(@babel/core@7.23.7)(esbuild@0.19.11)(jest@29.7.0)(typescript@5.3.3): + ts-jest@29.1.1(@babel/core@7.23.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.7))(esbuild@0.19.11)(jest@29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)))(typescript@5.3.3): dependencies: - '@babel/core': 7.23.7 bs-logger: 0.2.6 - esbuild: 0.19.11 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.19.6)(ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -16027,6 +16161,11 @@ snapshots: semver: 7.5.4 typescript: 5.3.3 yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.23.7 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.23.7) + esbuild: 0.19.11 ts-node@10.9.2(@types/node@18.19.6)(typescript@5.3.3): dependencies: @@ -16247,22 +16386,26 @@ snapshots: punycode: 1.3.2 querystring: 0.2.0 - use-callback-ref@1.3.1(react@18.2.0): + use-callback-ref@1.3.1(@types/react@18.2.47)(react@18.2.0): dependencies: react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.47 - use-resize-observer@9.1.0(react-dom@18.2.0)(react@18.2.0): + use-resize-observer@9.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@juggle/resize-observer': 3.4.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - use-sidecar@1.1.2(react@18.2.0): + use-sidecar@1.1.2(@types/react@18.2.47)(react@18.2.0): dependencies: detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.47 util-deprecate@1.0.2: {} @@ -16331,14 +16474,15 @@ snapshots: unist-util-stringify-position: 3.0.3 vfile-message: 3.1.4 - vite@4.5.1(sass@1.69.7): + vite@4.5.1(@types/node@18.19.6)(sass@1.69.7): dependencies: esbuild: 0.18.20 postcss: 8.4.33 rollup: 3.29.4 - sass: 1.69.7 optionalDependencies: + '@types/node': 18.19.6 fsevents: 2.3.3 + sass: 1.69.7 vue@2.6.14: {} diff --git a/stories/flow-lineage/dag-config.ts b/stories/flow-lineage/dag-config.ts new file mode 100644 index 000000000..350bb512c --- /dev/null +++ b/stories/flow-lineage/dag-config.ts @@ -0,0 +1,298 @@ +import { FDagConfig, FDagNode } from "@ollion/flow-lineage"; +import { html } from "lit"; + +const nodeTemplate = (node: FDagNode) => { + return html` + `; +}; + +const dagConfig: FDagConfig = { + nodes: [ + { + id: "node1", + label: "Node 1", + icon: "p-slack" + }, + { + id: "node2", + label: "Node 2", + icon: "p-kubernetes" + }, + { + id: "node3", + label: "Node 3", + icon: "p-docker", + group: "group1" + }, + { + id: "node4", + label: "Node 4", + icon: "p-azure", + group: "group2" + }, + { + id: "node5", + label: "Node 5", + icon: "p-gitlab", + + group: "group3" + }, + { + id: "node6", + label: "Node 6", + icon: "p-github", + + group: "group3" + }, + { + id: "node7", + label: "Node 7", + icon: "p-snowflake", + + group: "group4" + }, + { + id: "node8", + label: "Node 8", + icon: "p-ollion" + }, + { + id: "node9", + label: "Node 9", + icon: "p-terraform", + + group: "group5" + }, + { + id: "node10", + label: "Node 10", + icon: "p-aws-dark", + + group: "group5" + }, + { + id: "node11", + label: "Node 11", + icon: "p-postgresql", + + group: "group6" + }, + { + id: "node91", + label: "Node 91", + icon: "p-hadoop", + + group: "group7" + }, + { + id: "node101", + label: "Node 101", + icon: "p-redis", + + group: "group7" + }, + { + id: "node111", + label: "Node 111", + icon: "p-mysql", + + group: "group7" + }, + { + id: "node71", + label: "Node 71", + icon: "p-asana" + }, + { + id: "node72", + label: "Node 72", + icon: "p-prometheus", + effect: "loading" + }, + { + id: "node73", + label: "Node 73", + icon: "p-opa", + effect: "pulse" + } + ], + links: [ + { + from: { + elementId: "node1" + }, + to: { + elementId: "group4" + } + }, + { + from: { + elementId: "node1" + }, + to: { + elementId: "group1" + } + }, + { + from: { + elementId: "node3" + }, + to: { + elementId: "node4" + } + }, + { + from: { + elementId: "node2" + }, + to: { + elementId: "group3" + } + }, + { + from: { + elementId: "group1" + }, + to: { + elementId: "group2" + } + }, + { + from: { + elementId: "node6" + }, + to: { + elementId: "node8" + } + }, + { + from: { + elementId: "node7" + }, + to: { + elementId: "node10" + } + }, + { + from: { + elementId: "node9" + }, + to: { + elementId: "group6" + } + }, + { + from: { + elementId: "node6" + }, + to: { + elementId: "node91" + } + }, + { + from: { + elementId: "node11" + }, + to: { + elementId: "group7" + } + } + ], + groups: [ + { + id: "group1", + label: "Group 1", + icon: "i-tree", + spacing: { + x: 50, + y: 50 + } + }, + { + id: "group2", + label: "Group 2", + icon: "i-tree", + spacing: { + x: 50, + y: 50 + } + }, + { + id: "group3", + label: "Group 3", + icon: "i-tree", + spacing: { + x: 20, + y: 20 + }, + group: "group4" + }, + { + id: "group4", + label: "Group 4", + icon: "i-tree", + spacing: { + x: 20, + y: 20 + }, + group: "group1" + }, + { + id: "group5", + label: "Group 5", + icon: "i-tree", + spacing: { + x: 20, + y: 20 + }, + placement: { + section: 1, + position: "before" + } + }, + { + id: "group7", + label: "Group 7", + icon: "i-tree", + spacing: { + x: 20, + y: 20 + }, + layoutDirection: "vertical", + placement: { + elementId: "group1", + position: "after" + } + }, + { + id: "group6", + label: "Group 6", + icon: "i-tree", + spacing: { + x: 20, + y: 20 + }, + placement: { + elementId: "node8", + position: "after" + } + } + ], + spacing: { + x: 70, + y: 60 + }, + defaultNodeSize: { + width: 48, + height: 48 + }, + nodeTemplate, + layoutDirection: "vertical" +}; + +export default dagConfig; diff --git a/stories/flow-lineage/f-dag.stories.ts b/stories/flow-lineage/f-dag.stories.ts new file mode 100644 index 000000000..800ca77f3 --- /dev/null +++ b/stories/flow-lineage/f-dag.stories.ts @@ -0,0 +1,15 @@ +import { Meta, Story } from "@storybook/web-components"; +import { html } from "lit-html"; +import dagConfig from "./dag-config"; + +export default { + title: "@ollion/flow-lineage/f-dag" +} as Meta>; + +export const Basic = { + render: () => { + return html` + + `; + } +};