@likec4/diagram 1.20.3 → 1.21.1
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/README.md +2 -2
- package/dist/base/BaseXYFlow.js +1 -2
- package/dist/base/example/_types.d.ts +3 -3
- package/dist/base/example/custom.d.ts +3 -2
- package/dist/base/primitives/compound/CompoundActionButton.js +1 -1
- package/dist/base/primitives/compound/CompoundDetailsButton.js +1 -1
- package/dist/base/primitives/compound/CompoundNodeContainer.js +2 -2
- package/dist/base/primitives/compound/CompoundTitle.css.d.ts +1 -0
- package/dist/base/primitives/compound/CompoundTitle.css.js +2 -0
- package/dist/base/primitives/compound/CompoundTitle.d.ts +2 -2
- package/dist/base/primitives/compound/CompoundTitle.js +17 -6
- package/dist/base/primitives/edge/EdgeLabel.js +2 -2
- package/dist/base/primitives/element/ElementActionButtons.js +1 -1
- package/dist/base/primitives/element/ElementDetailsButton.js +1 -1
- package/dist/base/primitives/element/ElementNodeContainer.d.ts +7 -2
- package/dist/base/primitives/element/ElementNodeContainer.js +34 -1
- package/dist/base/primitives/element/ElementShape.js +1 -1
- package/dist/base/primitives/element/ElementTitle.css.d.ts +0 -1
- package/dist/base/primitives/element/ElementTitle.css.js +8 -8
- package/dist/base/primitives/element/ElementTitle.d.ts +1 -1
- package/dist/base/primitives/element/ElementTitle.js +11 -5
- package/dist/base/primitives/element/styles.css.d.ts +3 -0
- package/dist/base/primitives/element/styles.css.js +6 -0
- package/dist/context/DiagramEventHandlers.js +1 -1
- package/dist/context/DiagramFeatures.js +1 -1
- package/dist/context/RootContainer.js +1 -1
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/useDiagram.d.ts +1 -2
- package/dist/hooks/useXYFlow.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/likec4diagram/DiagramUI.d.ts +1 -2
- package/dist/likec4diagram/DiagramUI.js +3 -4
- package/dist/likec4diagram/XYFlow.js +1 -1
- package/dist/likec4diagram/custom/edges/NotePopover.js +1 -1
- package/dist/likec4diagram/custom/edges/RelationshipEdge.js +1 -1
- package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +5 -4
- package/dist/likec4diagram/custom/nodes/nodeTypes.js +8 -8
- package/dist/likec4diagram/custom/nodes/toolbar/_shared.js +2 -2
- package/dist/likec4diagram/state/assign.js +1 -1
- package/dist/likec4diagram/state/machine.js +5 -5
- package/dist/likec4diagram/types.d.ts +2 -2
- package/dist/likec4diagram/ui/controls/Controls.js +1 -1
- package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +5 -4
- package/dist/likec4diagram/ui/index.d.ts +2 -0
- package/dist/likec4diagram/ui/walkthrough/DynamicViewWalkthrough.js +2 -2
- package/dist/likec4diagram/useViewToNodesEdges.js +1 -1
- package/dist/overlays/Overlays.js +43 -22
- package/dist/overlays/element-details/ElementDetailsCard.d.ts +7 -3
- package/dist/overlays/element-details/ElementDetailsCard.js +38 -39
- package/dist/overlays/element-details/TabPanelDeployments.js +5 -3
- package/dist/overlays/element-details/TabPanelRelationships.js +14 -30
- package/dist/overlays/overlay/Overlay.css.js +2 -1
- package/dist/overlays/overlay/Overlay.js +2 -2
- package/dist/overlays/relationship-details/SelectEdge.js +1 -1
- package/dist/overlays/relationship-details/_types.d.ts +3 -3
- package/dist/overlays/relationship-details/actor.js +1 -1
- package/dist/overlays/relationship-details/custom/nodeTypes.d.ts +3 -3
- package/dist/overlays/relationship-details/custom/nodeTypes.js +2 -2
- package/dist/overlays/relationship-details/useLayoutedDetails.js +1 -4
- package/dist/overlays/relationships-browser/-useRelationshipsView.js +0 -3
- package/dist/overlays/relationships-browser/RelationshipsBrowser.js +3 -3
- package/dist/overlays/relationships-browser/_types.d.ts +3 -3
- package/dist/overlays/relationships-browser/actor.js +16 -16
- package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +3 -2
- package/dist/overlays/relationships-browser/custom/nodeTypes.js +3 -3
- package/dist/overlays/relationships-browser/useViewToNodesEdges.js +3 -2
- package/dist/style.css +1 -1
- package/package.json +14 -14
- package/src/base/BaseXYFlow.tsx +0 -1
- package/src/base/example/_types.ts +3 -2
- package/src/base/example/useViewToNodesEdges.ts +2 -1
- package/src/base/primitives/compound/CompoundTitle.css.ts +27 -1
- package/src/base/primitives/compound/CompoundTitle.tsx +12 -2
- package/src/base/primitives/element/ElementNodeContainer.css.ts +4 -7
- package/src/base/primitives/element/ElementNodeContainer.tsx +41 -1
- package/src/base/primitives/element/ElementShape.css.ts +5 -0
- package/src/base/primitives/element/ElementTitle.css.ts +25 -29
- package/src/base/primitives/element/ElementTitle.tsx +10 -4
- package/src/base/primitives/element/styles.css.ts +52 -0
- package/src/globals.css.ts +2 -0
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useDiagram.ts +1 -1
- package/src/index.ts +15 -1
- package/src/likec4diagram/DiagramUI.tsx +3 -6
- package/src/likec4diagram/XYFlow.tsx +2 -2
- package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +0 -1
- package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.css.ts +1 -0
- package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +4 -2
- package/src/likec4diagram/types.ts +2 -2
- package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +110 -107
- package/src/likec4diagram/ui/index.ts +2 -0
- package/src/likec4diagram/ui/notation/NotationPanel.tsx +2 -3
- package/src/likec4diagram/useViewToNodesEdges.ts +1 -1
- package/src/overlays/Overlays.tsx +62 -282
- package/src/overlays/element-details/ElementDetailsCard.tsx +214 -261
- package/src/overlays/element-details/TabPanelDeployments.tsx +4 -4
- package/src/overlays/element-details/TabPanelRelationships.tsx +13 -75
- package/src/overlays/overlay/Overlay.tsx +1 -1
- package/src/overlays/relationship-details/_types.ts +3 -3
- package/src/overlays/relationship-details/useLayoutedDetails.ts +1 -1
- package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +44 -55
- package/src/overlays/relationships-browser/_types.ts +12 -2
- package/src/overlays/relationships-browser/actor.ts +11 -10
- package/src/overlays/relationships-browser/useViewToNodesEdges.ts +2 -1
- package/dist/hooks/useCurrentViewId.js +0 -8
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
type Element,
|
|
4
4
|
type Fqn,
|
|
5
5
|
type LikeC4View,
|
|
6
|
-
|
|
6
|
+
type NodeId,
|
|
7
|
+
type ViewId,
|
|
7
8
|
ComputedView,
|
|
8
9
|
isDeploymentView,
|
|
9
10
|
isScopedElementView,
|
|
@@ -12,17 +13,13 @@ import {
|
|
|
12
13
|
type TextProps,
|
|
13
14
|
ActionIcon,
|
|
14
15
|
ActionIconGroup,
|
|
15
|
-
Anchor,
|
|
16
16
|
Badge,
|
|
17
17
|
Box,
|
|
18
18
|
Card,
|
|
19
19
|
CloseButton,
|
|
20
20
|
Code,
|
|
21
|
-
CopyButton,
|
|
22
21
|
Divider as MantineDivider,
|
|
23
22
|
Flex,
|
|
24
|
-
FocusTrap,
|
|
25
|
-
FocusTrapInitialFocus,
|
|
26
23
|
Group,
|
|
27
24
|
RemoveScroll,
|
|
28
25
|
ScrollArea,
|
|
@@ -36,18 +33,18 @@ import {
|
|
|
36
33
|
Tooltip as MantineTooltip,
|
|
37
34
|
UnstyledButton,
|
|
38
35
|
} from '@mantine/core'
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import
|
|
36
|
+
import { useSessionStorage, useViewportSize } from '@mantine/hooks'
|
|
37
|
+
import { useDebouncedCallback, useSyncedRef } from '@react-hookz/web'
|
|
38
|
+
import { IconExternalLink, IconFileSymlink, IconStack2, IconZoomScan } from '@tabler/icons-react'
|
|
39
|
+
import type { Rect } from '@xyflow/system'
|
|
42
40
|
import { type PanInfo, m, useDragControls, useMotionValue } from 'framer-motion'
|
|
43
|
-
import { type PropsWithChildren,
|
|
41
|
+
import { type PropsWithChildren, useCallback, useRef } from 'react'
|
|
44
42
|
import { clamp, isNullish, map, only, partition, pipe } from 'remeda'
|
|
45
43
|
import { Link } from '../../base'
|
|
46
|
-
import { IconRenderer, IfEnabled } from '../../context'
|
|
44
|
+
import { DiagramFeatures, IconRenderer, IfEnabled } from '../../context'
|
|
47
45
|
import { useUpdateEffect } from '../../hooks'
|
|
48
46
|
import { useDiagram } from '../../hooks/useDiagram'
|
|
49
|
-
import {
|
|
50
|
-
import type { ElementIconRenderer, OnNavigateTo } from '../../LikeC4Diagram.props'
|
|
47
|
+
import type { OnNavigateTo } from '../../LikeC4Diagram.props'
|
|
51
48
|
import { useLikeC4Model } from '../../likec4model'
|
|
52
49
|
import * as css from './ElementDetailsCard.css'
|
|
53
50
|
import { TabPanelDeployments } from './TabPanelDeployments'
|
|
@@ -85,6 +82,10 @@ const PropertyLabel = Text.withProps({
|
|
|
85
82
|
})
|
|
86
83
|
|
|
87
84
|
type ElementDetailsCardProps = {
|
|
85
|
+
viewId: ViewId
|
|
86
|
+
fromNode: NodeId | null
|
|
87
|
+
rectFromNode: Rect | null
|
|
88
|
+
onClose: () => void
|
|
88
89
|
fqn: Fqn
|
|
89
90
|
}
|
|
90
91
|
|
|
@@ -93,16 +94,13 @@ const MIN_PADDING = 24
|
|
|
93
94
|
const TABS = ['Properties', 'Relationships', 'Views', 'Structure', 'Deployments'] as const
|
|
94
95
|
type TabName = typeof TABS[number]
|
|
95
96
|
|
|
96
|
-
export
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
fromNode: s.activeElementDetails?.fromNode ?? null,
|
|
104
|
-
rectFromNode: s.activeElementDetails?.nodeRectScreen ?? null,
|
|
105
|
-
}))
|
|
97
|
+
export function ElementDetailsCard({
|
|
98
|
+
viewId,
|
|
99
|
+
fromNode,
|
|
100
|
+
rectFromNode,
|
|
101
|
+
fqn,
|
|
102
|
+
onClose,
|
|
103
|
+
}: ElementDetailsCardProps) {
|
|
106
104
|
const windowSize = useViewportSize()
|
|
107
105
|
const windowWidth = windowSize.width || window.innerWidth || 1200,
|
|
108
106
|
windowHeight = windowSize.height || window.innerHeight || 800
|
|
@@ -114,25 +112,18 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
114
112
|
const diagram = useDiagram()
|
|
115
113
|
const likec4model = useLikeC4Model(true)
|
|
116
114
|
const viewModel = likec4model.view(viewId)
|
|
117
|
-
// const currentView = diagram.currentView()
|
|
118
|
-
|
|
119
|
-
// const diagramNode = currentView.nodes.find(n => n.id === fqn)
|
|
120
|
-
// invariant(diagramNode, `DiagramNode with fqn ${fqn} not found`)
|
|
121
115
|
const nodeModel = fromNode ? viewModel.findNode(fromNode) : viewModel.findNodeWithElement(fqn)
|
|
122
|
-
|
|
116
|
+
|
|
123
117
|
const elementModel = viewModel.$model.element(fqn)
|
|
124
118
|
|
|
125
119
|
// const incoming = elementModel.incoming().map(r => r.id).toArray()
|
|
126
120
|
// const outgoing = elementModel.outgoing().map(r => r.id).toArray()
|
|
127
|
-
|
|
128
121
|
// const incomingInView = unique(nodeModel.incoming().flatMap(e => e.$edge.relations).toArray())
|
|
129
122
|
// const outgoingInView = unique(nodeModel.outgoing().flatMap(e => e.$edge.relations).toArray())
|
|
130
|
-
|
|
131
123
|
// const notIncludedRelations = [
|
|
132
124
|
// ...incoming,
|
|
133
125
|
// ...outgoing
|
|
134
126
|
// ].filter(r => !incomingInView.includes(r) && !outgoingInView.includes(r)).length
|
|
135
|
-
|
|
136
127
|
const [viewsOf, otherViews] = pipe(
|
|
137
128
|
[...elementModel.views()],
|
|
138
129
|
map(v => v.$view),
|
|
@@ -202,15 +193,13 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
202
193
|
}, [])
|
|
203
194
|
|
|
204
195
|
const ref = useRef<HTMLDialogElement>(null)
|
|
205
|
-
useLayoutEffect(() => {
|
|
206
|
-
ref.current?.showModal()
|
|
207
|
-
}, [])
|
|
208
196
|
|
|
209
|
-
const
|
|
197
|
+
const onCloseRef = useSyncedRef(onClose)
|
|
210
198
|
const close = useDebouncedCallback(
|
|
211
199
|
() => {
|
|
212
|
-
|
|
200
|
+
onCloseRef.current()
|
|
213
201
|
},
|
|
202
|
+
[],
|
|
214
203
|
50,
|
|
215
204
|
)
|
|
216
205
|
|
|
@@ -229,7 +218,6 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
229
218
|
<m.dialog
|
|
230
219
|
ref={ref}
|
|
231
220
|
className={css.dialog}
|
|
232
|
-
layoutRoot
|
|
233
221
|
initial={{
|
|
234
222
|
'--backdrop-blur': '0px',
|
|
235
223
|
'--backdrop-opacity': '10%',
|
|
@@ -245,6 +233,9 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
245
233
|
duration: 0.1,
|
|
246
234
|
},
|
|
247
235
|
}}
|
|
236
|
+
onAnimationStart={() => {
|
|
237
|
+
ref.current?.showModal()
|
|
238
|
+
}}
|
|
248
239
|
onClick={e => {
|
|
249
240
|
if ((e.target as any)?.nodeName?.toUpperCase() === 'DIALOG') {
|
|
250
241
|
e.stopPropagation()
|
|
@@ -267,7 +258,6 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
267
258
|
shadow="md"
|
|
268
259
|
component={m.div}
|
|
269
260
|
className={css.card}
|
|
270
|
-
layoutId={fqn}
|
|
271
261
|
initial={{
|
|
272
262
|
top,
|
|
273
263
|
left,
|
|
@@ -296,248 +286,211 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
296
286
|
height: height as any,
|
|
297
287
|
}}
|
|
298
288
|
data-likec4-color={nodeModel?.color ?? elementModel.color}>
|
|
299
|
-
<
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
<Group align="start" gap={'sm'} style={{ cursor: 'default' }} wrap="nowrap">
|
|
306
|
-
{elementIcon}
|
|
307
|
-
<Box>
|
|
308
|
-
<Text
|
|
309
|
-
component={m.div}
|
|
310
|
-
layout="position"
|
|
311
|
-
layoutId={`${viewId}:element:title:${fqn}`}
|
|
312
|
-
className={css.title}>
|
|
313
|
-
{elementModel.title}
|
|
314
|
-
</Text>
|
|
315
|
-
{notation && (
|
|
316
|
-
<Text component="div" c={'dimmed'} fz={'sm'} fw={500} lh={1.3} lineClamp={1}>
|
|
317
|
-
{notation}
|
|
318
|
-
</Text>
|
|
319
|
-
)}
|
|
320
|
-
</Box>
|
|
321
|
-
</Group>
|
|
322
|
-
<CloseButton
|
|
323
|
-
size={'lg'}
|
|
324
|
-
onClick={e => {
|
|
325
|
-
e.stopPropagation()
|
|
326
|
-
close()
|
|
327
|
-
}}
|
|
328
|
-
/>
|
|
329
|
-
</Group>
|
|
330
|
-
<Group align="baseline" gap={'sm'} wrap="nowrap">
|
|
289
|
+
<Box
|
|
290
|
+
className={css.cardHeader}
|
|
291
|
+
onPointerDown={e => controls.start(e)}>
|
|
292
|
+
<Group align="start" justify="space-between" gap={'sm'} mb={'sm'} wrap="nowrap">
|
|
293
|
+
<Group align="start" gap={'sm'} style={{ cursor: 'default' }} wrap="nowrap">
|
|
294
|
+
{elementIcon}
|
|
331
295
|
<Box>
|
|
332
|
-
<
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
296
|
+
<Text
|
|
297
|
+
component={m.div}
|
|
298
|
+
layout="position"
|
|
299
|
+
layoutId={`${viewId}:element:title:${fqn}`}
|
|
300
|
+
className={css.title}>
|
|
301
|
+
{elementModel.title}
|
|
302
|
+
</Text>
|
|
303
|
+
{notation && (
|
|
304
|
+
<Text component="div" c={'dimmed'} fz={'sm'} fw={500} lh={1.3} lineClamp={1}>
|
|
305
|
+
{notation}
|
|
306
|
+
</Text>
|
|
307
|
+
)}
|
|
343
308
|
</Box>
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
309
|
+
</Group>
|
|
310
|
+
<CloseButton
|
|
311
|
+
size={'lg'}
|
|
312
|
+
onClick={e => {
|
|
313
|
+
e.stopPropagation()
|
|
314
|
+
close()
|
|
315
|
+
}} />
|
|
316
|
+
</Group>
|
|
317
|
+
<Group align="baseline" gap={'sm'} wrap="nowrap">
|
|
318
|
+
<Box>
|
|
319
|
+
<SmallLabel>kind</SmallLabel>
|
|
320
|
+
<Badge radius={'sm'} size="sm" fw={600} color="gray">{elementModel.kind}</Badge>
|
|
321
|
+
</Box>
|
|
322
|
+
<Box flex={1}>
|
|
323
|
+
<SmallLabel>tags</SmallLabel>
|
|
324
|
+
<Flex gap={4} flex={1} mt={6}>
|
|
325
|
+
{elementModel.tags.map((tag) => (
|
|
326
|
+
<Badge key={tag} radius={'sm'} size="sm" fw={600} variant="gradient">#{tag}</Badge>
|
|
327
|
+
))}
|
|
328
|
+
{elementModel.tags.length === 0 && <Badge radius={'sm'} size="sm" fw={600} color="gray">—</Badge>}
|
|
329
|
+
</Flex>
|
|
330
|
+
</Box>
|
|
331
|
+
<ActionIconGroup
|
|
332
|
+
style={{
|
|
333
|
+
alignSelf: 'flex-end',
|
|
334
|
+
}}>
|
|
335
|
+
{defaultLink && (
|
|
336
|
+
<ActionIcon
|
|
337
|
+
component="a"
|
|
338
|
+
href={defaultLink.url}
|
|
339
|
+
target="_blank"
|
|
340
|
+
size="lg"
|
|
341
|
+
variant="default"
|
|
342
|
+
radius="sm"
|
|
343
|
+
>
|
|
344
|
+
<IconExternalLink stroke={1.6} style={{ width: '65%' }} />
|
|
345
|
+
</ActionIcon>
|
|
346
|
+
)}
|
|
347
|
+
<IfEnabled feature="Vscode">
|
|
348
|
+
<Tooltip label="Open source">
|
|
349
|
+
<ActionIcon
|
|
350
|
+
size="lg"
|
|
351
|
+
variant="default"
|
|
352
|
+
radius="sm"
|
|
353
|
+
onClick={e => {
|
|
354
|
+
e.stopPropagation()
|
|
355
|
+
diagram.openSource({
|
|
356
|
+
element: elementModel.id,
|
|
357
|
+
})
|
|
358
|
+
}}>
|
|
359
|
+
<IconFileSymlink stroke={1.8} style={{ width: '62%' }} />
|
|
360
|
+
</ActionIcon>
|
|
361
|
+
</Tooltip>
|
|
362
|
+
</IfEnabled>
|
|
363
|
+
{defaultView && (
|
|
364
|
+
<Tooltip label="Open default view">
|
|
349
365
|
<ActionIcon
|
|
350
|
-
component="a"
|
|
351
|
-
href={defaultLink.url}
|
|
352
|
-
target="_blank"
|
|
353
366
|
size="lg"
|
|
354
367
|
variant="default"
|
|
355
368
|
radius="sm"
|
|
356
|
-
|
|
357
|
-
|
|
369
|
+
onClick={e => {
|
|
370
|
+
e.stopPropagation()
|
|
371
|
+
diagram.navigateTo(defaultView.id, fromNode ?? undefined)
|
|
372
|
+
}}>
|
|
373
|
+
<IconZoomScan style={{ width: '70%' }} />
|
|
358
374
|
</ActionIcon>
|
|
375
|
+
</Tooltip>
|
|
376
|
+
)}
|
|
377
|
+
</ActionIconGroup>
|
|
378
|
+
</Group>
|
|
379
|
+
</Box>
|
|
380
|
+
|
|
381
|
+
<Tabs
|
|
382
|
+
value={activeTab}
|
|
383
|
+
onChange={v => setActiveTab(v as any)}
|
|
384
|
+
variant="none"
|
|
385
|
+
classNames={{
|
|
386
|
+
root: css.tabsRoot,
|
|
387
|
+
list: css.tabsList,
|
|
388
|
+
tab: css.tabsTab,
|
|
389
|
+
panel: css.tabsPanel,
|
|
390
|
+
}}>
|
|
391
|
+
<TabsList>
|
|
392
|
+
{TABS.map(tab => (
|
|
393
|
+
<TabsTab key={tab} value={tab}>
|
|
394
|
+
{tab}
|
|
395
|
+
</TabsTab>
|
|
396
|
+
))}
|
|
397
|
+
</TabsList>
|
|
398
|
+
|
|
399
|
+
<TabsPanel value="Properties">
|
|
400
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
401
|
+
<Box className={css.propertiesGrid} pt={'xs'}>
|
|
402
|
+
<ElementProperty title="description" emptyValue="no description">
|
|
403
|
+
{elementModel.description}
|
|
404
|
+
</ElementProperty>
|
|
405
|
+
{elementModel.technology && (
|
|
406
|
+
<ElementProperty title="technology">
|
|
407
|
+
{elementModel.technology}
|
|
408
|
+
</ElementProperty>
|
|
359
409
|
)}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
<
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
e.stopPropagation()
|
|
368
|
-
diagram.openSource({
|
|
369
|
-
element: elementModel.id,
|
|
370
|
-
})
|
|
371
|
-
}}>
|
|
372
|
-
<IconFileSymlink stroke={1.8} style={{ width: '62%' }} />
|
|
373
|
-
</ActionIcon>
|
|
374
|
-
</Tooltip>
|
|
375
|
-
</IfEnabled>
|
|
376
|
-
{defaultView && (
|
|
377
|
-
<Tooltip label="Open default view">
|
|
378
|
-
<ActionIcon
|
|
379
|
-
size="lg"
|
|
380
|
-
variant="default"
|
|
381
|
-
radius="sm"
|
|
382
|
-
onClick={e => {
|
|
383
|
-
e.stopPropagation()
|
|
384
|
-
diagram.navigateTo(defaultView.id, fromNode ?? undefined)
|
|
385
|
-
}}>
|
|
386
|
-
<IconZoomScan style={{ width: '70%' }} />
|
|
387
|
-
</ActionIcon>
|
|
388
|
-
</Tooltip>
|
|
410
|
+
{elementModel.links.length > 0 && (
|
|
411
|
+
<>
|
|
412
|
+
<PropertyLabel>links</PropertyLabel>
|
|
413
|
+
<Stack gap={'xs'} align="flex-start">
|
|
414
|
+
{elementModel.links.map((link, i) => <Link key={i} value={link} />)}
|
|
415
|
+
</Stack>
|
|
416
|
+
</>
|
|
389
417
|
)}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
panel: css.tabsPanel,
|
|
403
|
-
}}>
|
|
404
|
-
<TabsList>
|
|
405
|
-
{TABS.map(tab => (
|
|
406
|
-
<TabsTab key={tab} value={tab}>
|
|
407
|
-
{tab}
|
|
408
|
-
</TabsTab>
|
|
409
|
-
))}
|
|
410
|
-
</TabsList>
|
|
411
|
-
|
|
412
|
-
<TabsPanel value="Properties">
|
|
413
|
-
<ScrollArea scrollbars="y" type="auto">
|
|
414
|
-
<Box className={css.propertiesGrid} pt={'xs'}>
|
|
415
|
-
<ElementProperty title="description" emptyValue="no description">
|
|
416
|
-
{elementModel.description}
|
|
417
|
-
</ElementProperty>
|
|
418
|
-
{elementModel.technology && (
|
|
419
|
-
<ElementProperty title="technology">
|
|
420
|
-
{elementModel.technology}
|
|
421
|
-
</ElementProperty>
|
|
422
|
-
)}
|
|
423
|
-
{elementModel.links.length > 0 && (
|
|
424
|
-
<>
|
|
425
|
-
<PropertyLabel>links</PropertyLabel>
|
|
426
|
-
<Stack gap={'xs'} align="flex-start">
|
|
427
|
-
{elementModel.links.map((link, i) => <Link key={i} value={link} />)}
|
|
428
|
-
</Stack>
|
|
429
|
-
</>
|
|
430
|
-
)}
|
|
431
|
-
{elementModel.$element.metadata && <ElementMetata value={elementModel.$element.metadata} />}
|
|
432
|
-
</Box>
|
|
433
|
-
</ScrollArea>
|
|
434
|
-
</TabsPanel>
|
|
435
|
-
|
|
436
|
-
<TabsPanel value="Relationships">
|
|
437
|
-
{nodeModel && activeTab === 'Relationships' && (
|
|
418
|
+
{elementModel.$element.metadata && <ElementMetata value={elementModel.$element.metadata} />}
|
|
419
|
+
</Box>
|
|
420
|
+
</ScrollArea>
|
|
421
|
+
</TabsPanel>
|
|
422
|
+
|
|
423
|
+
<TabsPanel value="Relationships">
|
|
424
|
+
<DiagramFeatures
|
|
425
|
+
overrides={{
|
|
426
|
+
enableRelationshipBrowser: false,
|
|
427
|
+
enableNavigateTo: false,
|
|
428
|
+
}}>
|
|
429
|
+
{!!nodeModel && activeTab === 'Relationships' && (
|
|
438
430
|
<TabPanelRelationships
|
|
439
431
|
element={elementModel}
|
|
440
432
|
node={nodeModel}
|
|
441
433
|
currentView={diagram.currentView()} />
|
|
442
434
|
)}
|
|
443
|
-
</
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
/>
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
<
|
|
481
|
-
<
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
<
|
|
487
|
-
<
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
dragConstraints={{ top: 0, left: 0, right: 0, bottom: 0 }}
|
|
499
|
-
/>
|
|
500
|
-
</FocusTrap>
|
|
435
|
+
</DiagramFeatures>
|
|
436
|
+
</TabsPanel>
|
|
437
|
+
|
|
438
|
+
<TabsPanel value="Views">
|
|
439
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
440
|
+
<Stack gap={'lg'}>
|
|
441
|
+
{viewsOf.length > 0 && (
|
|
442
|
+
<Box>
|
|
443
|
+
<Divider label="views of the element (scoped)" />
|
|
444
|
+
<Stack gap={'sm'}>
|
|
445
|
+
{viewsOf.map((view) => (
|
|
446
|
+
<ViewButton
|
|
447
|
+
key={view.id}
|
|
448
|
+
view={view}
|
|
449
|
+
onNavigateTo={to => diagram.navigateTo(to, fromNode ?? undefined)} />
|
|
450
|
+
))}
|
|
451
|
+
</Stack>
|
|
452
|
+
</Box>
|
|
453
|
+
)}
|
|
454
|
+
{otherViews.length > 0 && (
|
|
455
|
+
<Box>
|
|
456
|
+
<Divider label="views including this element" />
|
|
457
|
+
<Stack gap={'sm'}>
|
|
458
|
+
{otherViews.map((view) => (
|
|
459
|
+
<ViewButton
|
|
460
|
+
key={view.id}
|
|
461
|
+
view={view}
|
|
462
|
+
onNavigateTo={to => diagram.navigateTo(to, fromNode ?? undefined)} />
|
|
463
|
+
))}
|
|
464
|
+
</Stack>
|
|
465
|
+
</Box>
|
|
466
|
+
)}
|
|
467
|
+
</Stack>
|
|
468
|
+
</ScrollArea>
|
|
469
|
+
</TabsPanel>
|
|
470
|
+
|
|
471
|
+
<TabsPanel value="Structure">
|
|
472
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
473
|
+
<TabPanelStructure element={elementModel} />
|
|
474
|
+
</ScrollArea>
|
|
475
|
+
</TabsPanel>
|
|
476
|
+
|
|
477
|
+
<TabsPanel value="Deployments">
|
|
478
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
479
|
+
<TabPanelDeployments elementFqn={elementModel.id} />
|
|
480
|
+
</ScrollArea>
|
|
481
|
+
</TabsPanel>
|
|
482
|
+
</Tabs>
|
|
483
|
+
<m.div
|
|
484
|
+
className={css.resizeHandle}
|
|
485
|
+
drag
|
|
486
|
+
dragElastic={0}
|
|
487
|
+
dragMomentum={false}
|
|
488
|
+
onDrag={handleDrag}
|
|
489
|
+
dragConstraints={{ top: 0, left: 0, right: 0, bottom: 0 }} />
|
|
501
490
|
</Card>
|
|
502
491
|
</RemoveScroll>
|
|
503
492
|
</m.dialog>
|
|
504
493
|
)
|
|
505
|
-
})
|
|
506
|
-
ElementDetailsCard.displayName = 'ElementDetailsCard'
|
|
507
|
-
|
|
508
|
-
const ElementIcon = (
|
|
509
|
-
{ element, viewId, renderIcon: RenderIcon }: {
|
|
510
|
-
element: ComputedNode
|
|
511
|
-
viewId: string
|
|
512
|
-
renderIcon: ElementIconRenderer | null
|
|
513
|
-
},
|
|
514
|
-
) => {
|
|
515
|
-
if (!element.icon || element.icon === 'none') {
|
|
516
|
-
return null
|
|
517
|
-
}
|
|
518
|
-
let icon = null as React.ReactNode
|
|
519
|
-
if (element.icon.startsWith('http://') || element.icon.startsWith('https://')) {
|
|
520
|
-
icon = <img src={element.icon} alt={element.title} />
|
|
521
|
-
} else if (RenderIcon) {
|
|
522
|
-
icon = <RenderIcon node={element} />
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
if (!icon) {
|
|
526
|
-
return null
|
|
527
|
-
}
|
|
528
|
-
return (
|
|
529
|
-
<m.div
|
|
530
|
-
// layout="position"
|
|
531
|
-
layoutId={`${viewId}:element:icon:${element.id}`}
|
|
532
|
-
className={clsx(
|
|
533
|
-
css.elementIcon,
|
|
534
|
-
'likec4-element-icon',
|
|
535
|
-
)}
|
|
536
|
-
data-likec4-icon={element.icon}
|
|
537
|
-
>
|
|
538
|
-
{icon}
|
|
539
|
-
</m.div>
|
|
540
|
-
)
|
|
541
494
|
}
|
|
542
495
|
|
|
543
496
|
const ViewButton = ({
|
|
@@ -2,7 +2,7 @@ import type { Fqn, LikeC4Model } from '@likec4/core'
|
|
|
2
2
|
import { Alert, Box, Button, Group, Menu, rem, Text, ThemeIcon, Tree, useTree } from '@mantine/core'
|
|
3
3
|
import { IconInfoCircle, IconTarget, IconZoomScan } from '@tabler/icons-react'
|
|
4
4
|
import { type ReactNode, memo, useEffect, useMemo } from 'react'
|
|
5
|
-
import {
|
|
5
|
+
import { useDiagram } from '../../hooks/useDiagram'
|
|
6
6
|
import { useLikeC4Model } from '../../likec4model/useLikeC4Model'
|
|
7
7
|
import { stopPropagation } from '../../utils'
|
|
8
8
|
import * as css from './TabPanelDeployments.css'
|
|
@@ -36,8 +36,8 @@ const DeployedInstanceRenderer = (
|
|
|
36
36
|
instance: LikeC4Model.DeployedInstance
|
|
37
37
|
},
|
|
38
38
|
) => {
|
|
39
|
-
const
|
|
40
|
-
|
|
39
|
+
const diagram = useDiagram()
|
|
40
|
+
const currentViewId = diagram.currentView().id
|
|
41
41
|
const views = [...instance.views()]
|
|
42
42
|
return (
|
|
43
43
|
(
|
|
@@ -91,7 +91,7 @@ const DeployedInstanceRenderer = (
|
|
|
91
91
|
}}
|
|
92
92
|
onClick={e => {
|
|
93
93
|
e.stopPropagation()
|
|
94
|
-
|
|
94
|
+
diagram.navigateTo(view.id)
|
|
95
95
|
}}>
|
|
96
96
|
{view.title}
|
|
97
97
|
</Menu.Item>
|