@likec4/diagram 1.20.1 → 1.20.2
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/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/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 +1 -1
- 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 +8 -8
- 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/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/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 +1 -1
- 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
|
] })
|
|
@@ -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
|
}) {
|
|
@@ -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,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Color, DiagramNode, Fqn, RelationshipLineType, ViewId } from '@likec4/core';
|
|
1
|
+
import { Color, DiagramNode, Fqn, NonEmptyArray, RelationId, RelationshipLineType, ViewId } from '@likec4/core';
|
|
2
2
|
import { Base, NonOptional, ReactFlowEdge, ReactFlowNode } from '../../base/types';
|
|
3
3
|
export declare namespace RelationshipsBrowserTypes {
|
|
4
4
|
type Column = 'incomers' | 'subjects' | 'outgoers';
|
|
@@ -31,6 +31,7 @@ export declare namespace RelationshipsBrowserTypes {
|
|
|
31
31
|
type Node = ElementNode | CompoundNode | EmptyNode;
|
|
32
32
|
type NodeData = Node['data'];
|
|
33
33
|
type EdgeData = Base.EdgeData<{
|
|
34
|
+
relations: NonEmptyArray<RelationId>;
|
|
34
35
|
color: Color | undefined;
|
|
35
36
|
label: string | null;
|
|
36
37
|
navigateTo: ViewId | null;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { BBox, DiagramView, Fqn } from '@likec4/core';
|
|
2
|
-
import { EdgeChange, NodeChange, ReactFlowInstance } from '@xyflow/react';
|
|
2
|
+
import { EdgeChange, NodeChange, ReactFlowInstance, useStoreApi } from '@xyflow/react';
|
|
3
3
|
import { ActorLogic, ActorRefFromLogic, MachineSnapshot, SnapshotFrom } from 'xstate';
|
|
4
4
|
import { LayoutRelationshipsViewResult } from './-useRelationshipsView';
|
|
5
5
|
import { RelationshipsBrowserTypes } from './_types';
|
|
6
6
|
type XYFLowInstance = ReactFlowInstance<RelationshipsBrowserTypes.Node, RelationshipsBrowserTypes.Edge>;
|
|
7
|
+
export type XYStoreApi = ReturnType<typeof useStoreApi<RelationshipsBrowserTypes.Node, RelationshipsBrowserTypes.Edge>>;
|
|
7
8
|
export type Input = {
|
|
8
9
|
subject: Fqn;
|
|
9
10
|
scope?: DiagramView | null;
|
|
@@ -14,14 +15,17 @@ export type Context = Readonly<Input & {
|
|
|
14
15
|
closeable: boolean;
|
|
15
16
|
enableNavigationMenu: boolean;
|
|
16
17
|
xyflow: XYFLowInstance | null;
|
|
18
|
+
xystore: XYStoreApi | null;
|
|
17
19
|
initialized: boolean;
|
|
18
20
|
layouted: LayoutRelationshipsViewResult | null;
|
|
21
|
+
navigateFromNode: string | null;
|
|
19
22
|
xynodes: RelationshipsBrowserTypes.Node[];
|
|
20
23
|
xyedges: RelationshipsBrowserTypes.Edge[];
|
|
21
24
|
}>;
|
|
22
25
|
export type Events = {
|
|
23
26
|
type: 'xyflow.init';
|
|
24
27
|
instance: XYFLowInstance;
|
|
28
|
+
store: XYStoreApi;
|
|
25
29
|
} | {
|
|
26
30
|
type: 'xyflow.nodeClick';
|
|
27
31
|
node: RelationshipsBrowserTypes.Node;
|
|
@@ -46,6 +50,8 @@ export type Events = {
|
|
|
46
50
|
} | {
|
|
47
51
|
type: 'xyflow.edgeMouseLeave';
|
|
48
52
|
edge: RelationshipsBrowserTypes.Edge;
|
|
53
|
+
} | {
|
|
54
|
+
type: 'xyflow.updateNodeInternals';
|
|
49
55
|
} | {
|
|
50
56
|
type: 'fitDiagram';
|
|
51
57
|
duration?: number;
|
|
@@ -53,13 +59,20 @@ export type Events = {
|
|
|
53
59
|
} | {
|
|
54
60
|
type: 'navigate.to';
|
|
55
61
|
subject: Fqn;
|
|
62
|
+
fromNode?: string | undefined;
|
|
63
|
+
} | {
|
|
64
|
+
type: 'update.xydata';
|
|
65
|
+
xynodes: RelationshipsBrowserTypes.Node[];
|
|
66
|
+
xyedges: RelationshipsBrowserTypes.Edge[];
|
|
56
67
|
} | {
|
|
57
68
|
type: 'update.view';
|
|
58
69
|
layouted: LayoutRelationshipsViewResult;
|
|
59
70
|
} | {
|
|
60
71
|
type: 'close';
|
|
61
72
|
};
|
|
62
|
-
export declare const relationshipsBrowserActor: ActorLogic<MachineSnapshot<Context, Events, any, "
|
|
73
|
+
export declare const relationshipsBrowserActor: ActorLogic<MachineSnapshot<Context, Events, any, "initializing" | "waiting-data" | "closed" | {
|
|
74
|
+
active: "idle" | "layouting";
|
|
75
|
+
}, "active", any, any, any>, Events, Input, any, any>;
|
|
63
76
|
export type RelationshipsBrowserLogic = typeof relationshipsBrowserActor;
|
|
64
77
|
export type RelationshipsBrowserActorRef = ActorRefFromLogic<typeof relationshipsBrowserActor>;
|
|
65
78
|
export type RelationshipsBrowserSnapshot = SnapshotFrom<RelationshipsBrowserActorRef>;
|