@likec4/diagram 1.39.5 → 1.41.0
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/bundle/{chunk-CW_KClZe.js → chunk-FGcODVxo.js} +1059 -1023
- package/bundle/custom.js +61 -60
- package/bundle/index.js +2932 -764
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.js +7 -4
- package/dist/LikeC4Diagram.props.d.ts +6 -1
- package/dist/base/const.d.ts +9 -0
- package/dist/base/const.js +10 -1
- package/dist/base/index.d.ts +1 -0
- package/dist/base/primitives/MarkdownBlock.js +2 -0
- package/dist/base/primitives/edge/EdgeLabel.js +2 -1
- package/dist/base/primitives/edge/EdgeLabelContainer.js +10 -4
- package/dist/base/primitives/edge/EdgePath.js +17 -8
- package/dist/base/primitives/edge/edge.css.d.ts +0 -1
- package/dist/base/primitives/edge/edge.css.js +6 -14
- package/dist/base/primitives/element/ElementActionButtons.js +1 -3
- package/dist/base/primitives/element/ElementNodeContainer.d.ts +0 -6
- package/dist/base/primitives/element/ElementNodeContainer.js +3 -26
- package/dist/base/primitives/element/ElementTitle.js +2 -2
- package/dist/base/types.d.ts +3 -3
- package/dist/bundle/LikeC4View.js +4 -12
- package/dist/bundle/LikeC4View.props.d.ts +12 -3
- package/dist/bundle/custom.js +1 -1
- package/dist/components/Link.js +28 -20
- package/dist/custom/customNodes.d.ts +6 -0
- package/dist/custom/customNodes.js +2 -1
- package/dist/custom/index.js +1 -1
- package/dist/hooks/useDiagram.d.ts +5 -1
- package/dist/hooks/useDiagram.js +3 -0
- package/dist/hooks/useXYFlow.d.ts +4 -439
- package/dist/likec4diagram/DiagramUI.js +1 -1
- package/dist/likec4diagram/DiagramXYFlow.js +8 -4
- package/dist/likec4diagram/convert-to-xyflow.d.ts +14 -0
- package/dist/likec4diagram/convert-to-xyflow.js +29 -0
- package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +4 -4
- package/dist/likec4diagram/custom/edges/RelationshipEdge.js +0 -1
- package/dist/likec4diagram/custom/edges/SequenceStepEdge.d.ts +3 -0
- package/dist/likec4diagram/custom/edges/SequenceStepEdge.js +71 -0
- package/dist/likec4diagram/custom/index.js +7 -2
- package/dist/likec4diagram/custom/nodes/ElementActions.d.ts +2 -1
- package/dist/likec4diagram/custom/nodes/SequenceActorNode.d.ts +4 -0
- package/dist/likec4diagram/custom/nodes/SequenceActorNode.js +157 -0
- package/dist/likec4diagram/custom/nodes/index.d.ts +1 -0
- package/dist/likec4diagram/custom/nodes/nodes.d.ts +1 -2
- package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +31 -27
- package/dist/likec4diagram/types.d.ts +41 -7
- package/dist/likec4diagram/xyflow-diagram/diagram-view.d.ts +11 -0
- package/dist/likec4diagram/{useViewToNodesEdges.js → xyflow-diagram/diagram-view.js} +4 -13
- package/dist/likec4diagram/xyflow-sequence/_types.d.ts +41 -0
- package/dist/likec4diagram/xyflow-sequence/const.d.ts +17 -0
- package/dist/likec4diagram/xyflow-sequence/const.js +16 -0
- package/dist/likec4diagram/xyflow-sequence/layouter.d.ts +46 -0
- package/dist/likec4diagram/xyflow-sequence/layouter.js +408 -0
- package/dist/likec4diagram/xyflow-sequence/sequence-view.d.ts +7 -0
- package/dist/likec4diagram/xyflow-sequence/sequence-view.js +273 -0
- package/dist/likec4diagram/xyflow-sequence/utils.d.ts +14 -0
- package/dist/likec4diagram/xyflow-sequence/utils.js +92 -0
- package/dist/navigationpanel/NavigationPanelControls.js +2 -2
- package/dist/navigationpanel/controls/ViewDetailsCard.js +27 -12
- package/dist/navigationpanel/dropdown/ProjectsMenu.js +53 -44
- package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.d.ts +1 -2
- package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.js +10 -41
- package/dist/navigationpanel/walkthrough/DynamicViewControls.d.ts +292 -0
- package/dist/navigationpanel/walkthrough/DynamicViewControls.js +119 -0
- package/dist/navigationpanel/walkthrough/index.d.ts +2 -1
- package/dist/overlays/element-details/ElementDetailsCard.css.js +7 -1
- package/dist/overlays/element-details/ElementDetailsCard.js +17 -19
- package/dist/overlays/relationship-details/RelationshipDetails.js +4 -1
- package/dist/overlays/relationship-details/layout.d.ts +3 -2
- package/dist/overlays/relationship-details/layout.js +1 -2
- package/dist/overlays/relationships-browser/RelationshipsBrowser.js +2 -1
- package/dist/overlays/relationships-browser/layout.js +1 -1
- package/dist/search/components/ElementsColumn.js +1 -1
- package/dist/state/DiagramActorProvider.d.ts +3 -2
- package/dist/state/DiagramActorProvider.js +40 -41
- package/dist/state/assign.js +11 -4
- package/dist/state/diagram-machine.d.ts +224 -194
- package/dist/state/diagram-machine.js +170 -63
- package/dist/state/utils.d.ts +7 -1
- package/dist/state/utils.js +67 -7
- package/dist/styles-min.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css2.js +1 -1
- package/package.json +8 -7
- package/panda.buildinfo.json +45 -24
- package/src/LikeC4Diagram.props.ts +14 -1
- package/src/LikeC4Diagram.tsx +7 -4
- package/src/base/const.ts +12 -0
- package/src/base/index.ts +2 -0
- package/src/base/primitives/MarkdownBlock.tsx +2 -0
- package/src/base/primitives/edge/EdgeLabel.tsx +23 -19
- package/src/base/primitives/edge/EdgeLabelContainer.tsx +12 -7
- package/src/base/primitives/edge/EdgePath.tsx +25 -14
- package/src/base/primitives/edge/edge.css.ts +5 -14
- package/src/base/primitives/element/ElementActionButtons.tsx +1 -3
- package/src/base/primitives/element/ElementNodeContainer.tsx +3 -30
- package/src/base/primitives/element/ElementTitle.tsx +2 -3
- package/src/base/types.ts +7 -5
- package/src/bundle/LikeC4View.props.ts +14 -3
- package/src/bundle/LikeC4View.tsx +4 -14
- package/src/bundle/ReactLikeC4.tsx +1 -2
- package/src/components/Link.tsx +21 -18
- package/src/custom/customNodes.ts +7 -0
- package/src/hooks/useDiagram.ts +10 -0
- package/src/likec4diagram/DiagramUI.tsx +1 -1
- package/src/likec4diagram/DiagramXYFlow.tsx +10 -5
- package/src/likec4diagram/convert-to-xyflow.ts +45 -0
- package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +0 -1
- package/src/likec4diagram/custom/edges/SequenceStepEdge.tsx +65 -0
- package/src/likec4diagram/custom/index.ts +7 -1
- package/src/likec4diagram/custom/nodes/ElementActions.tsx +4 -2
- package/src/likec4diagram/custom/nodes/SequenceActorNode.tsx +175 -0
- package/src/likec4diagram/custom/nodes/index.ts +1 -0
- package/src/likec4diagram/custom/nodes/nodes.tsx +1 -1
- package/src/likec4diagram/relationship-popover/RelationshipPopover.tsx +36 -30
- package/src/likec4diagram/types.ts +96 -13
- package/src/likec4diagram/{useViewToNodesEdges.ts → xyflow-diagram/diagram-view.ts} +7 -28
- package/src/likec4diagram/xyflow-sequence/_types.ts +45 -0
- package/src/likec4diagram/xyflow-sequence/const.ts +37 -0
- package/src/likec4diagram/xyflow-sequence/layouter.ts +567 -0
- package/src/likec4diagram/xyflow-sequence/sequence-view.ts +337 -0
- package/src/likec4diagram/xyflow-sequence/utils.ts +112 -0
- package/src/navigationpanel/NavigationPanelControls.tsx +2 -2
- package/src/navigationpanel/controls/ViewDetailsCard.tsx +29 -12
- package/src/navigationpanel/dropdown/ProjectsMenu.tsx +5 -1
- package/src/navigationpanel/walkthrough/ActiveWalkthroughControls.tsx +5 -40
- package/src/navigationpanel/walkthrough/DynamicViewControls.tsx +125 -0
- package/src/navigationpanel/walkthrough/index.tsx +2 -1
- package/src/overlays/element-details/ElementDetailsCard.css.ts +7 -1
- package/src/overlays/element-details/ElementDetailsCard.tsx +24 -25
- package/src/overlays/relationship-details/RelationshipDetails.tsx +5 -2
- package/src/overlays/relationship-details/layout.ts +4 -3
- package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +2 -1
- package/src/overlays/relationships-browser/layout.ts +1 -1
- package/src/search/components/ElementsColumn.tsx +1 -1
- package/src/state/DiagramActorProvider.tsx +46 -51
- package/src/state/assign.ts +18 -5
- package/src/state/diagram-machine.ts +207 -75
- package/src/state/utils.ts +81 -7
- package/dist/likec4diagram/useViewToNodesEdges.d.ts +0 -12
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { invariant } from '@likec4/core'
|
|
2
|
+
import type { DynamicViewDisplayVariant } from '@likec4/core/types'
|
|
3
|
+
import { css } from '@likec4/styles/css'
|
|
4
|
+
import { type ButtonProps, Button, SegmentedControl } from '@mantine/core'
|
|
5
|
+
import {
|
|
6
|
+
IconPlayerPlayFilled,
|
|
7
|
+
} from '@tabler/icons-react'
|
|
8
|
+
import { type HTMLMotionProps } from 'motion/react'
|
|
9
|
+
import * as m from 'motion/react-m'
|
|
10
|
+
import { forwardRef } from 'react'
|
|
11
|
+
import { useDiagram, useDiagramContext } from '../../hooks/useDiagram'
|
|
12
|
+
import { Tooltip } from '../_common'
|
|
13
|
+
import { useNavigationActor } from '../hooks'
|
|
14
|
+
|
|
15
|
+
export const TriggerWalkthroughButton = forwardRef<HTMLButtonElement, ButtonProps & HTMLMotionProps<'button'>>((
|
|
16
|
+
props,
|
|
17
|
+
ref,
|
|
18
|
+
) => (
|
|
19
|
+
<Button
|
|
20
|
+
variant="filled"
|
|
21
|
+
size="xs"
|
|
22
|
+
fw="500"
|
|
23
|
+
{...props}
|
|
24
|
+
ref={ref}
|
|
25
|
+
component={m.button}
|
|
26
|
+
layoutId={'trigger-dynamic-walkthrough'}
|
|
27
|
+
className={css({
|
|
28
|
+
flexShrink: 0,
|
|
29
|
+
})}
|
|
30
|
+
/>
|
|
31
|
+
))
|
|
32
|
+
|
|
33
|
+
function StartWalkthroughButton({ onClick }: { onClick: () => void }) {
|
|
34
|
+
const diagram = useDiagram()
|
|
35
|
+
const actor = useNavigationActor()
|
|
36
|
+
return (
|
|
37
|
+
<Tooltip label="Start Dynamic View Walkthrough">
|
|
38
|
+
<TriggerWalkthroughButton
|
|
39
|
+
onClick={e => {
|
|
40
|
+
e.stopPropagation()
|
|
41
|
+
actor.closeDropdown()
|
|
42
|
+
diagram.startWalkthrough()
|
|
43
|
+
}}
|
|
44
|
+
size="compact-xs"
|
|
45
|
+
h={26}
|
|
46
|
+
classNames={{
|
|
47
|
+
label: css({
|
|
48
|
+
display: {
|
|
49
|
+
base: 'none',
|
|
50
|
+
'@/md': '[inherit]',
|
|
51
|
+
},
|
|
52
|
+
}),
|
|
53
|
+
section: css({
|
|
54
|
+
marginInlineStart: {
|
|
55
|
+
base: '0',
|
|
56
|
+
'@/md': '2',
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
}}
|
|
60
|
+
rightSection={<IconPlayerPlayFilled size={10} />}
|
|
61
|
+
>
|
|
62
|
+
Start
|
|
63
|
+
</TriggerWalkthroughButton>
|
|
64
|
+
</Tooltip>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function DynamicViewModeSwitcher({
|
|
69
|
+
value,
|
|
70
|
+
onChange,
|
|
71
|
+
}: {
|
|
72
|
+
value: DynamicViewDisplayVariant
|
|
73
|
+
onChange: (variant: DynamicViewDisplayVariant) => void
|
|
74
|
+
}) {
|
|
75
|
+
return (
|
|
76
|
+
<m.div layout="position">
|
|
77
|
+
<SegmentedControl
|
|
78
|
+
size="xs"
|
|
79
|
+
value={value}
|
|
80
|
+
component={m.div}
|
|
81
|
+
onChange={variant => {
|
|
82
|
+
invariant(variant === 'diagram' || variant === 'sequence', 'Invalid dynamic view variant')
|
|
83
|
+
onChange(variant)
|
|
84
|
+
}}
|
|
85
|
+
classNames={{
|
|
86
|
+
label: css({
|
|
87
|
+
fontSize: 'xxs',
|
|
88
|
+
}),
|
|
89
|
+
}}
|
|
90
|
+
data={[
|
|
91
|
+
{
|
|
92
|
+
value: 'diagram',
|
|
93
|
+
label: 'Diagram',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
value: 'sequence',
|
|
97
|
+
label: 'Sequence',
|
|
98
|
+
},
|
|
99
|
+
]} />
|
|
100
|
+
</m.div>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function DynamicViewControls() {
|
|
105
|
+
const dynamicViewVariant = useDiagramContext(c => c.dynamicViewVariant)
|
|
106
|
+
const diagram = useDiagram()
|
|
107
|
+
const actor = useNavigationActor()
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
<DynamicViewModeSwitcher
|
|
111
|
+
key="dynamic-view-mode-switcher"
|
|
112
|
+
value={dynamicViewVariant}
|
|
113
|
+
onChange={mode => {
|
|
114
|
+
diagram.switchDynamicViewVariant(mode)
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
<StartWalkthroughButton
|
|
118
|
+
key="trigger-dynamic-walkthrough"
|
|
119
|
+
onClick={() => {
|
|
120
|
+
actor.closeDropdown()
|
|
121
|
+
diagram.startWalkthrough()
|
|
122
|
+
}} />
|
|
123
|
+
</>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { ActiveWalkthroughControls
|
|
1
|
+
export { ActiveWalkthroughControls } from './ActiveWalkthroughControls'
|
|
2
|
+
export { DynamicViewControls } from './DynamicViewControls'
|
|
@@ -25,13 +25,19 @@ export const dialog = css({
|
|
|
25
25
|
export const card = css({
|
|
26
26
|
position: 'absolute',
|
|
27
27
|
pointerEvents: 'all',
|
|
28
|
+
display: 'flex',
|
|
29
|
+
flexDirection: 'column',
|
|
30
|
+
padding: '4',
|
|
28
31
|
gap: 'lg',
|
|
29
32
|
justifyContent: 'stretch',
|
|
33
|
+
color: 'mantine.colors.text',
|
|
30
34
|
backgroundColor: {
|
|
31
35
|
base: 'mantine.colors.body',
|
|
32
36
|
_dark: 'mantine.colors.dark[6]',
|
|
33
37
|
},
|
|
34
|
-
|
|
38
|
+
boxShadow: 'md',
|
|
39
|
+
overflow: 'hidden',
|
|
40
|
+
border: 'none',
|
|
35
41
|
backgroundImage: `
|
|
36
42
|
linear-gradient(180deg,
|
|
37
43
|
color-mix(in srgb, var(--likec4-palette-fill) 60%, transparent),
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
ActionIconGroup,
|
|
17
17
|
Badge,
|
|
18
18
|
Box,
|
|
19
|
-
Card,
|
|
20
19
|
CloseButton,
|
|
21
20
|
Divider as MantineDivider,
|
|
22
21
|
Flex,
|
|
@@ -48,7 +47,7 @@ import { DiagramFeatures, IconRenderer, IfEnabled } from '../../context'
|
|
|
48
47
|
import { useUpdateEffect } from '../../hooks'
|
|
49
48
|
import { useDiagram } from '../../hooks/useDiagram'
|
|
50
49
|
import type { OnNavigateTo } from '../../LikeC4Diagram.props'
|
|
51
|
-
import {
|
|
50
|
+
import { useCurrentViewModel } from '../../likec4model'
|
|
52
51
|
import { stopPropagation } from '../../utils'
|
|
53
52
|
import * as styles from './ElementDetailsCard.css'
|
|
54
53
|
import { TabPanelDeployments } from './TabPanelDeployments'
|
|
@@ -115,8 +114,7 @@ export function ElementDetailsCard({
|
|
|
115
114
|
defaultValue: 'Properties',
|
|
116
115
|
})
|
|
117
116
|
const diagram = useDiagram()
|
|
118
|
-
const
|
|
119
|
-
const viewModel = likec4model.view(viewId)
|
|
117
|
+
const viewModel = useCurrentViewModel()
|
|
120
118
|
const nodeModel = fromNode ? viewModel.findNode(fromNode) : viewModel.findNodeWithElement(fqn)
|
|
121
119
|
|
|
122
120
|
const elementModel = viewModel.$model.element(fqn)
|
|
@@ -221,7 +219,7 @@ export function ElementDetailsCard({
|
|
|
221
219
|
*/
|
|
222
220
|
useTimeoutEffect(() => {
|
|
223
221
|
setOpened(true)
|
|
224
|
-
},
|
|
222
|
+
}, 220)
|
|
225
223
|
|
|
226
224
|
return (
|
|
227
225
|
<m.dialog
|
|
@@ -257,9 +255,7 @@ export function ElementDetailsCard({
|
|
|
257
255
|
}}
|
|
258
256
|
>
|
|
259
257
|
<RemoveScroll forwardProps removeScrollBar={false}>
|
|
260
|
-
<
|
|
261
|
-
shadow="md"
|
|
262
|
-
component={m.div}
|
|
258
|
+
<m.div
|
|
263
259
|
layout
|
|
264
260
|
layoutRoot
|
|
265
261
|
drag
|
|
@@ -292,13 +288,12 @@ export function ElementDetailsCard({
|
|
|
292
288
|
},
|
|
293
289
|
}}
|
|
294
290
|
style={{
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
height: height as any,
|
|
291
|
+
width,
|
|
292
|
+
height,
|
|
298
293
|
}}>
|
|
299
294
|
<div className={styles.cardHeader} onPointerDown={e => controls.start(e)}>
|
|
300
|
-
<
|
|
301
|
-
<
|
|
295
|
+
<HStack alignItems="start" justify="space-between" gap={'sm'} mb={'sm'} flexWrap="nowrap">
|
|
296
|
+
<HStack alignItems="start" gap={'sm'} style={{ cursor: 'default' }} flexWrap="nowrap">
|
|
302
297
|
{elementIcon}
|
|
303
298
|
<div>
|
|
304
299
|
<Text
|
|
@@ -312,15 +307,15 @@ export function ElementDetailsCard({
|
|
|
312
307
|
</Text>
|
|
313
308
|
)}
|
|
314
309
|
</div>
|
|
315
|
-
</
|
|
310
|
+
</HStack>
|
|
316
311
|
<CloseButton
|
|
317
312
|
size={'lg'}
|
|
318
313
|
onClick={e => {
|
|
319
314
|
e.stopPropagation()
|
|
320
315
|
close()
|
|
321
316
|
}} />
|
|
322
|
-
</
|
|
323
|
-
<
|
|
317
|
+
</HStack>
|
|
318
|
+
<HStack alignItems="baseline" gap={'sm'} flexWrap="nowrap">
|
|
324
319
|
<div>
|
|
325
320
|
<SmallLabel>kind</SmallLabel>
|
|
326
321
|
<Badge
|
|
@@ -403,7 +398,7 @@ export function ElementDetailsCard({
|
|
|
403
398
|
</Tooltip>
|
|
404
399
|
)}
|
|
405
400
|
</ActionIconGroup>
|
|
406
|
-
</
|
|
401
|
+
</HStack>
|
|
407
402
|
</div>
|
|
408
403
|
<Tabs
|
|
409
404
|
value={activeTab}
|
|
@@ -426,6 +421,12 @@ export function ElementDetailsCard({
|
|
|
426
421
|
<TabsPanel value="Properties">
|
|
427
422
|
<ScrollArea scrollbars="y" type="scroll" offsetScrollbars>
|
|
428
423
|
<Box className={styles.propertiesGrid} pt={'xs'}>
|
|
424
|
+
{elementModel.hasSummary && (
|
|
425
|
+
<>
|
|
426
|
+
<PropertyLabel>summary</PropertyLabel>
|
|
427
|
+
<MarkdownBlock value={elementModel.summary} />
|
|
428
|
+
</>
|
|
429
|
+
)}
|
|
429
430
|
<>
|
|
430
431
|
<PropertyLabel>description</PropertyLabel>
|
|
431
432
|
<MarkdownBlock
|
|
@@ -517,7 +518,7 @@ export function ElementDetailsCard({
|
|
|
517
518
|
dragMomentum={false}
|
|
518
519
|
onDrag={handleDrag}
|
|
519
520
|
dragConstraints={{ top: 0, left: 0, right: 0, bottom: 0 }} />
|
|
520
|
-
</
|
|
521
|
+
</m.div>
|
|
521
522
|
</RemoveScroll>
|
|
522
523
|
</m.dialog>
|
|
523
524
|
)
|
|
@@ -609,12 +610,10 @@ function ElementMetata({
|
|
|
609
610
|
{entries(metadata).map(([key, value]) => (
|
|
610
611
|
<div
|
|
611
612
|
key={key}
|
|
612
|
-
|
|
613
|
-
'
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
}),
|
|
617
|
-
)}
|
|
613
|
+
style={{
|
|
614
|
+
display: 'contents',
|
|
615
|
+
}}
|
|
616
|
+
className={'group'}
|
|
618
617
|
>
|
|
619
618
|
<div
|
|
620
619
|
className={css({
|
|
@@ -651,7 +650,7 @@ function ElementMetata({
|
|
|
651
650
|
fontSize: 'sm',
|
|
652
651
|
padding: 'xxs',
|
|
653
652
|
whiteSpace: 'pre',
|
|
654
|
-
fontFamily: '
|
|
653
|
+
fontFamily: 'mono',
|
|
655
654
|
userSelect: 'all',
|
|
656
655
|
})}>
|
|
657
656
|
{value}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DiagramEdge, type DiagramView, invariant, isAncestor, nonNullable } from '@likec4/core'
|
|
2
|
-
import { cx
|
|
2
|
+
import { cx } from '@likec4/styles/css'
|
|
3
3
|
import { ActionIcon, Group } from '@mantine/core'
|
|
4
4
|
import { useCallbackRef, useStateHistory } from '@mantine/hooks'
|
|
5
5
|
import { IconChevronLeft, IconChevronRight, IconX } from '@tabler/icons-react'
|
|
@@ -145,7 +145,10 @@ const RelationshipDetailsInner = memo(() => {
|
|
|
145
145
|
id={browser.rootElementId}
|
|
146
146
|
nodes={nodes}
|
|
147
147
|
edges={edges}
|
|
148
|
-
className={
|
|
148
|
+
className={cx(
|
|
149
|
+
initialized ? 'initialized' : 'not-initialized',
|
|
150
|
+
'likec4-relationship-details',
|
|
151
|
+
)}
|
|
149
152
|
nodeTypes={nodeTypes}
|
|
150
153
|
edgeTypes={edgeTypes}
|
|
151
154
|
onNodesChange={useCallbackRef((changes) => {
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
sortBy,
|
|
35
35
|
tap,
|
|
36
36
|
} from 'remeda'
|
|
37
|
+
import type { Except } from 'type-fest'
|
|
37
38
|
import type { RelationshipDetailsTypes } from './_types'
|
|
38
39
|
import type { RelationshipDetailsViewData } from './compute'
|
|
39
40
|
|
|
@@ -218,14 +219,14 @@ export type LayoutResult = {
|
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
export namespace LayoutResult {
|
|
221
|
-
export type Node =
|
|
222
|
+
export type Node = Except<DiagramNode, 'modelRef' | 'description' | 'deploymentRef' | 'inEdges' | 'outEdges'> & {
|
|
222
223
|
description: RichTextOrEmpty
|
|
223
224
|
modelRef: Fqn
|
|
224
225
|
column: RelationshipDetailsTypes.Column
|
|
225
226
|
ports: RelationshipDetailsTypes.Ports
|
|
226
227
|
// existsInCurrentView: boolean
|
|
227
228
|
}
|
|
228
|
-
export type Edge =
|
|
229
|
+
export type Edge = Except<DiagramEdge, 'relations' | 'description'> & {
|
|
229
230
|
relationId: RelationId
|
|
230
231
|
sourceHandle: string
|
|
231
232
|
targetHandle: string
|
|
@@ -402,7 +403,7 @@ export function layoutRelationshipDetails(
|
|
|
402
403
|
y: position.y,
|
|
403
404
|
position: [position.x, position.y],
|
|
404
405
|
title: element.title,
|
|
405
|
-
description:
|
|
406
|
+
description: element.summary,
|
|
406
407
|
technology: element.technology,
|
|
407
408
|
tags: [...element.tags],
|
|
408
409
|
links: null,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cx } from '@likec4/styles/css'
|
|
2
2
|
import { ActionIcon, Group } from '@mantine/core'
|
|
3
3
|
import { useCallbackRef, useStateHistory } from '@mantine/hooks'
|
|
4
|
+
import { useRafEffect } from '@react-hookz/web'
|
|
4
5
|
import { IconChevronLeft, IconChevronRight, IconX } from '@tabler/icons-react'
|
|
5
6
|
import { Panel, ReactFlowProvider, useReactFlow, useStoreApi } from '@xyflow/react'
|
|
6
7
|
import { shallowEqual } from 'fast-equals'
|
|
@@ -183,7 +184,7 @@ const RelationshipsBrowserInner = memo(() => {
|
|
|
183
184
|
}
|
|
184
185
|
}, [historySubjectId, browser])
|
|
185
186
|
|
|
186
|
-
|
|
187
|
+
useRafEffect(() => {
|
|
187
188
|
browser.updateView(layouted)
|
|
188
189
|
}, [layouted, browser])
|
|
189
190
|
|
|
@@ -518,7 +518,7 @@ export function layoutRelationshipsView(
|
|
|
518
518
|
y: position.y,
|
|
519
519
|
position: [position.x, position.y],
|
|
520
520
|
title: element.title,
|
|
521
|
-
description:
|
|
521
|
+
description: element.summary,
|
|
522
522
|
technology: element.technology,
|
|
523
523
|
tags: [...element.tags],
|
|
524
524
|
links: null,
|
|
@@ -279,7 +279,7 @@ function ElementTreeNode(
|
|
|
279
279
|
</Tooltip>
|
|
280
280
|
</Group>
|
|
281
281
|
<Highlight component="div" highlight={searchTerms} className={btn.description!} lineClamp={1}>
|
|
282
|
-
{element.
|
|
282
|
+
{element.summary.text || 'No description'}
|
|
283
283
|
</Highlight>
|
|
284
284
|
</Box>
|
|
285
285
|
|
|
@@ -1,32 +1,25 @@
|
|
|
1
|
-
import type { DiagramView, WhereOperator } from '@likec4/core/types'
|
|
2
|
-
import { useCustomCompareEffect } from '@react-hookz/web'
|
|
1
|
+
import type { DiagramView, DynamicViewDisplayVariant, WhereOperator } from '@likec4/core/types'
|
|
2
|
+
import { useCustomCompareEffect, useRafEffect } from '@react-hookz/web'
|
|
3
3
|
import { useActorRef, useSelector } from '@xstate/react'
|
|
4
4
|
import { useStoreApi } from '@xyflow/react'
|
|
5
5
|
import { deepEqual, shallowEqual } from 'fast-equals'
|
|
6
|
-
import { type PropsWithChildren,
|
|
6
|
+
import { type PropsWithChildren, useMemo, useRef } from 'react'
|
|
7
7
|
import { ErrorBoundary } from '../components/ErrorFallback'
|
|
8
8
|
import { useDiagramEventHandlers } from '../context/DiagramEventHandlers'
|
|
9
9
|
import { DiagramFeatures, useEnabledFeatures } from '../context/DiagramFeatures'
|
|
10
10
|
import { useOnDiagramEvent } from '../custom'
|
|
11
11
|
import { DiagramActorContextProvider } from '../hooks/safeContext'
|
|
12
|
-
import { useCurrentViewId } from '../hooks/useCurrentViewId'
|
|
13
12
|
import type { ViewPadding } from '../LikeC4Diagram.props'
|
|
13
|
+
import { convertToXYFlow } from '../likec4diagram/convert-to-xyflow'
|
|
14
14
|
import type { Types } from '../likec4diagram/types'
|
|
15
|
-
import { useViewToNodesEdges } from '../likec4diagram/useViewToNodesEdges'
|
|
16
15
|
import { CurrentViewModelContext } from '../likec4model/LikeC4ModelContext'
|
|
17
16
|
import { useLikeC4Model } from '../likec4model/useLikeC4Model'
|
|
18
17
|
import { type DiagramMachine, diagramMachine } from './diagram-machine'
|
|
19
18
|
import { syncManualLayoutActorLogic } from './syncManualLayoutActor'
|
|
20
19
|
import type { DiagramActorRef, DiagramActorSnapshot } from './types'
|
|
21
20
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
...state.context.toggledFeatures,
|
|
26
|
-
enableReadOnly: true,
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return state.context.toggledFeatures
|
|
21
|
+
const selectDynamicViewVariant = (state: DiagramActorSnapshot) => {
|
|
22
|
+
return state.context.dynamicViewVariant
|
|
30
23
|
}
|
|
31
24
|
|
|
32
25
|
export function DiagramActorProvider({
|
|
@@ -37,6 +30,7 @@ export function DiagramActorProvider({
|
|
|
37
30
|
nodesSelectable,
|
|
38
31
|
where,
|
|
39
32
|
children,
|
|
33
|
+
dynamicViewVariant: _defaultVariant,
|
|
40
34
|
}: PropsWithChildren<{
|
|
41
35
|
view: DiagramView
|
|
42
36
|
zoomable: boolean
|
|
@@ -44,6 +38,7 @@ export function DiagramActorProvider({
|
|
|
44
38
|
fitViewPadding: ViewPadding
|
|
45
39
|
nodesSelectable: boolean
|
|
46
40
|
where: WhereOperator | null
|
|
41
|
+
dynamicViewVariant: DynamicViewDisplayVariant | undefined
|
|
47
42
|
}>) {
|
|
48
43
|
const { handlersRef } = useDiagramEventHandlers()
|
|
49
44
|
const xystore = useStoreApi<Types.Node, Types.Edge>()
|
|
@@ -76,6 +71,7 @@ export function DiagramActorProvider({
|
|
|
76
71
|
pannable,
|
|
77
72
|
fitViewPadding,
|
|
78
73
|
nodesSelectable,
|
|
74
|
+
dynamicViewVariant: _defaultVariant,
|
|
79
75
|
},
|
|
80
76
|
},
|
|
81
77
|
)
|
|
@@ -97,39 +93,56 @@ export function DiagramActorProvider({
|
|
|
97
93
|
deepEqual,
|
|
98
94
|
)
|
|
99
95
|
|
|
100
|
-
const
|
|
101
|
-
view,
|
|
102
|
-
where,
|
|
103
|
-
nodesSelectable,
|
|
104
|
-
})
|
|
96
|
+
const dynamicViewVariant = useSelector(actorRef, selectDynamicViewVariant)
|
|
105
97
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
98
|
+
const update = useMemo(
|
|
99
|
+
() => convertToXYFlow({ view, where, nodesSelectable, dynamicViewVariant }),
|
|
100
|
+
[view, where, nodesSelectable, dynamicViewVariant],
|
|
101
|
+
)
|
|
109
102
|
|
|
110
|
-
|
|
103
|
+
useRafEffect(() => {
|
|
104
|
+
actorRef.send({
|
|
105
|
+
type: 'update.view',
|
|
106
|
+
...update,
|
|
107
|
+
})
|
|
108
|
+
}, [actorRef, update])
|
|
111
109
|
|
|
112
110
|
return (
|
|
113
111
|
<DiagramActorContextProvider value={actorRef}>
|
|
114
|
-
<
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
</ErrorBoundary>
|
|
120
|
-
</DiagramFeatures>
|
|
112
|
+
<ErrorBoundary>
|
|
113
|
+
<CurrentViewModelProvider actorRef={actorRef}>
|
|
114
|
+
{children}
|
|
115
|
+
</CurrentViewModelProvider>
|
|
116
|
+
</ErrorBoundary>
|
|
121
117
|
<DiagramActorEventListener actorRef={actorRef} />
|
|
122
118
|
</DiagramActorContextProvider>
|
|
123
119
|
)
|
|
124
120
|
}
|
|
125
121
|
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
const selectViewIdAndToggledFeatures = (state: DiagramActorSnapshot) => {
|
|
123
|
+
if (state.context.features.enableReadOnly || state.context.activeWalkthrough) {
|
|
124
|
+
return {
|
|
125
|
+
viewId: state.context.view.id,
|
|
126
|
+
toggledFeatures: {
|
|
127
|
+
...state.context.toggledFeatures,
|
|
128
|
+
enableReadOnly: true,
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
viewId: state.context.view.id,
|
|
134
|
+
toggledFeatures: state.context.toggledFeatures,
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function CurrentViewModelProvider({ children, actorRef }: PropsWithChildren<{ actorRef: DiagramActorRef }>) {
|
|
138
|
+
const { viewId, toggledFeatures } = useSelector(actorRef, selectViewIdAndToggledFeatures, deepEqual)
|
|
128
139
|
const likec4model = useLikeC4Model()
|
|
129
140
|
const viewmodel = likec4model.findView(viewId)
|
|
130
141
|
return (
|
|
131
142
|
<CurrentViewModelContext.Provider value={viewmodel}>
|
|
132
|
-
{
|
|
143
|
+
<DiagramFeatures overrides={toggledFeatures}>
|
|
144
|
+
{children}
|
|
145
|
+
</DiagramFeatures>
|
|
133
146
|
</CurrentViewModelContext.Provider>
|
|
134
147
|
)
|
|
135
148
|
}
|
|
@@ -141,25 +154,7 @@ function DiagramActorEventListener({ actorRef }: { actorRef: DiagramActorRef })
|
|
|
141
154
|
} = useDiagramEventHandlers()
|
|
142
155
|
|
|
143
156
|
useOnDiagramEvent('openSource', ({ params }) => onOpenSource?.(params))
|
|
144
|
-
|
|
145
|
-
// onNavigateTo we defer the callback for better responsiveness
|
|
146
|
-
// (allowing animation to finish)
|
|
147
|
-
useEffect(() => {
|
|
148
|
-
if (!onNavigateTo) return
|
|
149
|
-
let frame: number
|
|
150
|
-
|
|
151
|
-
const subscription = actorRef.on('navigateTo', ({ viewId }) => {
|
|
152
|
-
cancelAnimationFrame(frame)
|
|
153
|
-
// Slightly defer callback for better responsiveness
|
|
154
|
-
frame = requestAnimationFrame(() => {
|
|
155
|
-
onNavigateTo(viewId)
|
|
156
|
-
})
|
|
157
|
-
})
|
|
158
|
-
return () => {
|
|
159
|
-
cancelAnimationFrame(frame)
|
|
160
|
-
subscription.unsubscribe()
|
|
161
|
-
}
|
|
162
|
-
}, [actorRef, onNavigateTo])
|
|
157
|
+
useOnDiagramEvent('navigateTo', ({ viewId }) => onNavigateTo?.(viewId))
|
|
163
158
|
|
|
164
159
|
return null
|
|
165
160
|
}
|
package/src/state/assign.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { isEmpty, mergeDeep, omit } from 'remeda'
|
|
|
5
5
|
import { assertEvent } from 'xstate'
|
|
6
6
|
import { Base } from '../base/types'
|
|
7
7
|
import type { Types } from '../likec4diagram/types'
|
|
8
|
+
import { SeqParallelAreaColor } from '../likec4diagram/xyflow-sequence/const'
|
|
8
9
|
import { type Vector, vector, VectorImpl } from '../utils/vector'
|
|
9
10
|
import type { ActionArg, Context as DiagramContext } from './diagram-machine'
|
|
10
11
|
|
|
@@ -68,21 +69,25 @@ export function mergeXYNodesEdges({ context, event }: ActionArg): Partial<Diagra
|
|
|
68
69
|
const currentEdges = context.xyedges
|
|
69
70
|
xyedges = event.xyedges.map((update): Types.Edge => {
|
|
70
71
|
const existing = currentEdges.find(n => n.id === update.id)
|
|
71
|
-
if (existing) {
|
|
72
|
+
if (existing && existing.type === update.type) {
|
|
72
73
|
if (
|
|
73
74
|
eq(existing.hidden ?? false, update.hidden ?? false)
|
|
74
75
|
&& eq(existing.data, update.data)
|
|
76
|
+
&& eq(existing.source, update.source)
|
|
77
|
+
&& eq(existing.target, update.target)
|
|
78
|
+
&& eq(existing.sourceHandle, update.sourceHandle)
|
|
79
|
+
&& eq(existing.targetHandle, update.targetHandle)
|
|
75
80
|
) {
|
|
76
81
|
return existing
|
|
77
82
|
}
|
|
78
83
|
return {
|
|
79
|
-
...existing,
|
|
84
|
+
...omit(existing, ['sourceHandle', 'targetHandle']),
|
|
80
85
|
...update,
|
|
81
86
|
data: {
|
|
82
87
|
...existing.data,
|
|
83
88
|
...update.data,
|
|
84
89
|
},
|
|
85
|
-
}
|
|
90
|
+
} as Types.Edge
|
|
86
91
|
}
|
|
87
92
|
return update
|
|
88
93
|
})
|
|
@@ -388,7 +393,7 @@ export function resetEdgeControlPoints({ context }: ActionArg): Partial<DiagramC
|
|
|
388
393
|
...edge.data,
|
|
389
394
|
controlPoints: getControlPointForEdge(edge),
|
|
390
395
|
},
|
|
391
|
-
})
|
|
396
|
+
} as Types.Edge)
|
|
392
397
|
}),
|
|
393
398
|
}
|
|
394
399
|
}
|
|
@@ -401,11 +406,19 @@ export function updateActiveWalkthrough({ context }: ActionArg): Partial<Diagram
|
|
|
401
406
|
const active = stepId === edge.id || (!!parallelPrefix && edge.id.startsWith(parallelPrefix))
|
|
402
407
|
return Base.setData(edge, {
|
|
403
408
|
active,
|
|
404
|
-
dimmed:
|
|
409
|
+
dimmed: stepId !== edge.id,
|
|
405
410
|
})
|
|
406
411
|
}),
|
|
407
412
|
xynodes: context.xynodes.map(node => {
|
|
408
413
|
const dimmed = step.source !== node.id && step.target !== node.id
|
|
414
|
+
if (node.type === 'seq-parallel') {
|
|
415
|
+
return Base.setData(node, {
|
|
416
|
+
color: parallelPrefix === node.data.parallelPrefix
|
|
417
|
+
? SeqParallelAreaColor.active
|
|
418
|
+
: SeqParallelAreaColor.default,
|
|
419
|
+
dimmed,
|
|
420
|
+
})
|
|
421
|
+
}
|
|
409
422
|
return Base.setDimmed(node, dimmed)
|
|
410
423
|
}),
|
|
411
424
|
}
|