@likec4/diagram 1.20.2 → 1.21.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/README.md +2 -2
- package/dist/base/BaseXYFlow.js +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- package/dist/base/primitives/element/ElementNodeContainer.js +15 -0
- 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 +4 -2
- 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/useDiagram.d.ts +1 -2
- package/dist/hooks/useXYFlow.js +1 -1
- package/dist/likec4diagram/DiagramUI.d.ts +1 -2
- package/dist/likec4diagram/DiagramUI.js +3 -3
- 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 +4 -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 +1 -1
- package/dist/likec4diagram/ui/walkthrough/DynamicViewWalkthrough.js +2 -2
- package/dist/likec4diagram/useLayoutConstraints.d.ts +2 -1
- package/dist/likec4diagram/useLayoutConstraints.js +14 -15
- package/dist/likec4diagram/useViewToNodesEdges.js +1 -1
- package/dist/overlays/Overlays.js +42 -21
- 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 +1 -1
- package/dist/overlays/element-details/TabPanelRelationships.js +16 -32
- 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/ElementActions.js +12 -2
- 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/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.tsx +21 -1
- package/src/base/primitives/element/ElementShape.css.ts +5 -0
- package/src/base/primitives/element/ElementTitle.css.ts +17 -24
- package/src/base/primitives/element/ElementTitle.tsx +4 -2
- package/src/base/primitives/element/styles.css.ts +74 -0
- package/src/hooks/useDiagram.ts +1 -1
- package/src/likec4diagram/DiagramUI.tsx +2 -2
- package/src/likec4diagram/XYFlow.tsx +2 -2
- package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +3 -2
- package/src/likec4diagram/types.ts +2 -2
- package/src/likec4diagram/useLayoutConstraints.ts +23 -19
- package/src/likec4diagram/useViewToNodesEdges.ts +1 -1
- package/src/overlays/Overlays.tsx +61 -281
- package/src/overlays/element-details/ElementDetailsCard.tsx +213 -257
- package/src/overlays/element-details/TabPanelRelationships.tsx +15 -77
- 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/custom/ElementActions.tsx +12 -2
- package/src/overlays/relationships-browser/useViewToNodesEdges.ts +2 -1
|
@@ -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
|
|
@@ -115,7 +113,6 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
115
113
|
const likec4model = useLikeC4Model(true)
|
|
116
114
|
const viewModel = likec4model.view(viewId)
|
|
117
115
|
// const currentView = diagram.currentView()
|
|
118
|
-
|
|
119
116
|
// const diagramNode = currentView.nodes.find(n => n.id === fqn)
|
|
120
117
|
// invariant(diagramNode, `DiagramNode with fqn ${fqn} not found`)
|
|
121
118
|
const nodeModel = fromNode ? viewModel.findNode(fromNode) : viewModel.findNodeWithElement(fqn)
|
|
@@ -124,15 +121,12 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
124
121
|
|
|
125
122
|
// const incoming = elementModel.incoming().map(r => r.id).toArray()
|
|
126
123
|
// const outgoing = elementModel.outgoing().map(r => r.id).toArray()
|
|
127
|
-
|
|
128
124
|
// const incomingInView = unique(nodeModel.incoming().flatMap(e => e.$edge.relations).toArray())
|
|
129
125
|
// const outgoingInView = unique(nodeModel.outgoing().flatMap(e => e.$edge.relations).toArray())
|
|
130
|
-
|
|
131
126
|
// const notIncludedRelations = [
|
|
132
127
|
// ...incoming,
|
|
133
128
|
// ...outgoing
|
|
134
129
|
// ].filter(r => !incomingInView.includes(r) && !outgoingInView.includes(r)).length
|
|
135
|
-
|
|
136
130
|
const [viewsOf, otherViews] = pipe(
|
|
137
131
|
[...elementModel.views()],
|
|
138
132
|
map(v => v.$view),
|
|
@@ -202,15 +196,13 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
202
196
|
}, [])
|
|
203
197
|
|
|
204
198
|
const ref = useRef<HTMLDialogElement>(null)
|
|
205
|
-
useLayoutEffect(() => {
|
|
206
|
-
ref.current?.showModal()
|
|
207
|
-
}, [])
|
|
208
199
|
|
|
209
|
-
const
|
|
200
|
+
const onCloseRef = useSyncedRef(onClose)
|
|
210
201
|
const close = useDebouncedCallback(
|
|
211
202
|
() => {
|
|
212
|
-
|
|
203
|
+
onCloseRef.current()
|
|
213
204
|
},
|
|
205
|
+
[],
|
|
214
206
|
50,
|
|
215
207
|
)
|
|
216
208
|
|
|
@@ -229,7 +221,6 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
229
221
|
<m.dialog
|
|
230
222
|
ref={ref}
|
|
231
223
|
className={css.dialog}
|
|
232
|
-
layoutRoot
|
|
233
224
|
initial={{
|
|
234
225
|
'--backdrop-blur': '0px',
|
|
235
226
|
'--backdrop-opacity': '10%',
|
|
@@ -245,6 +236,9 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
245
236
|
duration: 0.1,
|
|
246
237
|
},
|
|
247
238
|
}}
|
|
239
|
+
onAnimationStart={() => {
|
|
240
|
+
ref.current?.showModal()
|
|
241
|
+
}}
|
|
248
242
|
onClick={e => {
|
|
249
243
|
if ((e.target as any)?.nodeName?.toUpperCase() === 'DIALOG') {
|
|
250
244
|
e.stopPropagation()
|
|
@@ -267,7 +261,6 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
267
261
|
shadow="md"
|
|
268
262
|
component={m.div}
|
|
269
263
|
className={css.card}
|
|
270
|
-
layoutId={fqn}
|
|
271
264
|
initial={{
|
|
272
265
|
top,
|
|
273
266
|
left,
|
|
@@ -296,248 +289,211 @@ export const ElementDetailsCard = memo(({ fqn }: ElementDetailsCardProps) => {
|
|
|
296
289
|
height: height as any,
|
|
297
290
|
}}
|
|
298
291
|
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">
|
|
292
|
+
<Box
|
|
293
|
+
className={css.cardHeader}
|
|
294
|
+
onPointerDown={e => controls.start(e)}>
|
|
295
|
+
<Group align="start" justify="space-between" gap={'sm'} mb={'sm'} wrap="nowrap">
|
|
296
|
+
<Group align="start" gap={'sm'} style={{ cursor: 'default' }} wrap="nowrap">
|
|
297
|
+
{elementIcon}
|
|
331
298
|
<Box>
|
|
332
|
-
<
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
299
|
+
<Text
|
|
300
|
+
component={m.div}
|
|
301
|
+
layout="position"
|
|
302
|
+
layoutId={`${viewId}:element:title:${fqn}`}
|
|
303
|
+
className={css.title}>
|
|
304
|
+
{elementModel.title}
|
|
305
|
+
</Text>
|
|
306
|
+
{notation && (
|
|
307
|
+
<Text component="div" c={'dimmed'} fz={'sm'} fw={500} lh={1.3} lineClamp={1}>
|
|
308
|
+
{notation}
|
|
309
|
+
</Text>
|
|
310
|
+
)}
|
|
343
311
|
</Box>
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
312
|
+
</Group>
|
|
313
|
+
<CloseButton
|
|
314
|
+
size={'lg'}
|
|
315
|
+
onClick={e => {
|
|
316
|
+
e.stopPropagation()
|
|
317
|
+
close()
|
|
318
|
+
}} />
|
|
319
|
+
</Group>
|
|
320
|
+
<Group align="baseline" gap={'sm'} wrap="nowrap">
|
|
321
|
+
<Box>
|
|
322
|
+
<SmallLabel>kind</SmallLabel>
|
|
323
|
+
<Badge radius={'sm'} size="sm" fw={600} color="gray">{elementModel.kind}</Badge>
|
|
324
|
+
</Box>
|
|
325
|
+
<Box flex={1}>
|
|
326
|
+
<SmallLabel>tags</SmallLabel>
|
|
327
|
+
<Flex gap={4} flex={1} mt={6}>
|
|
328
|
+
{elementModel.tags.map((tag) => (
|
|
329
|
+
<Badge key={tag} radius={'sm'} size="sm" fw={600} variant="gradient">#{tag}</Badge>
|
|
330
|
+
))}
|
|
331
|
+
{elementModel.tags.length === 0 && <Badge radius={'sm'} size="sm" fw={600} color="gray">—</Badge>}
|
|
332
|
+
</Flex>
|
|
333
|
+
</Box>
|
|
334
|
+
<ActionIconGroup
|
|
335
|
+
style={{
|
|
336
|
+
alignSelf: 'flex-end',
|
|
337
|
+
}}>
|
|
338
|
+
{defaultLink && (
|
|
339
|
+
<ActionIcon
|
|
340
|
+
component="a"
|
|
341
|
+
href={defaultLink.url}
|
|
342
|
+
target="_blank"
|
|
343
|
+
size="lg"
|
|
344
|
+
variant="default"
|
|
345
|
+
radius="sm"
|
|
346
|
+
>
|
|
347
|
+
<IconExternalLink stroke={1.6} style={{ width: '65%' }} />
|
|
348
|
+
</ActionIcon>
|
|
349
|
+
)}
|
|
350
|
+
<IfEnabled feature="Vscode">
|
|
351
|
+
<Tooltip label="Open source">
|
|
349
352
|
<ActionIcon
|
|
350
|
-
component="a"
|
|
351
|
-
href={defaultLink.url}
|
|
352
|
-
target="_blank"
|
|
353
353
|
size="lg"
|
|
354
354
|
variant="default"
|
|
355
355
|
radius="sm"
|
|
356
|
-
|
|
357
|
-
|
|
356
|
+
onClick={e => {
|
|
357
|
+
e.stopPropagation()
|
|
358
|
+
diagram.openSource({
|
|
359
|
+
element: elementModel.id,
|
|
360
|
+
})
|
|
361
|
+
}}>
|
|
362
|
+
<IconFileSymlink stroke={1.8} style={{ width: '62%' }} />
|
|
358
363
|
</ActionIcon>
|
|
364
|
+
</Tooltip>
|
|
365
|
+
</IfEnabled>
|
|
366
|
+
{defaultView && (
|
|
367
|
+
<Tooltip label="Open default view">
|
|
368
|
+
<ActionIcon
|
|
369
|
+
size="lg"
|
|
370
|
+
variant="default"
|
|
371
|
+
radius="sm"
|
|
372
|
+
onClick={e => {
|
|
373
|
+
e.stopPropagation()
|
|
374
|
+
diagram.navigateTo(defaultView.id, fromNode ?? undefined)
|
|
375
|
+
}}>
|
|
376
|
+
<IconZoomScan style={{ width: '70%' }} />
|
|
377
|
+
</ActionIcon>
|
|
378
|
+
</Tooltip>
|
|
379
|
+
)}
|
|
380
|
+
</ActionIconGroup>
|
|
381
|
+
</Group>
|
|
382
|
+
</Box>
|
|
383
|
+
|
|
384
|
+
<Tabs
|
|
385
|
+
value={activeTab}
|
|
386
|
+
onChange={v => setActiveTab(v as any)}
|
|
387
|
+
variant="none"
|
|
388
|
+
classNames={{
|
|
389
|
+
root: css.tabsRoot,
|
|
390
|
+
list: css.tabsList,
|
|
391
|
+
tab: css.tabsTab,
|
|
392
|
+
panel: css.tabsPanel,
|
|
393
|
+
}}>
|
|
394
|
+
<TabsList>
|
|
395
|
+
{TABS.map(tab => (
|
|
396
|
+
<TabsTab key={tab} value={tab}>
|
|
397
|
+
{tab}
|
|
398
|
+
</TabsTab>
|
|
399
|
+
))}
|
|
400
|
+
</TabsList>
|
|
401
|
+
|
|
402
|
+
<TabsPanel value="Properties">
|
|
403
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
404
|
+
<Box className={css.propertiesGrid} pt={'xs'}>
|
|
405
|
+
<ElementProperty title="description" emptyValue="no description">
|
|
406
|
+
{elementModel.description}
|
|
407
|
+
</ElementProperty>
|
|
408
|
+
{elementModel.technology && (
|
|
409
|
+
<ElementProperty title="technology">
|
|
410
|
+
{elementModel.technology}
|
|
411
|
+
</ElementProperty>
|
|
359
412
|
)}
|
|
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>
|
|
413
|
+
{elementModel.links.length > 0 && (
|
|
414
|
+
<>
|
|
415
|
+
<PropertyLabel>links</PropertyLabel>
|
|
416
|
+
<Stack gap={'xs'} align="flex-start">
|
|
417
|
+
{elementModel.links.map((link, i) => <Link key={i} value={link} />)}
|
|
418
|
+
</Stack>
|
|
419
|
+
</>
|
|
389
420
|
)}
|
|
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' && (
|
|
421
|
+
{elementModel.$element.metadata && <ElementMetata value={elementModel.$element.metadata} />}
|
|
422
|
+
</Box>
|
|
423
|
+
</ScrollArea>
|
|
424
|
+
</TabsPanel>
|
|
425
|
+
|
|
426
|
+
<TabsPanel value="Relationships">
|
|
427
|
+
<DiagramFeatures
|
|
428
|
+
overrides={{
|
|
429
|
+
enableRelationshipBrowser: false,
|
|
430
|
+
enableNavigateTo: false,
|
|
431
|
+
}}>
|
|
432
|
+
{!!nodeModel && activeTab === 'Relationships' && (
|
|
438
433
|
<TabPanelRelationships
|
|
439
434
|
element={elementModel}
|
|
440
435
|
node={nodeModel}
|
|
441
436
|
currentView={diagram.currentView()} />
|
|
442
437
|
)}
|
|
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>
|
|
438
|
+
</DiagramFeatures>
|
|
439
|
+
</TabsPanel>
|
|
440
|
+
|
|
441
|
+
<TabsPanel value="Views">
|
|
442
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
443
|
+
<Stack gap={'lg'}>
|
|
444
|
+
{viewsOf.length > 0 && (
|
|
445
|
+
<Box>
|
|
446
|
+
<Divider label="views of the element (scoped)" />
|
|
447
|
+
<Stack gap={'sm'}>
|
|
448
|
+
{viewsOf.map((view) => (
|
|
449
|
+
<ViewButton
|
|
450
|
+
key={view.id}
|
|
451
|
+
view={view}
|
|
452
|
+
onNavigateTo={to => diagram.navigateTo(to, fromNode ?? undefined)} />
|
|
453
|
+
))}
|
|
454
|
+
</Stack>
|
|
455
|
+
</Box>
|
|
456
|
+
)}
|
|
457
|
+
{otherViews.length > 0 && (
|
|
458
|
+
<Box>
|
|
459
|
+
<Divider label="views including this element" />
|
|
460
|
+
<Stack gap={'sm'}>
|
|
461
|
+
{otherViews.map((view) => (
|
|
462
|
+
<ViewButton
|
|
463
|
+
key={view.id}
|
|
464
|
+
view={view}
|
|
465
|
+
onNavigateTo={to => diagram.navigateTo(to, fromNode ?? undefined)} />
|
|
466
|
+
))}
|
|
467
|
+
</Stack>
|
|
468
|
+
</Box>
|
|
469
|
+
)}
|
|
470
|
+
</Stack>
|
|
471
|
+
</ScrollArea>
|
|
472
|
+
</TabsPanel>
|
|
473
|
+
|
|
474
|
+
<TabsPanel value="Structure">
|
|
475
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
476
|
+
<TabPanelStructure element={elementModel} />
|
|
477
|
+
</ScrollArea>
|
|
478
|
+
</TabsPanel>
|
|
479
|
+
|
|
480
|
+
<TabsPanel value="Deployments">
|
|
481
|
+
<ScrollArea scrollbars="y" type="auto">
|
|
482
|
+
<TabPanelDeployments elementFqn={elementModel.id} />
|
|
483
|
+
</ScrollArea>
|
|
484
|
+
</TabsPanel>
|
|
485
|
+
</Tabs>
|
|
486
|
+
<m.div
|
|
487
|
+
className={css.resizeHandle}
|
|
488
|
+
drag
|
|
489
|
+
dragElastic={0}
|
|
490
|
+
dragMomentum={false}
|
|
491
|
+
onDrag={handleDrag}
|
|
492
|
+
dragConstraints={{ top: 0, left: 0, right: 0, bottom: 0 }} />
|
|
501
493
|
</Card>
|
|
502
494
|
</RemoveScroll>
|
|
503
495
|
</m.dialog>
|
|
504
496
|
)
|
|
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
497
|
}
|
|
542
498
|
|
|
543
499
|
const ViewButton = ({
|