@finos/legend-extension-dsl-data-space 10.0.11 → 10.0.13

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.
Files changed (126) hide show
  1. package/lib/__lib__/DSL_DataSpace_LegendApplicationCommand.d.ts +28 -0
  2. package/lib/__lib__/DSL_DataSpace_LegendApplicationCommand.d.ts.map +1 -0
  3. package/lib/__lib__/DSL_DataSpace_LegendApplicationCommand.js +70 -0
  4. package/lib/__lib__/DSL_DataSpace_LegendApplicationCommand.js.map +1 -0
  5. package/lib/__lib__/DSL_DataSpace_LegendApplicationNavigation.d.ts +20 -0
  6. package/lib/__lib__/DSL_DataSpace_LegendApplicationNavigation.d.ts.map +1 -0
  7. package/lib/__lib__/DSL_DataSpace_LegendApplicationNavigation.js +21 -0
  8. package/lib/__lib__/DSL_DataSpace_LegendApplicationNavigation.js.map +1 -0
  9. package/lib/components/DSL_DataSpace_LegendApplicationPlugin.d.ts +3 -1
  10. package/lib/components/DSL_DataSpace_LegendApplicationPlugin.d.ts.map +1 -1
  11. package/lib/components/DSL_DataSpace_LegendApplicationPlugin.js +13 -1
  12. package/lib/components/DSL_DataSpace_LegendApplicationPlugin.js.map +1 -1
  13. package/lib/components/DataSpaceDataAccess.d.ts.map +1 -1
  14. package/lib/components/DataSpaceDataAccess.js +5 -76
  15. package/lib/components/DataSpaceDataAccess.js.map +1 -1
  16. package/lib/components/DataSpaceDescription.d.ts.map +1 -1
  17. package/lib/components/DataSpaceDescription.js +2 -1
  18. package/lib/components/DataSpaceDescription.js.map +1 -1
  19. package/lib/components/DataSpaceDiagramViewer.d.ts.map +1 -1
  20. package/lib/components/DataSpaceDiagramViewer.js +110 -39
  21. package/lib/components/DataSpaceDiagramViewer.js.map +1 -1
  22. package/lib/components/DataSpaceExecutionContextViewer.d.ts.map +1 -1
  23. package/lib/components/DataSpaceExecutionContextViewer.js +3 -3
  24. package/lib/components/DataSpaceExecutionContextViewer.js.map +1 -1
  25. package/lib/components/DataSpaceInfoPanel.d.ts.map +1 -1
  26. package/lib/components/DataSpaceInfoPanel.js +6 -6
  27. package/lib/components/DataSpaceInfoPanel.js.map +1 -1
  28. package/lib/components/DataSpaceModelsDocumentation.d.ts.map +1 -1
  29. package/lib/components/DataSpaceModelsDocumentation.js +18 -8
  30. package/lib/components/DataSpaceModelsDocumentation.js.map +1 -1
  31. package/lib/components/DataSpacePlaceholder.d.ts +4 -0
  32. package/lib/components/DataSpacePlaceholder.d.ts.map +1 -1
  33. package/lib/components/DataSpacePlaceholder.js +6 -1
  34. package/lib/components/DataSpacePlaceholder.js.map +1 -1
  35. package/lib/components/DataSpaceQuickStart.d.ts.map +1 -1
  36. package/lib/components/DataSpaceQuickStart.js +24 -11
  37. package/lib/components/DataSpaceQuickStart.js.map +1 -1
  38. package/lib/components/DataSpaceSupportPanel.d.ts.map +1 -1
  39. package/lib/components/DataSpaceSupportPanel.js +17 -8
  40. package/lib/components/DataSpaceSupportPanel.js.map +1 -1
  41. package/lib/components/DataSpaceViewer.d.ts.map +1 -1
  42. package/lib/components/DataSpaceViewer.js +34 -13
  43. package/lib/components/DataSpaceViewer.js.map +1 -1
  44. package/lib/components/DataSpaceViewerActivityBar.d.ts.map +1 -1
  45. package/lib/components/DataSpaceViewerActivityBar.js +15 -12
  46. package/lib/components/DataSpaceViewerActivityBar.js.map +1 -1
  47. package/lib/components/index.d.ts +1 -0
  48. package/lib/components/index.d.ts.map +1 -1
  49. package/lib/components/index.js +1 -0
  50. package/lib/components/index.js.map +1 -1
  51. package/lib/graph-manager/protocol/pure/v1/V1_DSL_DataSpace_PureGraphManagerExtension.js +1 -1
  52. package/lib/graph-manager/protocol/pure/v1/V1_DSL_DataSpace_PureGraphManagerExtension.js.map +1 -1
  53. package/lib/index.css +2 -2
  54. package/lib/index.css.map +1 -1
  55. package/lib/package.json +2 -2
  56. package/lib/stores/DataSpaceLayoutState.d.ts +46 -0
  57. package/lib/stores/DataSpaceLayoutState.d.ts.map +1 -1
  58. package/lib/stores/DataSpaceLayoutState.js +184 -1
  59. package/lib/stores/DataSpaceLayoutState.js.map +1 -1
  60. package/lib/stores/DataSpaceModelsDocumentationState.d.ts +11 -2
  61. package/lib/stores/DataSpaceModelsDocumentationState.d.ts.map +1 -1
  62. package/lib/stores/DataSpaceModelsDocumentationState.js +41 -0
  63. package/lib/stores/DataSpaceModelsDocumentationState.js.map +1 -1
  64. package/lib/stores/DataSpaceQuickStartState.d.ts +24 -0
  65. package/lib/stores/DataSpaceQuickStartState.d.ts.map +1 -0
  66. package/lib/stores/DataSpaceQuickStartState.js +48 -0
  67. package/lib/stores/DataSpaceQuickStartState.js.map +1 -0
  68. package/lib/stores/DataSpaceViewerDiagramViewerState.d.ts +44 -0
  69. package/lib/stores/DataSpaceViewerDiagramViewerState.d.ts.map +1 -0
  70. package/lib/stores/DataSpaceViewerDiagramViewerState.js +194 -0
  71. package/lib/stores/DataSpaceViewerDiagramViewerState.js.map +1 -0
  72. package/lib/stores/DataSpaceViewerNavigation.d.ts +36 -0
  73. package/lib/stores/DataSpaceViewerNavigation.d.ts.map +1 -0
  74. package/lib/stores/DataSpaceViewerNavigation.js +47 -0
  75. package/lib/stores/DataSpaceViewerNavigation.js.map +1 -0
  76. package/lib/stores/DataSpaceViewerState.d.ts +22 -74
  77. package/lib/stores/DataSpaceViewerState.d.ts.map +1 -1
  78. package/lib/stores/DataSpaceViewerState.js +34 -259
  79. package/lib/stores/DataSpaceViewerState.js.map +1 -1
  80. package/lib/stores/query/DataSpaceAdvancedSearchState.d.ts.map +1 -1
  81. package/lib/stores/query/DataSpaceAdvancedSearchState.js +8 -5
  82. package/lib/stores/query/DataSpaceAdvancedSearchState.js.map +1 -1
  83. package/lib/stores/query/DataSpaceQueryCreatorStore.d.ts +8 -8
  84. package/lib/stores/query/DataSpaceQueryCreatorStore.d.ts.map +1 -1
  85. package/lib/stores/query/DataSpaceQueryCreatorStore.js +1 -1
  86. package/lib/stores/query/DataSpaceQueryCreatorStore.js.map +1 -1
  87. package/lib/stores/query/DataSpaceQuerySetupStore.d.ts +1 -1
  88. package/lib/stores/query/DataSpaceQuerySetupStore.d.ts.map +1 -1
  89. package/lib/stores/query/DataSpaceQuerySetupStore.js +1 -1
  90. package/lib/stores/query/DataSpaceQuerySetupStore.js.map +1 -1
  91. package/lib/stores/studio/DataSpacePreviewState.d.ts.map +1 -1
  92. package/lib/stores/studio/DataSpacePreviewState.js +15 -3
  93. package/lib/stores/studio/DataSpacePreviewState.js.map +1 -1
  94. package/package.json +14 -14
  95. package/src/__lib__/DSL_DataSpace_LegendApplicationCommand.ts +74 -0
  96. package/src/__lib__/DSL_DataSpace_LegendApplicationNavigation.ts +33 -0
  97. package/src/components/DSL_DataSpace_LegendApplicationPlugin.tsx +20 -1
  98. package/src/components/DataSpaceDataAccess.tsx +9 -122
  99. package/src/components/DataSpaceDescription.tsx +5 -5
  100. package/src/components/DataSpaceDiagramViewer.tsx +449 -69
  101. package/src/components/DataSpaceExecutionContextViewer.tsx +47 -40
  102. package/src/components/DataSpaceInfoPanel.tsx +107 -117
  103. package/src/components/DataSpaceModelsDocumentation.tsx +31 -12
  104. package/src/components/DataSpacePlaceholder.tsx +22 -0
  105. package/src/components/DataSpaceQuickStart.tsx +95 -15
  106. package/src/components/DataSpaceSupportPanel.tsx +146 -14
  107. package/src/components/DataSpaceViewer.tsx +153 -23
  108. package/src/components/DataSpaceViewerActivityBar.tsx +40 -20
  109. package/src/components/index.ts +1 -0
  110. package/src/graph-manager/protocol/pure/v1/V1_DSL_DataSpace_PureGraphManagerExtension.ts +1 -1
  111. package/src/stores/DataSpaceLayoutState.ts +272 -0
  112. package/src/stores/DataSpaceModelsDocumentationState.ts +61 -2
  113. package/src/stores/DataSpaceQuickStartState.ts +91 -0
  114. package/src/stores/DataSpaceViewerDiagramViewerState.ts +245 -0
  115. package/src/stores/DataSpaceViewerNavigation.ts +64 -0
  116. package/src/stores/DataSpaceViewerState.ts +88 -401
  117. package/src/stores/query/DataSpaceAdvancedSearchState.ts +30 -6
  118. package/src/stores/query/DataSpaceQueryCreatorStore.ts +8 -8
  119. package/src/stores/query/DataSpaceQuerySetupStore.ts +1 -1
  120. package/src/stores/studio/DataSpacePreviewState.ts +27 -5
  121. package/tsconfig.json +5 -1
  122. package/lib/stores/DataSpaceViewerDataAccessState.d.ts +0 -35
  123. package/lib/stores/DataSpaceViewerDataAccessState.d.ts.map +0 -1
  124. package/lib/stores/DataSpaceViewerDataAccessState.js +0 -98
  125. package/lib/stores/DataSpaceViewerDataAccessState.js.map +0 -1
  126. package/src/stores/DataSpaceViewerDataAccessState.ts +0 -143
