@likec4/diagram 1.20.1 → 1.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4Diagram.css.d.ts +1 -0
- package/dist/LikeC4Diagram.css.js +3 -1
- package/dist/base/BaseXYFlow.js +15 -14
- package/dist/base/Link.css.d.ts +3 -0
- package/dist/base/Link.css.js +9 -0
- package/dist/base/Link.d.ts +5 -0
- package/dist/base/Link.js +58 -0
- package/dist/base/const.d.ts +1 -0
- package/dist/base/const.js +2 -1
- package/dist/base/example/custom.d.ts +1 -1
- package/dist/base/index.d.ts +1 -0
- package/dist/base/primitives/compound/CompoundActionButton.js +2 -1
- package/dist/base/primitives/compound/CompoundDetailsButton.js +2 -1
- package/dist/base/primitives/compound/CompoundNodeContainer.css.d.ts +0 -1
- package/dist/base/primitives/compound/CompoundNodeContainer.css.js +4 -6
- package/dist/base/primitives/compound/CompoundNodeContainer.js +2 -2
- package/dist/base/primitives/customEdge.d.ts +1 -1
- package/dist/base/primitives/customEdge.js +1 -1
- package/dist/base/primitives/customNode.js +1 -1
- package/dist/base/primitives/edge/EdgeLabel.js +3 -1
- package/dist/base/primitives/edge/EdgePath.d.ts +2 -1
- package/dist/base/primitives/edge/EdgePath.js +2 -0
- package/dist/base/primitives/element/ElementActionButtons.js +2 -1
- package/dist/base/primitives/element/ElementDetailsButton.js +2 -1
- package/dist/base/primitives/element/ElementNodeContainer.css.d.ts +0 -1
- package/dist/base/primitives/element/ElementNodeContainer.css.js +1 -3
- package/dist/base/primitives/element/ElementNodeContainer.js +2 -3
- package/dist/base/primitives/element/ElementShape.js +4 -2
- package/dist/base/primitives/element/ElementTitle.js +2 -1
- package/dist/base/updateEdges.js +3 -3
- package/dist/base/updateNodes.js +2 -2
- package/dist/context/FramerMotionConfig.js +1 -1
- package/dist/hooks/useDiagram.d.ts +313 -90
- package/dist/hooks/useDiagramActor.d.ts +2 -2
- package/dist/hooks/useDiagramContext.d.ts +1 -1
- package/dist/hooks/useXYFlow.d.ts +2 -1
- package/dist/hooks/useXYFlow.js +5 -0
- package/dist/likec4diagram/XYFlow.js +12 -10
- package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +1 -1
- package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +2 -2
- package/dist/likec4diagram/custom/index.d.ts +1 -1
- package/dist/likec4diagram/custom/nodes/nodeTypes.js +2 -2
- package/dist/likec4diagram/state/actorContext.d.ts +1438 -364
- package/dist/likec4diagram/state/assign.js +2 -2
- package/dist/likec4diagram/state/machine.d.ts +321 -93
- package/dist/likec4diagram/state/syncManualLayoutActor.d.ts +1 -1
- package/dist/likec4diagram/types.d.ts +1 -0
- package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +4 -3
- package/dist/likec4diagram/useLayoutConstraints.d.ts +2 -1
- package/dist/likec4diagram/useLayoutConstraints.js +14 -15
- package/dist/likec4diagram/useViewToNodesEdges.js +3 -1
- package/dist/overlays/element-details/ElementDetailsCard.css.d.ts +0 -1
- package/dist/overlays/element-details/ElementDetailsCard.css.js +1 -3
- package/dist/overlays/element-details/ElementDetailsCard.js +5 -30
- package/dist/overlays/element-details/TabPanelRelationships.js +2 -2
- package/dist/overlays/relationship-details/RelationshipDetails.js +4 -4
- package/dist/overlays/relationship-details/custom/ElementActions.js +1 -3
- package/dist/overlays/relationship-details/custom/edgeTypes.d.ts +1 -1
- package/dist/overlays/relationship-details/hooks.d.ts +2 -2
- package/dist/overlays/relationship-details/hooks.js +7 -7
- package/dist/overlays/relationship-details/useLayoutedDetails.js +7 -10
- package/dist/overlays/relationships-browser/-useRelationshipsView.d.ts +4 -1
- package/dist/overlays/relationships-browser/-useRelationshipsView.js +12 -11
- package/dist/overlays/relationships-browser/RelationshipsBrowser.js +81 -66
- package/dist/overlays/relationships-browser/_types.d.ts +2 -1
- package/dist/overlays/relationships-browser/actor.d.ts +15 -2
- package/dist/overlays/relationships-browser/actor.js +262 -65
- package/dist/overlays/relationships-browser/const.d.ts +1 -0
- package/dist/overlays/relationships-browser/const.js +4 -0
- package/dist/overlays/relationships-browser/custom/ElementActions.js +13 -3
- package/dist/overlays/relationships-browser/custom/edgeTypes.d.ts +3 -2
- package/dist/overlays/relationships-browser/custom/edgeTypes.js +24 -6
- package/dist/overlays/relationships-browser/custom/nodeTypes.js +3 -2
- package/dist/overlays/relationships-browser/hooks.d.ts +6 -3
- package/dist/overlays/relationships-browser/hooks.js +4 -2
- package/dist/overlays/relationships-browser/useViewToNodesEdges.js +7 -2
- package/dist/style.css +1 -1
- package/dist/utils/xyflow.js +9 -1
- package/package.json +10 -10
- package/src/LikeC4Diagram.css.ts +8 -0
- package/src/base/BaseXYFlow.tsx +23 -14
- package/src/base/Link.css.ts +49 -0
- package/src/base/Link.tsx +66 -0
- package/src/base/const.ts +1 -0
- package/src/base/index.ts +2 -0
- package/src/base/primitives/compound/CompoundActionButton.tsx +2 -1
- package/src/base/primitives/compound/CompoundDetailsButton.tsx +2 -1
- package/src/base/primitives/compound/CompoundNodeContainer.css.ts +16 -10
- package/src/base/primitives/compound/CompoundNodeContainer.tsx +1 -1
- package/src/base/primitives/customEdge.ts +2 -0
- package/src/base/primitives/customNode.ts +3 -0
- package/src/base/primitives/edge/EdgeLabel.tsx +3 -1
- package/src/base/primitives/edge/EdgePath.tsx +3 -0
- package/src/base/primitives/element/ElementActionButtons.tsx +2 -1
- package/src/base/primitives/element/ElementDetailsButton.tsx +2 -1
- package/src/base/primitives/element/ElementNodeContainer.css.ts +9 -4
- package/src/base/primitives/element/ElementNodeContainer.tsx +1 -2
- package/src/base/primitives/element/ElementShape.tsx +4 -3
- package/src/base/primitives/element/ElementTitle.tsx +2 -1
- package/src/base/updateEdges.ts +3 -2
- package/src/base/updateNodes.ts +3 -2
- package/src/context/DiagramFeatures.tsx +1 -0
- package/src/context/FramerMotionConfig.tsx +1 -1
- package/src/hooks/useDiagramActor.ts +7 -5
- package/src/hooks/useDiagramContext.ts +4 -1
- package/src/hooks/useXYFlow.ts +6 -1
- package/src/likec4diagram/XYFlow.tsx +20 -9
- package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +2 -2
- package/src/likec4diagram/custom/nodes/nodeTypes.tsx +2 -2
- package/src/likec4diagram/types.ts +1 -0
- package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +4 -3
- package/src/likec4diagram/useLayoutConstraints.ts +23 -19
- package/src/likec4diagram/useViewToNodesEdges.ts +1 -0
- package/src/overlays/element-details/ElementDetailsCard.css.ts +0 -28
- package/src/overlays/element-details/ElementDetailsCard.tsx +2 -50
- package/src/overlays/element-details/TabPanelRelationships.tsx +2 -2
- package/src/overlays/relationship-details/RelationshipDetails.tsx +4 -4
- package/src/overlays/relationship-details/custom/ElementActions.tsx +1 -2
- package/src/overlays/relationship-details/custom/edgeTypes.tsx +0 -5
- package/src/overlays/relationship-details/hooks.ts +6 -6
- package/src/overlays/relationship-details/useLayoutedDetails.ts +7 -10
- package/src/overlays/relationships-browser/-useRelationshipsView.ts +16 -12
- package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +105 -68
- package/src/overlays/relationships-browser/_types.ts +2 -1
- package/src/overlays/relationships-browser/actor.ts +321 -62
- package/src/overlays/relationships-browser/const.ts +1 -0
- package/src/overlays/relationships-browser/custom/ElementActions.tsx +13 -3
- package/src/overlays/relationships-browser/custom/edgeTypes.tsx +25 -6
- package/src/overlays/relationships-browser/custom/nodeTypes.tsx +3 -2
- package/src/overlays/relationships-browser/hooks.ts +3 -1
- package/src/overlays/relationships-browser/useViewToNodesEdges.ts +8 -2
- package/dist/likec4diagram/ui/diagram-title/Link.js +0 -36
- package/dist/ui/Link.d.ts +0 -4
- package/src/ui/Link.tsx +0 -40
|
@@ -23,7 +23,7 @@ export declare const syncManualLayoutActor: StateMachine<Readonly<Input>, Events
|
|
|
23
23
|
}, {
|
|
24
24
|
type: "same view";
|
|
25
25
|
params: unknown;
|
|
26
|
-
}, "timeout", "stopped" | "
|
|
26
|
+
}, "timeout", "stopped" | "synced" | "pending" | "idle" | "paused", "pending" | "ready", Input, NonReducibleUnknown, EventObject, MetaObject, {
|
|
27
27
|
readonly initial: "idle";
|
|
28
28
|
readonly context: ({ input }: {
|
|
29
29
|
spawn: {
|
|
@@ -10,6 +10,7 @@ type NonOptional<T extends object> = Simplify<{
|
|
|
10
10
|
}>;
|
|
11
11
|
export declare namespace Types {
|
|
12
12
|
type LeafNodeData = Base.NodeData<NonOptional<Pick<DiagramNode, 'id' | 'title' | 'technology' | 'description' | 'color' | 'shape' | 'width' | 'level' | 'height' | 'style' | 'position'>> & {
|
|
13
|
+
isMultiple?: boolean | undefined;
|
|
13
14
|
icon: string | null;
|
|
14
15
|
}>;
|
|
15
16
|
/**
|
|
@@ -6,7 +6,7 @@ import clsx from "clsx";
|
|
|
6
6
|
import { AnimatePresence, m } from "framer-motion";
|
|
7
7
|
import { useDiagramContext } from "../../../hooks/useDiagramContext.js";
|
|
8
8
|
import { container, card, title, description } from "./DiagramTitlePanel.css.js";
|
|
9
|
-
import { Link } from "
|
|
9
|
+
import { Link } from "../../../base/Link.js";
|
|
10
10
|
const selector = (s) => ({
|
|
11
11
|
id: s.view.id,
|
|
12
12
|
title: s.view.title ?? "untitled",
|
|
@@ -140,10 +140,11 @@ function DiagramTitlePanel() {
|
|
|
140
140
|
links && /* @__PURE__ */ jsx(
|
|
141
141
|
Stack,
|
|
142
142
|
{
|
|
143
|
-
|
|
143
|
+
mt: "xs",
|
|
144
|
+
gap: 4,
|
|
144
145
|
justify: "stretch",
|
|
145
146
|
align: "stretch",
|
|
146
|
-
children: links.map((link) => /* @__PURE__ */ jsx(Link, { link }, link.url))
|
|
147
|
+
children: links.map((link) => /* @__PURE__ */ jsx(Link, { value: link }, link.url))
|
|
147
148
|
}
|
|
148
149
|
)
|
|
149
150
|
] })
|
|
@@ -21,9 +21,10 @@ declare abstract class Rect {
|
|
|
21
21
|
};
|
|
22
22
|
get position(): XYPosition;
|
|
23
23
|
protected abstract parent: Compound | null;
|
|
24
|
+
constructor(xynode: InternalNode, parent?: Compound | null);
|
|
24
25
|
}
|
|
25
26
|
declare class Compound extends Rect {
|
|
26
|
-
|
|
27
|
+
readonly parent: Compound | null;
|
|
27
28
|
readonly children: Rect[];
|
|
28
29
|
constructor(xynode: InternalNode, parent?: Compound | null);
|
|
29
30
|
}
|
|
@@ -10,12 +10,23 @@ import { useSyncedRef } from "@react-hookz/web";
|
|
|
10
10
|
import { useDiagram } from "../hooks/useDiagram.js";
|
|
11
11
|
import { useXYStoreApi } from "../hooks/useXYFlow.js";
|
|
12
12
|
class Rect {
|
|
13
|
-
constructor() {
|
|
13
|
+
constructor(xynode, parent = null) {
|
|
14
14
|
__publicField(this, "id");
|
|
15
15
|
__publicField(this, "minX", Infinity);
|
|
16
16
|
__publicField(this, "minY", Infinity);
|
|
17
17
|
__publicField(this, "maxX", -Infinity);
|
|
18
18
|
__publicField(this, "maxY", -Infinity);
|
|
19
|
+
this.id = xynode.id;
|
|
20
|
+
this.positionAbsolute = !parent ? xynode.position : {
|
|
21
|
+
x: xynode.position.x + parent.minX,
|
|
22
|
+
y: xynode.position.y + parent.minY
|
|
23
|
+
};
|
|
24
|
+
const { width, height } = getNodeDimensions(xynode);
|
|
25
|
+
this.maxX = this.minX + Math.ceil(width);
|
|
26
|
+
this.maxY = this.minY + Math.ceil(height);
|
|
27
|
+
if (parent) {
|
|
28
|
+
parent.children.push(this);
|
|
29
|
+
}
|
|
19
30
|
}
|
|
20
31
|
get positionAbsolute() {
|
|
21
32
|
return {
|
|
@@ -56,27 +67,15 @@ __publicField(Rect, "TopPadding", 55);
|
|
|
56
67
|
__publicField(Rect, "BottomPadding", 40);
|
|
57
68
|
class Compound extends Rect {
|
|
58
69
|
constructor(xynode, parent = null) {
|
|
59
|
-
super();
|
|
70
|
+
super(xynode, parent);
|
|
60
71
|
__publicField(this, "children", []);
|
|
61
72
|
this.parent = parent;
|
|
62
|
-
this.id = xynode.id;
|
|
63
|
-
if (parent) {
|
|
64
|
-
parent.children.push(this);
|
|
65
|
-
}
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
75
|
class Leaf extends Rect {
|
|
69
76
|
constructor(xynode, parent = null) {
|
|
70
|
-
super();
|
|
77
|
+
super(xynode, parent);
|
|
71
78
|
this.parent = parent;
|
|
72
|
-
this.id = xynode.id;
|
|
73
|
-
this.positionAbsolute = xynode.internals.positionAbsolute;
|
|
74
|
-
const { width, height } = getNodeDimensions(xynode);
|
|
75
|
-
this.maxX = this.minX + Math.ceil(width);
|
|
76
|
-
this.maxY = this.minY + Math.ceil(height);
|
|
77
|
-
if (parent) {
|
|
78
|
-
parent.children.push(this);
|
|
79
|
-
}
|
|
80
79
|
}
|
|
81
80
|
}
|
|
82
81
|
function createLayoutConstraints(xyflowApi, editingNodeIds) {
|
|
@@ -3,6 +3,7 @@ import { useDeepCompareMemo } from "@react-hookz/web";
|
|
|
3
3
|
import { pick, hasAtLeast } from "remeda";
|
|
4
4
|
import { ZIndexes } from "../base/const.js";
|
|
5
5
|
function viewToNodesEdge(opts) {
|
|
6
|
+
var _a;
|
|
6
7
|
const {
|
|
7
8
|
view,
|
|
8
9
|
nodesDraggable: draggable,
|
|
@@ -94,7 +95,8 @@ function viewToNodesEdge(opts) {
|
|
|
94
95
|
shape: node.shape,
|
|
95
96
|
style: node.style,
|
|
96
97
|
icon: node.icon ?? null,
|
|
97
|
-
position: node.position
|
|
98
|
+
position: node.position,
|
|
99
|
+
isMultiple: ((_a = node.style) == null ? void 0 : _a.multiple) ?? false
|
|
98
100
|
};
|
|
99
101
|
if (node.kind === ElementKind.Group) {
|
|
100
102
|
xynodes.push({
|
|
@@ -12,14 +12,12 @@ var tabsTab = "paikoyd";
|
|
|
12
12
|
var tabsPanel = "paikoye";
|
|
13
13
|
var propertiesGrid = "paikoyf";
|
|
14
14
|
var propertyLabel = "paikoyg";
|
|
15
|
-
var
|
|
16
|
-
var resizeHandle = "paikoyi";
|
|
15
|
+
var resizeHandle = "paikoyh";
|
|
17
16
|
export {
|
|
18
17
|
card,
|
|
19
18
|
cardHeader,
|
|
20
19
|
dialog,
|
|
21
20
|
elementIcon,
|
|
22
|
-
elementLink,
|
|
23
21
|
propertiesGrid,
|
|
24
22
|
propertyLabel,
|
|
25
23
|
resizeHandle,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { isScopedElementView, isDeploymentView } from "@likec4/core";
|
|
3
|
-
import { Divider as Divider$1, Tooltip as Tooltip$1, Text, RemoveScroll, Card, FocusTrap, FocusTrapInitialFocus, Box, Group, CloseButton, Badge, Flex, ActionIconGroup, ActionIcon, Tabs, TabsList, TabsTab, TabsPanel, ScrollArea, Stack, UnstyledButton, ThemeIcon,
|
|
3
|
+
import { Divider as Divider$1, Tooltip as Tooltip$1, Text, RemoveScroll, Card, FocusTrap, FocusTrapInitialFocus, Box, Group, CloseButton, Badge, Flex, ActionIconGroup, ActionIcon, Tabs, TabsList, TabsTab, TabsPanel, ScrollArea, Stack, UnstyledButton, ThemeIcon, Code } from "@mantine/core";
|
|
4
4
|
import { useViewportSize, useSessionStorage, useDebouncedCallback } from "@mantine/hooks";
|
|
5
|
-
import { IconExternalLink, IconFileSymlink, IconZoomScan, IconStack2
|
|
5
|
+
import { IconExternalLink, IconFileSymlink, IconZoomScan, IconStack2 } from "@tabler/icons-react";
|
|
6
6
|
import "clsx";
|
|
7
7
|
import { useDragControls, useMotionValue, m } from "framer-motion";
|
|
8
8
|
import { memo, useCallback, useRef, useLayoutEffect } from "react";
|
|
9
9
|
import { pipe, map, partition, only, clamp, isNullish } from "remeda";
|
|
10
10
|
import { useDiagram } from "../../hooks/useDiagram.js";
|
|
11
11
|
import { useDiagramContext } from "../../hooks/useDiagramContext.js";
|
|
12
|
-
import { propertyLabel, elementIcon, dialog, card, cardHeader, title, tabsRoot, tabsList, tabsTab, tabsPanel, propertiesGrid, resizeHandle, viewButton, viewButtonTitle
|
|
12
|
+
import { propertyLabel, elementIcon, dialog, card, cardHeader, title, tabsRoot, tabsList, tabsTab, tabsPanel, propertiesGrid, resizeHandle, viewButton, viewButtonTitle } from "./ElementDetailsCard.css.js";
|
|
13
13
|
import { TabPanelDeployments } from "./TabPanelDeployments.js";
|
|
14
14
|
import { TabPanelRelationships } from "./TabPanelRelationships.js";
|
|
15
15
|
import { TabPanelStructure } from "./TabPanelStructure.js";
|
|
@@ -17,6 +17,7 @@ import { useLikeC4Model } from "../../likec4model/useLikeC4Model.js";
|
|
|
17
17
|
import { useUpdateEffect } from "../../hooks/useUpdateEffect.js";
|
|
18
18
|
import { IconRenderer } from "../../context/IconRenderer.js";
|
|
19
19
|
import { IfEnabled } from "../../context/DiagramFeatures.js";
|
|
20
|
+
import { Link } from "../../base/Link.js";
|
|
20
21
|
const Divider = Divider$1.withProps({
|
|
21
22
|
mb: 8,
|
|
22
23
|
labelPosition: "left",
|
|
@@ -344,7 +345,7 @@ const ElementDetailsCard = memo(({ fqn }) => {
|
|
|
344
345
|
elementModel.technology && /* @__PURE__ */ jsx(ElementProperty, { title: "technology", children: elementModel.technology }),
|
|
345
346
|
elementModel.links.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
346
347
|
/* @__PURE__ */ jsx(PropertyLabel, { children: "links" }),
|
|
347
|
-
/* @__PURE__ */ jsx(Stack, { gap: "xs", align: "flex-start", children: elementModel.links.map((link, i) => /* @__PURE__ */ jsx(
|
|
348
|
+
/* @__PURE__ */ jsx(Stack, { gap: "xs", align: "flex-start", children: elementModel.links.map((link, i) => /* @__PURE__ */ jsx(Link, { value: link }, i)) })
|
|
348
349
|
] }),
|
|
349
350
|
elementModel.$element.metadata && /* @__PURE__ */ jsx(ElementMetata, { value: elementModel.$element.metadata })
|
|
350
351
|
] }) }) }),
|
|
@@ -440,32 +441,6 @@ function ElementProperty({
|
|
|
440
441
|
)
|
|
441
442
|
] });
|
|
442
443
|
}
|
|
443
|
-
function ElementLink({
|
|
444
|
-
value
|
|
445
|
-
}) {
|
|
446
|
-
const url = new URL(value.url, window.location.href).toString();
|
|
447
|
-
return /* @__PURE__ */ jsx(CopyButton, { value: url, children: ({ copied, copy }) => /* @__PURE__ */ jsx(Anchor, { href: url, target: "_blank", underline: "never", className: elementLink, children: /* @__PURE__ */ jsxs(Group, { gap: 4, align: "center", wrap: "nowrap", children: [
|
|
448
|
-
/* @__PURE__ */ jsx(
|
|
449
|
-
ActionIcon,
|
|
450
|
-
{
|
|
451
|
-
tabIndex: -1,
|
|
452
|
-
size: 24,
|
|
453
|
-
variant: copied ? "light" : "subtle",
|
|
454
|
-
color: copied ? "teal" : "gray",
|
|
455
|
-
onClick: (e) => {
|
|
456
|
-
e.stopPropagation();
|
|
457
|
-
e.preventDefault();
|
|
458
|
-
copy();
|
|
459
|
-
},
|
|
460
|
-
children: copied ? /* @__PURE__ */ jsx(IconCheck, {}) : /* @__PURE__ */ jsx(IconCopy, { style: { width: "65%", opacity: 0.8 } })
|
|
461
|
-
}
|
|
462
|
-
),
|
|
463
|
-
/* @__PURE__ */ jsxs(Box, { flex: 1, children: [
|
|
464
|
-
/* @__PURE__ */ jsx(Text, { fz: "sm", truncate: true, lh: 1.3, fw: value.title ? 500 : 400, children: value.title || url }),
|
|
465
|
-
value.title && /* @__PURE__ */ jsx(Text, { component: "div", fz: 10, c: "dimmed", lh: 1.2, truncate: true, children: url })
|
|
466
|
-
] })
|
|
467
|
-
] }) }) });
|
|
468
|
-
}
|
|
469
444
|
function ElementMetata({
|
|
470
445
|
value
|
|
471
446
|
}) {
|
|
@@ -20,8 +20,8 @@ function TabPanelRelationships({
|
|
|
20
20
|
useState("view");
|
|
21
21
|
const incoming = [...element.incoming()].map((r) => r.id);
|
|
22
22
|
const outgoing = [...element.outgoing()].map((r) => r.id);
|
|
23
|
-
const incomingInView = unique(node.incoming().flatMap((e) => e.$edge.relations)
|
|
24
|
-
const outgoingInView = unique(node.outgoing().flatMap((e) => e.$edge.relations)
|
|
23
|
+
const incomingInView = unique([...node.incoming()].flatMap((e) => e.$edge.relations));
|
|
24
|
+
const outgoingInView = unique([...node.outgoing()].flatMap((e) => e.$edge.relations));
|
|
25
25
|
const notIncludedRelations = [
|
|
26
26
|
...incoming,
|
|
27
27
|
...outgoing
|
|
@@ -11,7 +11,7 @@ import { updateEdges } from "../../base/updateEdges.js";
|
|
|
11
11
|
import { updateNodes } from "../../base/updateNodes.js";
|
|
12
12
|
import { edgeTypes } from "./custom/edgeTypes.js";
|
|
13
13
|
import { nodeTypes } from "./custom/nodeTypes.js";
|
|
14
|
-
import { RelationshipDetailsActorContext, useRelationshipDetails,
|
|
14
|
+
import { RelationshipDetailsActorContext, useRelationshipDetails, useRelationshipDetailsState } from "./hooks.js";
|
|
15
15
|
import { SelectEdge } from "./SelectEdge.js";
|
|
16
16
|
import { useLayoutedDetails } from "./useLayoutedDetails.js";
|
|
17
17
|
import { useUpdateEffect } from "../../hooks/useUpdateEffect.js";
|
|
@@ -36,7 +36,7 @@ const RelationshipDetailsInner = memo(() => {
|
|
|
36
36
|
edgeId,
|
|
37
37
|
view,
|
|
38
38
|
initialized
|
|
39
|
-
} =
|
|
39
|
+
} = useRelationshipDetailsState(selector);
|
|
40
40
|
const {
|
|
41
41
|
edge,
|
|
42
42
|
xynodes,
|
|
@@ -86,9 +86,9 @@ const RelationshipDetailsInner = memo(() => {
|
|
|
86
86
|
e.stopPropagation();
|
|
87
87
|
browser.send({ type: "xyflow.paneClick" });
|
|
88
88
|
}),
|
|
89
|
-
onViewportResize: () => {
|
|
89
|
+
onViewportResize: useCallbackRef(() => {
|
|
90
90
|
browser.send({ type: "xyflow.resized" });
|
|
91
|
-
},
|
|
91
|
+
}),
|
|
92
92
|
nodesDraggable: false,
|
|
93
93
|
fitView: false,
|
|
94
94
|
pannable: true,
|
|
@@ -2,14 +2,12 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { IconZoomScan } from "@tabler/icons-react";
|
|
3
3
|
import { useEnabledFeature } from "../../../context/DiagramFeatures.js";
|
|
4
4
|
import { useDiagram } from "../../../hooks/useDiagram.js";
|
|
5
|
-
import { useRelationshipDetails } from "../hooks.js";
|
|
6
5
|
import { ElementActionButtons } from "../../../base/primitives/element/ElementActionButtons.js";
|
|
7
6
|
const ElementActions = (props) => {
|
|
8
7
|
const { enableNavigateTo } = useEnabledFeature("NavigateTo");
|
|
9
8
|
const diagram = useDiagram();
|
|
10
|
-
useRelationshipDetails();
|
|
11
9
|
const buttons = [];
|
|
12
|
-
const { navigateTo
|
|
10
|
+
const { navigateTo } = props.data;
|
|
13
11
|
if (navigateTo && enableNavigateTo) {
|
|
14
12
|
buttons.push({
|
|
15
13
|
key: "navigate",
|
|
@@ -4,8 +4,8 @@ import { Context, ReactNode, CSSProperties } from 'react';
|
|
|
4
4
|
import { GeneralHelpers, ViewportHelperFunctions } from '@xyflow/react';
|
|
5
5
|
import { EdgeMarkerType, HandleType } from '@xyflow/system';
|
|
6
6
|
export declare const RelationshipDetailsActorContext: Context<RelationshipDetailsActorRef | null>;
|
|
7
|
-
export declare function
|
|
8
|
-
export declare function
|
|
7
|
+
export declare function useRelationshipDetailsActor(): RelationshipDetailsActorRef;
|
|
8
|
+
export declare function useRelationshipDetailsState<T = unknown>(selector: (state: RelationshipDetailsSnapshot) => T, compare?: (a: NoInfer<T>, b: NoInfer<T>) => boolean): T;
|
|
9
9
|
export declare function useRelationshipDetails(): {
|
|
10
10
|
getState: () => Readonly< Input & {
|
|
11
11
|
xyflow: ( GeneralHelpers<import("./_types").RelationshipDetailsTypes.Node, {
|
|
@@ -4,16 +4,16 @@ import { useSelector } from "@xstate/react";
|
|
|
4
4
|
import { shallowEqual } from "fast-equals";
|
|
5
5
|
import { createContext, useTransition, useMemo, useContext } from "react";
|
|
6
6
|
const RelationshipDetailsActorContext = createContext(null);
|
|
7
|
-
function
|
|
8
|
-
return nonNullable(useContext(RelationshipDetailsActorContext), "No
|
|
7
|
+
function useRelationshipDetailsActor() {
|
|
8
|
+
return nonNullable(useContext(RelationshipDetailsActorContext), "No RelationshipDetailsActorContext");
|
|
9
9
|
}
|
|
10
|
-
function
|
|
10
|
+
function useRelationshipDetailsState(selector, compare = shallowEqual) {
|
|
11
11
|
const select = useCallbackRef(selector);
|
|
12
|
-
const actor =
|
|
12
|
+
const actor = useRelationshipDetailsActor();
|
|
13
13
|
return useSelector(actor, select, compare);
|
|
14
14
|
}
|
|
15
15
|
function useRelationshipDetails() {
|
|
16
|
-
const actor =
|
|
16
|
+
const actor = useRelationshipDetailsActor();
|
|
17
17
|
const [, startTransition] = useTransition();
|
|
18
18
|
return useMemo(() => ({
|
|
19
19
|
getState: () => actor.getSnapshot().context,
|
|
@@ -41,6 +41,6 @@ function useRelationshipDetails() {
|
|
|
41
41
|
export {
|
|
42
42
|
RelationshipDetailsActorContext,
|
|
43
43
|
useRelationshipDetails,
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
useRelationshipDetailsActor,
|
|
45
|
+
useRelationshipDetailsState
|
|
46
46
|
};
|
|
@@ -193,8 +193,8 @@ function layout(edge, view, likec4model) {
|
|
|
193
193
|
type: "relationship",
|
|
194
194
|
source: source.id,
|
|
195
195
|
target: target.id,
|
|
196
|
-
sourceHandle:
|
|
197
|
-
targetHandle:
|
|
196
|
+
sourceHandle: source.id + "_out" + (source.data.ports.out.length - 1),
|
|
197
|
+
targetHandle: target.id + "_in" + (target.data.ports.in.length - 1),
|
|
198
198
|
data: {
|
|
199
199
|
relationId: relation.id,
|
|
200
200
|
color: relation.color,
|
|
@@ -209,15 +209,12 @@ function layout(edge, view, likec4model) {
|
|
|
209
209
|
ctx.xyedges.push(edge2);
|
|
210
210
|
}
|
|
211
211
|
const nodebounds = applyDagreLayout(ctx.g);
|
|
212
|
-
const sortedPorts = (ports) => {
|
|
213
|
-
if (ports.length < 2) {
|
|
214
|
-
return ports;
|
|
215
|
-
}
|
|
212
|
+
const sortedPorts = (nodeId, type, ports) => {
|
|
216
213
|
return pipe(
|
|
217
214
|
ports,
|
|
218
|
-
map((port) => {
|
|
215
|
+
map((port, index) => {
|
|
219
216
|
return {
|
|
220
|
-
port,
|
|
217
|
+
port: nodeId + "_" + type + index,
|
|
221
218
|
topY: nodebounds(port).position.y
|
|
222
219
|
};
|
|
223
220
|
}),
|
|
@@ -227,8 +224,8 @@ function layout(edge, view, likec4model) {
|
|
|
227
224
|
};
|
|
228
225
|
const xynodes = [...ctx.xynodes.values()].map((node) => {
|
|
229
226
|
const { position, width, height } = nodebounds(node.id, node.parentId);
|
|
230
|
-
node.data.ports.in = sortedPorts(node.data.ports.in);
|
|
231
|
-
node.data.ports.out = sortedPorts(node.data.ports.out);
|
|
227
|
+
node.data.ports.in = sortedPorts(node.id, "in", node.data.ports.in);
|
|
228
|
+
node.data.ports.out = sortedPorts(node.id, "out", node.data.ports.out);
|
|
232
229
|
if (node.type === "element") {
|
|
233
230
|
node.data.width = width;
|
|
234
231
|
node.data.height = height;
|
|
@@ -19,7 +19,10 @@ export declare namespace LayoutRelationshipsViewResult {
|
|
|
19
19
|
column: RelationshipsBrowserTypes.Column;
|
|
20
20
|
ports: RelationshipsBrowserTypes.Ports;
|
|
21
21
|
};
|
|
22
|
-
type Edge = DiagramEdge & {
|
|
22
|
+
type Edge = DiagramEdge & {
|
|
23
|
+
sourceHandle: string;
|
|
24
|
+
targetHandle: string;
|
|
25
|
+
};
|
|
23
26
|
}
|
|
24
27
|
export declare function layoutRelationshipsView(data: RelationshipsViewData): LayoutRelationshipsViewResult;
|
|
25
28
|
export declare function useRelationshipsView(fqn: Fqn): {
|
|
@@ -195,7 +195,9 @@ function layoutRelationshipsView(data) {
|
|
|
195
195
|
edges.push({
|
|
196
196
|
name,
|
|
197
197
|
source: source.id,
|
|
198
|
+
sourceHandle: source.id + "_out" + (g.node(source.id).outPorts.length - 1),
|
|
198
199
|
target: target.id,
|
|
200
|
+
targetHandle: target.id + "_in" + (g.node(target.id).inPorts.length - 1),
|
|
199
201
|
relations: map(grouped, prop("relation"))
|
|
200
202
|
});
|
|
201
203
|
})
|
|
@@ -309,15 +311,12 @@ function layoutRelationshipsView(data) {
|
|
|
309
311
|
}
|
|
310
312
|
return 1 + Math.max(...children.map(nodeDepth));
|
|
311
313
|
}
|
|
312
|
-
const sortedPorts = (ports) => {
|
|
313
|
-
if (ports.length < 2) {
|
|
314
|
-
return ports;
|
|
315
|
-
}
|
|
314
|
+
const sortedPorts = (nodeId, type, ports) => {
|
|
316
315
|
return pipe(
|
|
317
316
|
ports,
|
|
318
|
-
map((port) => {
|
|
317
|
+
map((port, index) => {
|
|
319
318
|
return {
|
|
320
|
-
port,
|
|
319
|
+
port: nodeId + "_" + type + index,
|
|
321
320
|
topY: nodeBounds(port).position.y
|
|
322
321
|
};
|
|
323
322
|
}),
|
|
@@ -417,15 +416,15 @@ function layoutRelationshipsView(data) {
|
|
|
417
416
|
height,
|
|
418
417
|
column,
|
|
419
418
|
ports: {
|
|
420
|
-
in: sortedPorts(inPorts),
|
|
421
|
-
out: sortedPorts(outPorts)
|
|
419
|
+
in: sortedPorts(id, "in", inPorts),
|
|
420
|
+
out: sortedPorts(id, "out", outPorts)
|
|
422
421
|
}
|
|
423
422
|
};
|
|
424
423
|
});
|
|
425
424
|
return {
|
|
426
425
|
bounds: {
|
|
427
|
-
x: minX,
|
|
428
|
-
y: minY,
|
|
426
|
+
x: Math.min(minX, 0),
|
|
427
|
+
y: Math.min(minY, 0),
|
|
429
428
|
width: g.graph().width ?? 100,
|
|
430
429
|
height: g.graph().height ?? 100
|
|
431
430
|
},
|
|
@@ -437,7 +436,7 @@ function layoutRelationshipsView(data) {
|
|
|
437
436
|
if (!ename) {
|
|
438
437
|
return acc;
|
|
439
438
|
}
|
|
440
|
-
const { name, source, target, relations } = find(edges, (e2) => e2.name === ename);
|
|
439
|
+
const { name, source, target, relations, sourceHandle, targetHandle } = find(edges, (e2) => e2.name === ename);
|
|
441
440
|
const onlyRelation = only(relations);
|
|
442
441
|
const label = (onlyRelation == null ? void 0 : onlyRelation.title) ?? "untitled";
|
|
443
442
|
const isMultiple = relations.length > 1;
|
|
@@ -449,7 +448,9 @@ function layoutRelationshipsView(data) {
|
|
|
449
448
|
acc.push({
|
|
450
449
|
id: name,
|
|
451
450
|
source,
|
|
451
|
+
sourceHandle,
|
|
452
452
|
target,
|
|
453
|
+
targetHandle,
|
|
453
454
|
label: isMultiple ? `${relations.length} relationships` : label,
|
|
454
455
|
relations: relations.map((r) => r.id),
|
|
455
456
|
parent: null,
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { ActionIcon, Group, Box } from "@mantine/core";
|
|
3
|
-
import {
|
|
3
|
+
import { useCallbackRef, useStateHistory } from "@mantine/hooks";
|
|
4
4
|
import { IconX, IconChevronLeft, IconChevronRight } from "@tabler/icons-react";
|
|
5
|
-
import { ReactFlowProvider, Panel } from "@xyflow/react";
|
|
5
|
+
import { ReactFlowProvider, useStoreApi, Panel } from "@xyflow/react";
|
|
6
6
|
import clsx from "clsx";
|
|
7
|
+
import { shallowEqual } from "fast-equals";
|
|
7
8
|
import { LayoutGroup, AnimatePresence, m } from "framer-motion";
|
|
8
9
|
import { useRef, memo, useEffect } from "react";
|
|
9
10
|
import { BaseXYFlow } from "../../base/BaseXYFlow.js";
|
|
10
11
|
import { useRelationshipsView } from "./-useRelationshipsView.js";
|
|
12
|
+
import { ViewPadding } from "./const.js";
|
|
11
13
|
import { edgeTypes } from "./custom/edgeTypes.js";
|
|
12
14
|
import { nodeTypes } from "./custom/nodeTypes.js";
|
|
13
15
|
import { RelationshipsBrowserActorContext, useRelationshipsBrowser, useRelationshipsBrowserState } from "./hooks.js";
|
|
@@ -16,61 +18,43 @@ function RelationshipsBrowser({ actorRef }) {
|
|
|
16
18
|
const initialRef = useRef(null);
|
|
17
19
|
if (initialRef.current == null) {
|
|
18
20
|
initialRef.current = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
initialNodes: [],
|
|
22
|
+
initialEdges: []
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
|
-
return /* @__PURE__ */ jsx(RelationshipsBrowserActorContext.Provider, { value: actorRef, children: /* @__PURE__ */ jsx(ReactFlowProvider, { ...initialRef.current, children: /* @__PURE__ */ jsx(
|
|
25
|
+
return /* @__PURE__ */ jsx(RelationshipsBrowserActorContext.Provider, { value: actorRef, children: /* @__PURE__ */ jsx(ReactFlowProvider, { ...initialRef.current, children: /* @__PURE__ */ jsx(RelationshipsBrowserXYFlow, {}) }) });
|
|
24
26
|
}
|
|
25
27
|
const selector = (state) => ({
|
|
26
|
-
subjectId: state.context.subject,
|
|
27
28
|
initialized: state.context.initialized,
|
|
28
|
-
|
|
29
|
+
isActive: state.hasTag("active"),
|
|
29
30
|
nodes: state.context.xynodes,
|
|
30
|
-
edges: state.context.xyedges
|
|
31
|
-
closeable: state.context.closeable,
|
|
32
|
-
enableNavigationMenu: state.context.enableNavigationMenu
|
|
31
|
+
edges: state.context.xyedges
|
|
33
32
|
});
|
|
34
|
-
const
|
|
33
|
+
const selectorEq = (a, b) => a.initialized === b.initialized && a.isActive === b.isActive && shallowEqual(a.nodes, b.nodes) && shallowEqual(a.edges, b.edges);
|
|
34
|
+
const RelationshipsBrowserXYFlow = memo(() => {
|
|
35
|
+
const xystore = useStoreApi();
|
|
35
36
|
const browser = useRelationshipsBrowser();
|
|
36
37
|
const {
|
|
37
|
-
subjectId,
|
|
38
38
|
initialized,
|
|
39
|
-
|
|
39
|
+
isActive,
|
|
40
40
|
nodes,
|
|
41
|
-
edges
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
if (historySubjectId !== subjectId) {
|
|
49
|
-
historyOps.set(subjectId);
|
|
50
|
-
}
|
|
51
|
-
}, [subjectId]);
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
if (historySubjectId !== subjectId) {
|
|
54
|
-
browser.navigateTo(historySubjectId);
|
|
55
|
-
}
|
|
56
|
-
}, [historySubjectId]);
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
browser.send({ type: "update.view", layouted });
|
|
59
|
-
}, [layouted]);
|
|
60
|
-
const hasStepBack = current > 0;
|
|
61
|
-
const hasStepForward = current + 1 < history.length;
|
|
62
|
-
return /* @__PURE__ */ jsx(LayoutGroup, { children: /* @__PURE__ */ jsxs(
|
|
41
|
+
edges
|
|
42
|
+
} = useRelationshipsBrowserState(
|
|
43
|
+
selector,
|
|
44
|
+
selectorEq
|
|
45
|
+
);
|
|
46
|
+
return /* @__PURE__ */ jsx(LayoutGroup, { children: /* @__PURE__ */ jsx(
|
|
63
47
|
BaseXYFlow,
|
|
64
48
|
{
|
|
65
49
|
id: "relationships-browser",
|
|
66
50
|
nodes,
|
|
67
51
|
edges,
|
|
68
|
-
className: clsx(initialized ? "initialized" : "not-initialized"),
|
|
52
|
+
className: clsx(initialized && isActive ? "initialized" : "not-initialized"),
|
|
69
53
|
nodeTypes,
|
|
70
54
|
edgeTypes,
|
|
71
|
-
fitViewPadding:
|
|
55
|
+
fitViewPadding: ViewPadding,
|
|
72
56
|
onInit: useCallbackRef((instance) => {
|
|
73
|
-
browser.send({ type: "xyflow.init", instance });
|
|
57
|
+
browser.send({ type: "xyflow.init", instance, store: xystore });
|
|
74
58
|
}),
|
|
75
59
|
onNodeClick: useCallbackRef((e, node) => {
|
|
76
60
|
e.stopPropagation();
|
|
@@ -88,9 +72,9 @@ const RelationshipsBrowserInner = memo(() => {
|
|
|
88
72
|
e.stopPropagation();
|
|
89
73
|
browser.send({ type: "xyflow.paneDblClick" });
|
|
90
74
|
}),
|
|
91
|
-
onViewportResize: () => {
|
|
75
|
+
onViewportResize: useCallbackRef(() => {
|
|
92
76
|
browser.send({ type: "xyflow.resized" });
|
|
93
|
-
},
|
|
77
|
+
}),
|
|
94
78
|
onNodesChange: useCallbackRef((changes) => {
|
|
95
79
|
browser.send({ type: "xyflow.applyNodeChages", changes });
|
|
96
80
|
}),
|
|
@@ -101,34 +85,65 @@ const RelationshipsBrowserInner = memo(() => {
|
|
|
101
85
|
fitView: false,
|
|
102
86
|
pannable: true,
|
|
103
87
|
zoomable: true,
|
|
104
|
-
children:
|
|
105
|
-
/* @__PURE__ */ jsx(
|
|
106
|
-
TopLeftPanel,
|
|
107
|
-
{
|
|
108
|
-
enableNavigationMenu,
|
|
109
|
-
subjectId,
|
|
110
|
-
hasStepBack,
|
|
111
|
-
hasStepForward,
|
|
112
|
-
onStepBack: () => historyOps.back(),
|
|
113
|
-
onStepForward: () => historyOps.forward()
|
|
114
|
-
}
|
|
115
|
-
),
|
|
116
|
-
closeable && /* @__PURE__ */ jsx(Panel, { position: "top-right", children: /* @__PURE__ */ jsx(
|
|
117
|
-
ActionIcon,
|
|
118
|
-
{
|
|
119
|
-
variant: "default",
|
|
120
|
-
color: "gray",
|
|
121
|
-
onClick: (e) => {
|
|
122
|
-
e.stopPropagation();
|
|
123
|
-
browser.close();
|
|
124
|
-
},
|
|
125
|
-
children: /* @__PURE__ */ jsx(IconX, {})
|
|
126
|
-
}
|
|
127
|
-
) })
|
|
128
|
-
]
|
|
88
|
+
children: initialized && /* @__PURE__ */ jsx(RelationshipsBrowserInner, {})
|
|
129
89
|
}
|
|
130
90
|
) });
|
|
131
91
|
});
|
|
92
|
+
const selector2 = (state) => ({
|
|
93
|
+
subjectId: state.context.subject,
|
|
94
|
+
closeable: state.context.closeable,
|
|
95
|
+
enableNavigationMenu: state.context.enableNavigationMenu
|
|
96
|
+
});
|
|
97
|
+
const RelationshipsBrowserInner = memo(() => {
|
|
98
|
+
const browser = useRelationshipsBrowser();
|
|
99
|
+
const {
|
|
100
|
+
subjectId,
|
|
101
|
+
closeable,
|
|
102
|
+
enableNavigationMenu
|
|
103
|
+
} = useRelationshipsBrowserState(selector2);
|
|
104
|
+
const layouted = useRelationshipsView(subjectId);
|
|
105
|
+
const [historySubjectId, historyOps, { history, current }] = useStateHistory(subjectId);
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (historySubjectId !== subjectId) {
|
|
108
|
+
historyOps.set(subjectId);
|
|
109
|
+
}
|
|
110
|
+
}, [subjectId]);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (historySubjectId !== subjectId) {
|
|
113
|
+
browser.navigateTo(historySubjectId);
|
|
114
|
+
}
|
|
115
|
+
}, [historySubjectId]);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
browser.send({ type: "update.view", layouted });
|
|
118
|
+
}, [layouted]);
|
|
119
|
+
const hasStepBack = current > 0;
|
|
120
|
+
const hasStepForward = current + 1 < history.length;
|
|
121
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
TopLeftPanel,
|
|
124
|
+
{
|
|
125
|
+
enableNavigationMenu,
|
|
126
|
+
subjectId,
|
|
127
|
+
hasStepBack,
|
|
128
|
+
hasStepForward,
|
|
129
|
+
onStepBack: () => historyOps.back(),
|
|
130
|
+
onStepForward: () => historyOps.forward()
|
|
131
|
+
}
|
|
132
|
+
),
|
|
133
|
+
closeable && /* @__PURE__ */ jsx(Panel, { position: "top-right", children: /* @__PURE__ */ jsx(
|
|
134
|
+
ActionIcon,
|
|
135
|
+
{
|
|
136
|
+
variant: "default",
|
|
137
|
+
color: "gray",
|
|
138
|
+
onClick: (e) => {
|
|
139
|
+
e.stopPropagation();
|
|
140
|
+
browser.close();
|
|
141
|
+
},
|
|
142
|
+
children: /* @__PURE__ */ jsx(IconX, {})
|
|
143
|
+
}
|
|
144
|
+
) })
|
|
145
|
+
] });
|
|
146
|
+
});
|
|
132
147
|
const TopLeftPanel = ({
|
|
133
148
|
enableNavigationMenu,
|
|
134
149
|
subjectId,
|