@@ -16,28 +16,49 @@
16
16
 
17
17
  import {
18
18
  AnchorLinkIcon,
19
+ CaretDownIcon,
20
+ CenterFocusIcon,
19
21
  CircleIcon,
22
+ CloseIcon,
23
+ ContextMenu,
24
+ CustomSelectorInput,
25
+ DescriptionIcon,
26
+ DropdownMenu,
27
+ MenuContent,
28
+ MenuContentDivider,
29
+ MenuContentItem,
30
+ MousePointerIcon,
31
+ MoveIcon,
32
+ ShapesIcon,
33
+ ThinChevronDownIcon,
20
34
  ThinChevronLeftIcon,
21
35
  ThinChevronRightIcon,
36
+ ThinChevronUpIcon,
37
+ ZoomInIcon,
38
+ ZoomOutIcon,
22
39
  clsx,
23
40
  useResizeDetector,
24
41
  } from '@finos/legend-art';
25
- import {
26
- DATA_SPACE_VIEWER_ACTIVITY_MODE,
27
- generateAnchorForActivity,
28
- type DataSpaceViewerState,
29
- generateAnchorForDiagram,
30
- } from '../stores/DataSpaceViewerState.js';
42
+ import { type DataSpaceViewerState } from '../stores/DataSpaceViewerState.js';
31
43
  import { observer } from 'mobx-react-lite';
32
44
  import { forwardRef, useEffect, useRef } from 'react';
33
45
  import { type Diagram } from '@finos/legend-extension-dsl-diagram/graph';
34
- import { DiagramRenderer } from '@finos/legend-extension-dsl-diagram/application';
35
46
  import {
36
- getNullableFirstEntry,
37
- getNullableLastEntry,
38
- guaranteeNonNullable,
39
- } from '@finos/legend-shared';
47
+ DIAGRAM_INTERACTION_MODE,
48
+ DIAGRAM_RELATIONSHIP_EDIT_MODE,
49
+ DIAGRAM_ZOOM_LEVELS,
50
+ DiagramRenderer,
51
+ } from '@finos/legend-extension-dsl-diagram/application';
40
52
  import { DataSpaceWikiPlaceholder } from './DataSpacePlaceholder.js';
53
+ import type { DataSpaceDiagramAnalysisResult } from '../graph-manager/index.js';
54
+ import { getNonNullableEntry } from '@finos/legend-shared';
55
+ import { DataSpaceMarkdownTextViewer } from './DataSpaceMarkdownTextViewer.js';
56
+ import { useCommands } from '@finos/legend-application';
57
+ import {
58
+ DATA_SPACE_VIEWER_ACTIVITY_MODE,
59
+ generateAnchorForActivity,
60
+ generateAnchorForDiagram,
61
+ } from '../stores/DataSpaceViewerNavigation.js';
41
62
 
42
63
  const DataSpaceDiagramCanvas = observer(
43
64
  forwardRef<
@@ -48,7 +69,9 @@ const DataSpaceDiagramCanvas = observer(
48
69
  }
49
70
  >(function DataSpaceDiagramCanvas(props, ref) {
50
71
  const { dataSpaceViewerState, diagram } = props;
72
+ const diagramViewerState = dataSpaceViewerState.diagramViewerState;
51
73
  const diagramCanvasRef = ref as React.MutableRefObject<HTMLDivElement>;
74
+ const descriptionText = diagramViewerState.currentDiagram?.description;
52
75
 
53
76
  const { width, height } = useResizeDetector<HTMLDivElement>({
54
77
  refreshMode: 'debounce',
@@ -56,41 +79,411 @@ const DataSpaceDiagramCanvas = observer(
56
79
  targetRef: diagramCanvasRef,
57
80
  });
58
81
 
82
+ useEffect(() => {
83
+ diagramViewerState.setExpandDescription(false);
84
+ }, [diagramViewerState, diagramViewerState.currentDiagram]);
85
+
59
86
  useEffect(() => {
60
87
  const renderer = new DiagramRenderer(diagramCanvasRef.current, diagram);
61
- dataSpaceViewerState.setDiagramRenderer(renderer);
62
- dataSpaceViewerState.setupDiagramRenderer();
88
+ diagramViewerState.setDiagramRenderer(renderer);
89
+ diagramViewerState.setupDiagramRenderer();
63
90
  renderer.render({ initial: true });
64
- }, [diagramCanvasRef, dataSpaceViewerState, diagram]);
91
+ }, [diagramCanvasRef, diagramViewerState, diagram]);
65
92
 
66
93
  useEffect(() => {
67
- if (dataSpaceViewerState.isDiagramRendererInitialized) {
68
- dataSpaceViewerState.diagramRenderer.refresh();
94
+ if (diagramViewerState.isDiagramRendererInitialized) {
95
+ diagramViewerState.diagramRenderer.refresh();
69
96
  }
70
- }, [dataSpaceViewerState, width, height]);
97
+ }, [diagramViewerState, width, height]);
98
+
99
+ // actions
100
+ const queryClass = (): void => {
101
+ if (diagramViewerState.contextMenuClassView) {
102
+ dataSpaceViewerState.queryClass(
103
+ diagramViewerState.contextMenuClassView.class.value,
104
+ );
105
+ }
106
+ };
107
+ const viewClassDocumentation = (): void => {
108
+ if (
109
+ diagramViewerState.contextMenuClassView &&
110
+ dataSpaceViewerState.modelsDocumentationState.hasClassDocumentation(
111
+ diagramViewerState.contextMenuClassView.class.value.path,
112
+ )
113
+ ) {
114
+ dataSpaceViewerState.modelsDocumentationState.viewClassDocumentation(
115
+ diagramViewerState.contextMenuClassView.class.value.path,
116
+ );
117
+ dataSpaceViewerState.changeZone(
118
+ generateAnchorForActivity(
119
+ DATA_SPACE_VIEWER_ACTIVITY_MODE.MODELS_DOCUMENTATION,
120
+ ),
121
+ );
122
+ }
123
+ };
71
124
 
72
125
  return (
73
- <div
74
- ref={diagramCanvasRef}
75
- className={clsx(
76
- 'diagram-canvas ',
77
- dataSpaceViewerState.diagramCursorClass,
126
+ <ContextMenu
127
+ className="data-space__viewer__diagram-viewer__canvas"
128
+ content={
129
+ <MenuContent>
130
+ <MenuContentItem
131
+ onClick={queryClass}
132
+ disabled={!diagramViewerState.contextMenuClassView}
133
+ >
134
+ Query
135
+ </MenuContentItem>
136
+ <MenuContentItem
137
+ onClick={viewClassDocumentation}
138
+ disabled={
139
+ !diagramViewerState.contextMenuClassView ||
140
+ !dataSpaceViewerState.modelsDocumentationState.hasClassDocumentation(
141
+ diagramViewerState.contextMenuClassView.class.value.path,
142
+ )
143
+ }
144
+ >
145
+ View Documentation
146
+ </MenuContentItem>
147
+ </MenuContent>
148
+ }
149
+ disabled={!diagramViewerState.contextMenuClassView}
150
+ menuProps={{ elevation: 7 }}
151
+ onClose={(): void =>
152
+ diagramViewerState.setContextMenuClassView(undefined)
153
+ }
154
+ >
155
+ {diagramViewerState.showDescription && (
156
+ <div
157
+ className={clsx('data-space__viewer__diagram-viewer__description', {
158
+ 'data-space__viewer__diagram-viewer__description--expanded':
159
+ diagramViewerState.expandDescription,
160
+ })}
161
+ >
162
+ <button
163
+ className="data-space__viewer__diagram-viewer__description__close-btn"
164
+ tabIndex={-1}
165
+ title="Hide Description"
166
+ onClick={() => diagramViewerState.setShowDescription(false)}
167
+ >
168
+ <CloseIcon />
169
+ </button>
170
+ <div className="data-space__viewer__diagram-viewer__description__title">
171
+ {diagramViewerState.currentDiagram?.title
172
+ ? diagramViewerState.currentDiagram.title
173
+ : 'Untitled'}
174
+ </div>
175
+ <div className="data-space__viewer__diagram-viewer__description__content">
176
+ {descriptionText ? (
177
+ <DataSpaceMarkdownTextViewer value={descriptionText} />
178
+ ) : (
179
+ <div className="data-space__viewer__diagram-viewer__description__content__placeholder">
180
+ (not specified)
181
+ </div>
182
+ )}
183
+ </div>
184
+ <button
185
+ className="data-space__viewer__diagram-viewer__description__expand-btn"
186
+ tabIndex={-1}
187
+ title={
188
+ diagramViewerState.expandDescription ? 'Collapse' : 'Expand'
189
+ }
190
+ onClick={() =>
191
+ diagramViewerState.setExpandDescription(
192
+ !diagramViewerState.expandDescription,
193
+ )
194
+ }
195
+ >
196
+ {diagramViewerState.expandDescription ? (
197
+ <ThinChevronUpIcon />
198
+ ) : (
199
+ <ThinChevronDownIcon />
200
+ )}
201
+ </button>
202
+ </div>
78
203
  )}
79
- tabIndex={0}
80
- />
204
+ <div
205
+ ref={diagramCanvasRef}
206
+ className={clsx(
207
+ 'diagram-canvas',
208
+ diagramViewerState.diagramCursorClass,
209
+ )}
210
+ tabIndex={0}
211
+ />
212
+ </ContextMenu>
81
213
  );
82
214
  }),
83
215
  );
84
216
 
217
+ type DiagramOption = {
218
+ label: React.ReactNode;
219
+ value: DataSpaceDiagramAnalysisResult;
220
+ };
221
+ const buildDiagramOption = (
222
+ diagram: DataSpaceDiagramAnalysisResult,
223
+ ): DiagramOption => ({
224
+ label: (
225
+ <div className="data-space__viewer__diagram-viewer__header__navigation__selector__label">
226
+ <ShapesIcon className="data-space__viewer__diagram-viewer__header__navigation__selector__icon" />
227
+ <div className="data-space__viewer__diagram-viewer__header__navigation__selector__title">
228
+ {diagram.title ? diagram.title : 'Untitled'}
229
+ </div>
230
+ </div>
231
+ ),
232
+ value: diagram,
233
+ });
234
+
235
+ const DataSpaceDiagramViewerHeader = observer(
236
+ (props: { dataSpaceViewerState: DataSpaceViewerState }) => {
237
+ const { dataSpaceViewerState } = props;
238
+ const diagramViewerState = dataSpaceViewerState.diagramViewerState;
239
+ const diagramOptions =
240
+ dataSpaceViewerState.dataSpaceAnalysisResult.diagrams.map(
241
+ buildDiagramOption,
242
+ );
243
+ const selectedDiagramOption = diagramViewerState.currentDiagram
244
+ ? buildDiagramOption(diagramViewerState.currentDiagram)
245
+ : null;
246
+ const onDiagramOptionChange = (option: DiagramOption): void => {
247
+ if (option.value !== diagramViewerState.currentDiagram) {
248
+ diagramViewerState.setCurrentDiagram(option.value);
249
+ }
250
+ };
251
+ const createModeSwitcher =
252
+ (
253
+ editMode: DIAGRAM_INTERACTION_MODE,
254
+ relationshipMode: DIAGRAM_RELATIONSHIP_EDIT_MODE,
255
+ ): (() => void) =>
256
+ (): void =>
257
+ diagramViewerState.diagramRenderer.changeMode(
258
+ editMode,
259
+ relationshipMode,
260
+ );
261
+ const createCenterZoomer =
262
+ (zoomLevel: number): (() => void) =>
263
+ (): void => {
264
+ diagramViewerState.diagramRenderer.zoomCenter(zoomLevel / 100);
265
+ };
266
+ const zoomToFit = (): void =>
267
+ diagramViewerState.diagramRenderer.zoomToFit();
268
+
269
+ return (
270
+ <div className="data-space__viewer__diagram-viewer__header">
271
+ <div className="data-space__viewer__diagram-viewer__header__navigation">
272
+ <CustomSelectorInput
273
+ className="data-space__viewer__diagram-viewer__header__navigation__selector"
274
+ options={diagramOptions}
275
+ onChange={onDiagramOptionChange}
276
+ value={selectedDiagramOption}
277
+ placeholder="Search for a diagram"
278
+ darkMode={true}
279
+ />
280
+ <div className="data-space__viewer__diagram-viewer__header__navigation__pager">
281
+ <input
282
+ className="data-space__viewer__diagram-viewer__header__navigation__pager__input input--dark"
283
+ value={diagramViewerState.currentDiagramIndex}
284
+ type="number"
285
+ onChange={(event) => {
286
+ const value = parseInt(event.target.value, 10);
287
+ if (
288
+ isNaN(value) ||
289
+ value < 1 ||
290
+ value >
291
+ dataSpaceViewerState.dataSpaceAnalysisResult.diagrams.length
292
+ ) {
293
+ return;
294
+ }
295
+ diagramViewerState.setCurrentDiagram(
296
+ getNonNullableEntry(
297
+ dataSpaceViewerState.dataSpaceAnalysisResult.diagrams,
298
+ value - 1,
299
+ ),
300
+ );
301
+ }}
302
+ />
303
+ </div>
304
+ <div className="data-space__viewer__diagram-viewer__header__navigation__pager__count">
305
+ /{dataSpaceViewerState.dataSpaceAnalysisResult.diagrams.length}
306
+ </div>
307
+ </div>
308
+ <div className="data-space__viewer__diagram-viewer__header__actions">
309
+ {diagramViewerState.isDiagramRendererInitialized && (
310
+ <>
311
+ <div className="data-space__viewer__diagram-viewer__header__group">
312
+ <button
313
+ className="data-space__viewer__diagram-viewer__header__tool"
314
+ tabIndex={-1}
315
+ onClick={(): void => {
316
+ if (diagramViewerState.currentDiagram) {
317
+ dataSpaceViewerState.syncZoneWithNavigation(
318
+ generateAnchorForDiagram(
319
+ diagramViewerState.currentDiagram,
320
+ ),
321
+ );
322
+ }
323
+ }}
324
+ title="Copy Link"
325
+ >
326
+ <AnchorLinkIcon />
327
+ </button>
328
+ <button
329
+ className="data-space__viewer__diagram-viewer__header__tool"
330
+ tabIndex={-1}
331
+ onClick={() => diagramViewerState.diagramRenderer.recenter()}
332
+ title="Recenter (R)"
333
+ >
334
+ <CenterFocusIcon className="data-space__viewer__diagram-viewer__icon--recenter" />
335
+ </button>
336
+ <button
337
+ className={clsx(
338
+ 'data-space__viewer__diagram-viewer__header__tool',
339
+ {
340
+ 'data-space__viewer__diagram-viewer__header__tool--active':
341
+ diagramViewerState.showDescription,
342
+ },
343
+ )}
344
+ tabIndex={-1}
345
+ onClick={() =>
346
+ diagramViewerState.setShowDescription(
347
+ !diagramViewerState.showDescription,
348
+ )
349
+ }
350
+ title="Toggle Description (D)"
351
+ >
352
+ <DescriptionIcon className="data-space__viewer__diagram-viewer__icon--description" />
353
+ </button>
354
+ </div>
355
+ <div className="data-space__viewer__diagram-viewer__header__group__separator" />
356
+ <div className="data-space__viewer__diagram-viewer__header__group">
357
+ <button
358
+ className={clsx(
359
+ 'data-space__viewer__diagram-viewer__header__tool',
360
+ {
361
+ 'data-space__viewer__diagram-viewer__header__tool--active':
362
+ diagramViewerState.diagramRenderer.interactionMode ===
363
+ DIAGRAM_INTERACTION_MODE.LAYOUT,
364
+ },
365
+ )}
366
+ tabIndex={-1}
367
+ onClick={createModeSwitcher(
368
+ DIAGRAM_INTERACTION_MODE.LAYOUT,
369
+ DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE,
370
+ )}
371
+ title="View Tool (V)"
372
+ >
373
+ <MousePointerIcon className="data-space__viewer__diagram-viewer__icon--layout" />
374
+ </button>
375
+ <button
376
+ className={clsx(
377
+ 'data-space__viewer__diagram-viewer__header__tool',
378
+ {
379
+ 'data-space__viewer__diagram-viewer__header__tool--active':
380
+ diagramViewerState.diagramRenderer.interactionMode ===
381
+ DIAGRAM_INTERACTION_MODE.PAN,
382
+ },
383
+ )}
384
+ tabIndex={-1}
385
+ onClick={createModeSwitcher(
386
+ DIAGRAM_INTERACTION_MODE.PAN,
387
+ DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE,
388
+ )}
389
+ title="Pan Tool (M)"
390
+ >
391
+ <MoveIcon className="data-space__viewer__diagram-viewer__icon--pan" />
392
+ </button>
393
+ <button
394
+ className={clsx(
395
+ 'data-space__viewer__diagram-viewer__header__tool',
396
+ {
397
+ 'data-space__viewer__diagram-viewer__header__tool--active':
398
+ diagramViewerState.diagramRenderer.interactionMode ===
399
+ DIAGRAM_INTERACTION_MODE.ZOOM_IN,
400
+ },
401
+ )}
402
+ tabIndex={-1}
403
+ title="Zoom In (Z)"
404
+ onClick={createModeSwitcher(
405
+ DIAGRAM_INTERACTION_MODE.ZOOM_IN,
406
+ DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE,
407
+ )}
408
+ >
409
+ <ZoomInIcon className="data-space__viewer__diagram-viewer__icon--zoom-in" />
410
+ </button>
411
+ <button
412
+ className={clsx(
413
+ 'data-space__viewer__diagram-viewer__header__tool',
414
+ {
415
+ 'data-space__viewer__diagram-viewer__header__tool--active':
416
+ diagramViewerState.diagramRenderer.interactionMode ===
417
+ DIAGRAM_INTERACTION_MODE.ZOOM_OUT,
418
+ },
419
+ )}
420
+ tabIndex={-1}
421
+ title="Zoom Out (Z)"
422
+ onClick={createModeSwitcher(
423
+ DIAGRAM_INTERACTION_MODE.ZOOM_OUT,
424
+ DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE,
425
+ )}
426
+ >
427
+ <ZoomOutIcon className="data-space__viewer__diagram-viewer__icon--zoom-out" />
428
+ </button>
429
+ </div>
430
+ <div className="data-space__viewer__diagram-viewer__header__group__separator" />
431
+ <DropdownMenu
432
+ className="data-space__viewer__diagram-viewer__header__group data-space__viewer__diagram-viewer__header__dropdown"
433
+ title="Zoom..."
434
+ content={
435
+ <MenuContent>
436
+ <MenuContentItem
437
+ className="data-space__viewer__diagram-viewer__header__zoomer__dropdown__menu__item"
438
+ onClick={zoomToFit}
439
+ >
440
+ Fit
441
+ </MenuContentItem>
442
+ <MenuContentDivider />
443
+ {DIAGRAM_ZOOM_LEVELS.map((zoomLevel) => (
444
+ <MenuContentItem
445
+ key={zoomLevel}
446
+ className="data-space__viewer__diagram-viewer__header__zoomer__dropdown__menu__item"
447
+ onClick={createCenterZoomer(zoomLevel)}
448
+ >
449
+ {zoomLevel}%
450
+ </MenuContentItem>
451
+ ))}
452
+ </MenuContent>
453
+ }
454
+ menuProps={{
455
+ anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
456
+ transformOrigin: { vertical: 'top', horizontal: 'right' },
457
+ elevation: 7,
458
+ }}
459
+ >
460
+ <div className="data-space__viewer__diagram-viewer__header__dropdown__label data-space__viewer__diagram-viewer__header__zoomer__dropdown__label">
461
+ {Math.round(diagramViewerState.diagramRenderer.zoom * 100)}%
462
+ </div>
463
+ <div className="data-space__viewer__diagram-viewer__header__dropdown__trigger data-space__viewer__diagram-viewer__header__zoomer__dropdown__trigger">
464
+ <CaretDownIcon />
465
+ </div>
466
+ </DropdownMenu>
467
+ </>
468
+ )}
469
+ </div>
470
+ </div>
471
+ );
472
+ },
473
+ );
474
+
85
475
  export const DataSpaceDiagramViewer = observer(
86
476
  (props: { dataSpaceViewerState: DataSpaceViewerState }) => {
87
477
  const { dataSpaceViewerState } = props;
478
+ const diagramViewerState = dataSpaceViewerState.diagramViewerState;
88
479
  const analysisResult = dataSpaceViewerState.dataSpaceAnalysisResult;
89
480
  const sectionRef = useRef<HTMLDivElement>(null);
90
481
  const anchor = generateAnchorForActivity(
91
482
  DATA_SPACE_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER,
92
483
  );
93
484
 
485
+ useCommands(diagramViewerState);
486
+
94
487
  useEffect(() => {
95
488
  if (sectionRef.current) {
96
489
  dataSpaceViewerState.layoutState.setWikiPageAnchor(
@@ -101,44 +494,25 @@ export const DataSpaceDiagramViewer = observer(
101
494
  return () => dataSpaceViewerState.layoutState.unsetWikiPageAnchor(anchor);
102
495
  }, [dataSpaceViewerState, anchor]);
103
496
 
104
- // diagram selector
105
497
  const diagramCanvasRef = useRef<HTMLDivElement>(null);
498
+ const previousDiagram = diagramViewerState.previousDiagram;
499
+ const nextDiagram = diagramViewerState.nextDiagram;
106
500
 
107
501
  const showPreviousDiagram = (): void => {
108
- if (!dataSpaceViewerState.currentDiagram) {
109
- return;
110
- }
111
- const idx = analysisResult.diagrams.indexOf(
112
- dataSpaceViewerState.currentDiagram,
113
- );
114
- if (idx === 0 || idx === -1) {
115
- return;
502
+ if (previousDiagram) {
503
+ diagramViewerState.setCurrentDiagram(previousDiagram);
504
+ dataSpaceViewerState.syncZoneWithNavigation(
505
+ generateAnchorForDiagram(previousDiagram),
506
+ );
116
507
  }
117
- const previousDiagram = guaranteeNonNullable(
118
- analysisResult.diagrams[idx - 1],
119
- );
120
- dataSpaceViewerState.setCurrentDiagram(previousDiagram);
121
- dataSpaceViewerState.syncZoneWithNavigation(
122
- generateAnchorForDiagram(previousDiagram),
123
- );
124
508
  };
125
509
  const showNextDiagram = (): void => {
126
- if (!dataSpaceViewerState.currentDiagram) {
127
- return;
128
- }
129
- const idx = analysisResult.diagrams.indexOf(
130
- dataSpaceViewerState.currentDiagram,
131
- );
132
- if (idx === analysisResult.diagrams.length - 1 || idx === -1) {
133
- return;
510
+ if (nextDiagram) {
511
+ diagramViewerState.setCurrentDiagram(nextDiagram);
512
+ dataSpaceViewerState.syncZoneWithNavigation(
513
+ generateAnchorForDiagram(nextDiagram),
514
+ );
134
515
  }
135
- const nextDiagram = guaranteeNonNullable(
136
- analysisResult.diagrams[idx + 1],
137
- );
138
- dataSpaceViewerState.setCurrentDiagram(nextDiagram);
139
- dataSpaceViewerState.syncZoneWithNavigation(
140
- generateAnchorForDiagram(nextDiagram),
141
- );
142
516
  };
143
517
 
144
518
  return (
@@ -158,13 +532,16 @@ export const DataSpaceDiagramViewer = observer(
158
532
  <div className="data-space__viewer__wiki__section__content">
159
533
  {analysisResult.diagrams.length > 0 && (
160
534
  <div className="data-space__viewer__diagram-viewer">
535
+ <DataSpaceDiagramViewerHeader
536
+ dataSpaceViewerState={dataSpaceViewerState}
537
+ />
161
538
  <div className="data-space__viewer__diagram-viewer__carousel">
162
539
  <div className="data-space__viewer__diagram-viewer__carousel__frame">
163
540
  <div className="data-space__viewer__diagram-viewer__carousel__frame__display">
164
- {dataSpaceViewerState.currentDiagram && (
541
+ {diagramViewerState.currentDiagram && (
165
542
  <DataSpaceDiagramCanvas
166
543
  dataSpaceViewerState={dataSpaceViewerState}
167
- diagram={dataSpaceViewerState.currentDiagram.diagram}
544
+ diagram={diagramViewerState.currentDiagram.diagram}
168
545
  ref={diagramCanvasRef}
169
546
  />
170
547
  )}
@@ -172,11 +549,12 @@ export const DataSpaceDiagramViewer = observer(
172
549
  <button
173
550
  className="data-space__viewer__diagram-viewer__carousel__frame__navigator data-space__viewer__diagram-viewer__carousel__frame__navigator--back"
174
551
  tabIndex={-1}
175
- title="Previous"
176
- disabled={
177
- getNullableFirstEntry(analysisResult.diagrams) ===
178
- dataSpaceViewerState.currentDiagram
179
- }
552
+ title={`Previous - ${
553
+ previousDiagram?.title
554
+ ? previousDiagram.title
555
+ : '(untitled)'
556
+ } (⇦)`}
557
+ disabled={!previousDiagram}
180
558
  onClick={showPreviousDiagram}
181
559
  >
182
560
  <ThinChevronLeftIcon />
@@ -184,11 +562,10 @@ export const DataSpaceDiagramViewer = observer(
184
562
  <button
185
563
  className="data-space__viewer__diagram-viewer__carousel__frame__navigator data-space__viewer__diagram-viewer__carousel__frame__navigator--next"
186
564
  tabIndex={-1}
187
- title="Next"
188
- disabled={
189
- getNullableLastEntry(analysisResult.diagrams) ===
190
- dataSpaceViewerState.currentDiagram
191
- }
565
+ title={`Next - ${
566
+ nextDiagram?.title ? nextDiagram.title : '(untitled)'
567
+ } ()`}
568
+ disabled={!nextDiagram}
192
569
  onClick={showNextDiagram}
193
570
  >
194
571
  <ThinChevronRightIcon />
@@ -202,11 +579,14 @@ export const DataSpaceDiagramViewer = observer(
202
579
  'data-space__viewer__diagram-viewer__carousel__frame__indicator',
203
580
  {
204
581
  'data-space__viewer__diagram-viewer__carousel__frame__indicator--active':
205
- dataSpaceViewerState.currentDiagram === diagram,
582
+ diagramViewerState.currentDiagram === diagram,
206
583
  },
207
584
  )}
585
+ title={`View Diagram - ${
586
+ diagram.title ? diagram.title : '(untitled)'
587
+ }`}
208
588
  onClick={() => {
209
- dataSpaceViewerState.setCurrentDiagram(diagram);
589
+ diagramViewerState.setCurrentDiagram(diagram);
210
590
  dataSpaceViewerState.syncZoneWithNavigation(
211
591
  generateAnchorForDiagram(diagram),
212
592
  );