@finos/legend-application-studio 22.1.5 → 22.2.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.
Files changed (95) hide show
  1. package/lib/components/DSL_ExternalFormat_LegendStudioApplicationPlugin.d.ts +3 -1
  2. package/lib/components/DSL_ExternalFormat_LegendStudioApplicationPlugin.d.ts.map +1 -1
  3. package/lib/components/DSL_ExternalFormat_LegendStudioApplicationPlugin.js +15 -3
  4. package/lib/components/DSL_ExternalFormat_LegendStudioApplicationPlugin.js.map +1 -1
  5. package/lib/components/editor/edit-panel/GrammarTextEditor.d.ts.map +1 -1
  6. package/lib/components/editor/edit-panel/GrammarTextEditor.js +8 -0
  7. package/lib/components/editor/edit-panel/GrammarTextEditor.js.map +1 -1
  8. package/lib/components/editor/edit-panel/external-format-editor/DSL_ExternalFormat_ExternalFormatConnectionEditor.d.ts +1 -0
  9. package/lib/components/editor/edit-panel/external-format-editor/DSL_ExternalFormat_ExternalFormatConnectionEditor.d.ts.map +1 -1
  10. package/lib/components/editor/edit-panel/external-format-editor/DSL_ExternalFormat_ExternalFormatConnectionEditor.js +4 -0
  11. package/lib/components/editor/edit-panel/external-format-editor/DSL_ExternalFormat_ExternalFormatConnectionEditor.js.map +1 -1
  12. package/lib/components/editor/edit-panel/project-configuration-editor/ProjectDependencyEditor.d.ts.map +1 -1
  13. package/lib/components/editor/edit-panel/project-configuration-editor/ProjectDependencyEditor.js +155 -59
  14. package/lib/components/editor/edit-panel/project-configuration-editor/ProjectDependencyEditor.js.map +1 -1
  15. package/lib/components/editor/side-bar/CreateNewElementModal.d.ts.map +1 -1
  16. package/lib/components/editor/side-bar/CreateNewElementModal.js +28 -23
  17. package/lib/components/editor/side-bar/CreateNewElementModal.js.map +1 -1
  18. package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
  19. package/lib/components/editor/side-bar/Explorer.js +1 -0
  20. package/lib/components/editor/side-bar/Explorer.js.map +1 -1
  21. package/lib/components/editor/side-bar/LocalChanges.d.ts.map +1 -1
  22. package/lib/components/editor/side-bar/LocalChanges.js +16 -3
  23. package/lib/components/editor/side-bar/LocalChanges.js.map +1 -1
  24. package/lib/index.css +2 -2
  25. package/lib/index.css.map +1 -1
  26. package/lib/package.json +3 -3
  27. package/lib/stores/ChangeDetectionState.d.ts +3 -0
  28. package/lib/stores/ChangeDetectionState.d.ts.map +1 -1
  29. package/lib/stores/ChangeDetectionState.js +68 -1
  30. package/lib/stores/ChangeDetectionState.js.map +1 -1
  31. package/lib/stores/DSL_Mapping_LegendStudioApplicationPlugin_Extension.d.ts +15 -1
  32. package/lib/stores/DSL_Mapping_LegendStudioApplicationPlugin_Extension.d.ts.map +1 -1
  33. package/lib/stores/EditorGraphState.d.ts +9 -1
  34. package/lib/stores/EditorGraphState.d.ts.map +1 -1
  35. package/lib/stores/EditorGraphState.js +220 -38
  36. package/lib/stores/EditorGraphState.js.map +1 -1
  37. package/lib/stores/EditorStore.d.ts +2 -1
  38. package/lib/stores/EditorStore.d.ts.map +1 -1
  39. package/lib/stores/EditorStore.js +14 -2
  40. package/lib/stores/EditorStore.js.map +1 -1
  41. package/lib/stores/EditorTabManagerState.d.ts +3 -10
  42. package/lib/stores/EditorTabManagerState.d.ts.map +1 -1
  43. package/lib/stores/EditorTabManagerState.js +33 -37
  44. package/lib/stores/EditorTabManagerState.js.map +1 -1
  45. package/lib/stores/ExplorerTreeState.d.ts +2 -0
  46. package/lib/stores/ExplorerTreeState.d.ts.map +1 -1
  47. package/lib/stores/ExplorerTreeState.js +53 -0
  48. package/lib/stores/ExplorerTreeState.js.map +1 -1
  49. package/lib/stores/LegendStudioRouter.d.ts +1 -1
  50. package/lib/stores/LegendStudioRouter.d.ts.map +1 -1
  51. package/lib/stores/LegendStudioRouter.js.map +1 -1
  52. package/lib/stores/editor/NewElementState.d.ts +14 -9
  53. package/lib/stores/editor/NewElementState.d.ts.map +1 -1
  54. package/lib/stores/editor/NewElementState.js +38 -19
  55. package/lib/stores/editor/NewElementState.js.map +1 -1
  56. package/lib/stores/editor-state/FileGenerationViewerState.d.ts +1 -0
  57. package/lib/stores/editor-state/FileGenerationViewerState.d.ts.map +1 -1
  58. package/lib/stores/editor-state/FileGenerationViewerState.js +4 -0
  59. package/lib/stores/editor-state/FileGenerationViewerState.js.map +1 -1
  60. package/lib/stores/editor-state/GraphGenerationState.d.ts.map +1 -1
  61. package/lib/stores/editor-state/GraphGenerationState.js +4 -1
  62. package/lib/stores/editor-state/GraphGenerationState.js.map +1 -1
  63. package/lib/stores/editor-state/element-editor-state/ElementEditorState.d.ts +1 -0
  64. package/lib/stores/editor-state/element-editor-state/ElementEditorState.d.ts.map +1 -1
  65. package/lib/stores/editor-state/element-editor-state/ElementEditorState.js +4 -0
  66. package/lib/stores/editor-state/element-editor-state/ElementEditorState.js.map +1 -1
  67. package/lib/stores/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.d.ts +46 -13
  68. package/lib/stores/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.d.ts.map +1 -1
  69. package/lib/stores/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.js +176 -23
  70. package/lib/stores/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.js.map +1 -1
  71. package/lib/stores/sidebar-state/LocalChangesState.d.ts +14 -2
  72. package/lib/stores/sidebar-state/LocalChangesState.d.ts.map +1 -1
  73. package/lib/stores/sidebar-state/LocalChangesState.js +206 -30
  74. package/lib/stores/sidebar-state/LocalChangesState.js.map +1 -1
  75. package/package.json +12 -12
  76. package/src/components/DSL_ExternalFormat_LegendStudioApplicationPlugin.tsx +17 -3
  77. package/src/components/editor/edit-panel/GrammarTextEditor.tsx +14 -0
  78. package/src/components/editor/edit-panel/external-format-editor/DSL_ExternalFormat_ExternalFormatConnectionEditor.tsx +5 -0
  79. package/src/components/editor/edit-panel/project-configuration-editor/ProjectDependencyEditor.tsx +430 -169
  80. package/src/components/editor/side-bar/CreateNewElementModal.tsx +50 -43
  81. package/src/components/editor/side-bar/Explorer.tsx +1 -0
  82. package/src/components/editor/side-bar/LocalChanges.tsx +16 -6
  83. package/src/stores/ChangeDetectionState.ts +119 -0
  84. package/src/stores/DSL_Mapping_LegendStudioApplicationPlugin_Extension.ts +19 -1
  85. package/src/stores/EditorGraphState.ts +321 -44
  86. package/src/stores/EditorStore.ts +22 -2
  87. package/src/stores/EditorTabManagerState.ts +55 -37
  88. package/src/stores/ExplorerTreeState.ts +118 -0
  89. package/src/stores/LegendStudioRouter.ts +1 -1
  90. package/src/stores/editor/NewElementState.ts +57 -28
  91. package/src/stores/editor-state/FileGenerationViewerState.ts +5 -0
  92. package/src/stores/editor-state/GraphGenerationState.ts +9 -0
  93. package/src/stores/editor-state/element-editor-state/ElementEditorState.ts +5 -0
  94. package/src/stores/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.ts +259 -34
  95. package/src/stores/sidebar-state/LocalChangesState.ts +338 -62
@@ -14,12 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import {
18
- EDITOR_LANGUAGE,
19
- TextInputEditor,
20
- useApplicationStore,
21
- TAB_SIZE,
22
- } from '@finos/legend-application';
17
+ import { useApplicationStore, TAB_SIZE } from '@finos/legend-application';
23
18
  import {
24
19
  type SelectComponent,
25
20
  type TreeData,
@@ -43,10 +38,13 @@ import {
43
38
  ChevronDownIcon,
44
39
  ChevronRightIcon,
45
40
  ContextMenu,
46
- RepoIcon,
47
41
  CompressIcon,
48
42
  SubjectIcon,
49
43
  ViewHeadlineIcon,
44
+ ExpandAllIcon,
45
+ BlankPanelContent,
46
+ VersionsIcon,
47
+ RepoIcon,
50
48
  } from '@finos/legend-art';
51
49
  import {
52
50
  MASTER_SNAPSHOT_ALIAS,
@@ -60,6 +58,7 @@ import {
60
58
  guaranteeNonNullable,
61
59
  isNonNullable,
62
60
  LogEvent,
61
+ prettyCONSTName,
63
62
  } from '@finos/legend-shared';
64
63
  import {
65
64
  compareSemVerVersions,
@@ -70,13 +69,19 @@ import { observer } from 'mobx-react-lite';
70
69
  import { forwardRef, useRef, useState } from 'react';
71
70
  import { ProjectConfigurationEditorState } from '../../../../stores/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js';
72
71
  import {
72
+ type ProjectDependencyConflictTreeNodeData,
73
+ ConflictTreeNodeData,
74
+ ConflictVersionNodeData,
73
75
  buildDependencyNodeChildren,
74
- type DependencyTreeNodeData,
76
+ DEPENDENCY_REPORT_TAB,
77
+ openAllDependencyNodesInTree,
78
+ ProjectDependencyTreeNodeData,
75
79
  type ProjectDependencyEditorState,
76
80
  } from '../../../../stores/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.js';
77
81
  import { LEGEND_STUDIO_APP_EVENT } from '../../../../stores/LegendStudioAppEvent.js';
78
82
  import {
79
83
  generateViewProjectByGAVRoute,
84
+ generateViewProjectRoute,
80
85
  generateViewVersionRoute,
81
86
  } from '../../../../stores/LegendStudioRouter.js';
82
87
  import { LEGEND_STUDIO_TEST_ID } from '../../../LegendStudioTestID.js';
@@ -103,12 +108,16 @@ const ProjectDependencyActions = observer(
103
108
  dependencyEditorState.dependencyReport?.conflicts.length;
104
109
  const viewTree = (): void => {
105
110
  if (dependencyEditorState.dependencyReport) {
106
- dependencyEditorState.setDependencyTreeReportModal(true);
111
+ dependencyEditorState.setDependencyReport(
112
+ DEPENDENCY_REPORT_TAB.EXPLORER,
113
+ );
107
114
  }
108
115
  };
109
116
  const viewConflict = (): void => {
110
117
  if (dependencyEditorState.dependencyReport) {
111
- dependencyEditorState.setDependencyConflictModal(true);
118
+ dependencyEditorState.setDependencyReport(
119
+ DEPENDENCY_REPORT_TAB.CONFLICTS,
120
+ );
112
121
  }
113
122
  };
114
123
  return (
@@ -122,14 +131,13 @@ const ProjectDependencyActions = observer(
122
131
  >
123
132
  View Dependency Explorer
124
133
  </button>
125
-
126
134
  {Boolean(hasConflicts) && (
127
135
  <button
128
136
  className="project-dependency-editor__conflicts-btn"
129
137
  tabIndex={-1}
130
138
  onClick={viewConflict}
131
139
  disabled={
132
- !dependencyEditorState.dependencyReport?.conflictPaths.size
140
+ !dependencyEditorState.dependencyReport?.conflictInfo.size
133
141
  }
134
142
  title="View any conflicts in your dependencies"
135
143
  >
@@ -156,37 +164,75 @@ const DependencyTreeNodeContextMenu = observer(
156
164
  forwardRef<
157
165
  HTMLDivElement,
158
166
  {
159
- node: DependencyTreeNodeData;
167
+ node: ProjectDependencyConflictTreeNodeData;
160
168
  }
161
- >(function WorkflowExplorerContextMenu(props, ref) {
169
+ >(function DependencyTreeNodeContextMenu(props, ref) {
162
170
  const { node } = props;
163
- const value = node.value;
164
171
  const applicationStore = useApplicationStore();
172
+ const getViewProjectUrl = (): string => {
173
+ let groupId: string | undefined;
174
+ let artifactId: string | undefined;
175
+ let versionId: string | undefined;
176
+ if (node instanceof ConflictTreeNodeData) {
177
+ groupId = node.conflict.groupId;
178
+ artifactId = node.conflict.artifactId;
179
+ } else if (node instanceof ConflictVersionNodeData) {
180
+ groupId = node.versionConflict.conflict.groupId;
181
+ artifactId = node.versionConflict.conflict.artifactId;
182
+ versionId = node.versionConflict.version.versionId;
183
+ } else if (node instanceof ProjectDependencyTreeNodeData) {
184
+ groupId = node.value.groupId;
185
+ artifactId = node.value.artifactId;
186
+ versionId = node.value.versionId;
187
+ }
188
+ return generateViewProjectByGAVRoute(
189
+ guaranteeNonNullable(groupId),
190
+ guaranteeNonNullable(artifactId),
191
+ versionId === MASTER_SNAPSHOT_ALIAS
192
+ ? SNAPSHOT_VERSION_ALIAS
193
+ : versionId,
194
+ );
195
+ };
196
+ const getSDLCProjectUrl = (): string | undefined => {
197
+ if (node instanceof ConflictTreeNodeData) {
198
+ const version = node.conflict.versions[0];
199
+ return version
200
+ ? generateViewProjectRoute(version.projectId)
201
+ : undefined;
202
+ } else if (node instanceof ConflictVersionNodeData) {
203
+ return generateViewVersionRoute(
204
+ node.versionConflict.version.projectId,
205
+ node.versionConflict.version.artifactId,
206
+ );
207
+ } else if (node instanceof ProjectDependencyTreeNodeData) {
208
+ return generateViewVersionRoute(
209
+ node.value.projectId,
210
+ node.value.versionId,
211
+ );
212
+ }
213
+ return undefined;
214
+ };
215
+
216
+ const sdlcProjectUrl = getSDLCProjectUrl();
217
+ const viewProjectUrl = getViewProjectUrl();
218
+
165
219
  const viewProject = (): void => {
166
220
  applicationStore.navigator.visitAddress(
167
- applicationStore.navigator.generateAddress(
168
- generateViewProjectByGAVRoute(
169
- guaranteeNonNullable(value.groupId),
170
- guaranteeNonNullable(value.artifactId),
171
- value.versionId === MASTER_SNAPSHOT_ALIAS
172
- ? SNAPSHOT_VERSION_ALIAS
173
- : value.versionId,
174
- ),
175
- ),
221
+ applicationStore.navigator.generateAddress(viewProjectUrl),
176
222
  );
177
223
  };
178
224
  const viewSDLCProject = (): void => {
179
- applicationStore.navigator.visitAddress(
180
- applicationStore.navigator.generateAddress(
181
- generateViewVersionRoute(value.projectId, value.versionId),
182
- ),
183
- );
225
+ if (sdlcProjectUrl) {
226
+ applicationStore.navigator.visitAddress(
227
+ applicationStore.navigator.generateAddress(sdlcProjectUrl),
228
+ );
229
+ }
184
230
  };
185
231
 
186
232
  return (
187
233
  <MenuContent data-testid={LEGEND_STUDIO_TEST_ID.EXPLORER_CONTEXT_MENU}>
188
234
  <MenuContentItem onClick={viewProject}>Visit Project</MenuContentItem>
189
- <MenuContentItem onClick={viewSDLCProject}>
235
+ <MenuContentItem disabled={!sdlcProjectUrl} onClick={viewSDLCProject}>
190
236
  Visit SDLC Project
191
237
  </MenuContentItem>
192
238
  </MenuContent>
@@ -196,19 +242,16 @@ const DependencyTreeNodeContextMenu = observer(
196
242
 
197
243
  const DependencyTreeNodeContainer: React.FC<
198
244
  TreeNodeContainerProps<
199
- DependencyTreeNodeData,
245
+ ProjectDependencyTreeNodeData,
200
246
  {
201
- onNodeExpand: (node: DependencyTreeNodeData) => void;
247
+ onNodeExpand: (node: ProjectDependencyTreeNodeData) => void;
202
248
  }
203
249
  >
204
250
  > = (props) => {
205
- const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
206
- const { onNodeExpand } = innerProps;
251
+ const { node, level, stepPaddingInRem, onNodeSelect } = props;
207
252
  const isExpandable = Boolean(node.childrenIds?.length);
208
253
  const selectNode = (): void => onNodeSelect?.(node);
209
- const expandNode = (): void => onNodeExpand(node);
210
254
  const value = node.value;
211
- const label = `${value.artifactId}:${value.versionId}`;
212
255
  const nodeExpandIcon = isExpandable ? (
213
256
  node.isOpen ? (
214
257
  <ChevronDownIcon />
@@ -218,7 +261,6 @@ const DependencyTreeNodeContainer: React.FC<
218
261
  ) : (
219
262
  <div />
220
263
  );
221
-
222
264
  return (
223
265
  <ContextMenu
224
266
  content={<DependencyTreeNodeContextMenu node={node} />}
@@ -241,36 +283,37 @@ const DependencyTreeNodeContainer: React.FC<
241
283
  onClick={selectNode}
242
284
  >
243
285
  <div className="tree-view__node__icon project-dependency-explorer-tree__node__icon">
244
- <div
245
- onClick={expandNode}
246
- className="project-dependency-explorer-tree__node__icon__expand"
247
- >
286
+ <div className="project-dependency-explorer-tree__node__icon__expand">
248
287
  {nodeExpandIcon}
249
288
  </div>
250
- <div className="project-dependency-explorer-tree__node__icon__type">
251
- <RepoIcon />
252
- </div>
253
289
  </div>
254
-
255
290
  <button
256
291
  className="tree-view__node__label project-dependency-explorer-tree__node__label"
257
292
  tabIndex={-1}
258
- title={node.id}
293
+ title={value.id}
259
294
  >
260
- {label}
295
+ {value.artifactId}
261
296
  </button>
297
+ <div className="project-dependency-explorer-tree__node__version">
298
+ <button
299
+ className="project-dependency-explorer-tree__node__version-btn"
300
+ title={value.versionId}
301
+ tabIndex={-1}
302
+ >
303
+ {value.versionId}
304
+ </button>
305
+ </div>
262
306
  </div>
263
307
  </ContextMenu>
264
308
  );
265
309
  };
266
310
 
267
311
  const DependencyTreeView: React.FC<{
268
- configState: ProjectDependencyEditorState;
269
- treeData: TreeData<DependencyTreeNodeData>;
270
- setTreeData: (treeData: TreeData<DependencyTreeNodeData>) => void;
312
+ treeData: TreeData<ProjectDependencyTreeNodeData>;
313
+ setTreeData: (treeData: TreeData<ProjectDependencyTreeNodeData>) => void;
271
314
  }> = (props) => {
272
315
  const { treeData, setTreeData } = props;
273
- const onNodeExpand = (node: DependencyTreeNodeData): void => {
316
+ const onNodeExpand = (node: ProjectDependencyTreeNodeData): void => {
274
317
  if (node.childrenIds?.length) {
275
318
  node.isOpen = !node.isOpen;
276
319
  node.childrenIds
@@ -280,15 +323,14 @@ const DependencyTreeView: React.FC<{
280
323
  }
281
324
  setTreeData({ ...treeData });
282
325
  };
283
- const onNodeSelect = (node: DependencyTreeNodeData): void => {
326
+ const onNodeSelect = (node: ProjectDependencyTreeNodeData): void => {
284
327
  buildDependencyNodeChildren(node, treeData.nodes);
285
328
  onNodeExpand(node);
286
329
  setTreeData({ ...treeData });
287
330
  };
288
-
289
331
  const getChildNodes = (
290
- node: DependencyTreeNodeData,
291
- ): DependencyTreeNodeData[] => {
332
+ node: ProjectDependencyTreeNodeData,
333
+ ): ProjectDependencyTreeNodeData[] => {
292
334
  if (!node.childrenIds || node.childrenIds.length === 0) {
293
335
  return [];
294
336
  }
@@ -312,102 +354,149 @@ const DependencyTreeView: React.FC<{
312
354
  );
313
355
  };
314
356
 
315
- const ProjectDependencyExplorer = observer(
316
- (props: { dependencyEditorState: ProjectDependencyEditorState }) => {
317
- const { dependencyEditorState } = props;
318
- const closeModal = (): void =>
319
- dependencyEditorState.setDependencyTreeReportModal(false);
320
- const [viewAsTree, setViewAsTree] = useState(true);
321
- const setTreeData = (treeData: TreeData<DependencyTreeNodeData>): void => {
322
- if (viewAsTree) {
323
- dependencyEditorState.setDependencyTreeData(treeData);
324
- } else {
325
- dependencyEditorState.setFlattenDependencyTreeData(treeData);
326
- }
327
- };
328
- const toggleViewAsListOrAsTree = (): void => {
329
- setViewAsTree(!viewAsTree);
330
- };
331
- const treeData = viewAsTree
332
- ? dependencyEditorState.dependencyTreeData
333
- : dependencyEditorState.flattenDependencyTreeData;
334
- const collapseTree = (): void => {
335
- if (treeData) {
336
- Array.from(treeData.nodes.values()).forEach((node) => {
337
- node.isOpen = false;
338
- });
339
- }
340
- };
341
- return (
342
- <Dialog
343
- open={Boolean(dependencyEditorState.dependencyTreeReportModal)}
344
- onClose={closeModal}
345
- classes={{
346
- root: 'editor-modal__root-container',
347
- container: 'editor-modal__container',
348
- paper: 'editor-modal__content',
357
+ const ConflictTreeNodeContainer: React.FC<
358
+ TreeNodeContainerProps<
359
+ ProjectDependencyConflictTreeNodeData,
360
+ {
361
+ onNodeExpand: (node: ProjectDependencyConflictTreeNodeData) => void;
362
+ }
363
+ >
364
+ > = (props) => {
365
+ const { node, level, stepPaddingInRem, onNodeSelect } = props;
366
+ const isExpandable = Boolean(node.childrenIds?.length);
367
+ const selectNode = (): void => onNodeSelect?.(node);
368
+ const nodeExpandIcon = isExpandable ? (
369
+ node.isOpen ? (
370
+ <ChevronDownIcon />
371
+ ) : (
372
+ <ChevronRightIcon />
373
+ )
374
+ ) : (
375
+ <div />
376
+ );
377
+ return (
378
+ <ContextMenu
379
+ content={<DependencyTreeNodeContextMenu node={node} />}
380
+ menuProps={{ elevation: 7 }}
381
+ >
382
+ <div
383
+ className={clsx(
384
+ 'tree-view__node__container project-dependency-explorer-tree__node__container',
385
+ {
386
+ 'menu__trigger--on-menu-open': !node.isSelected,
387
+ },
388
+ {
389
+ 'project-dependency-explorer-tree__node__container--selected':
390
+ node.isSelected,
391
+ },
392
+ )}
393
+ style={{
394
+ paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1)}rem`,
349
395
  }}
396
+ onClick={selectNode}
350
397
  >
351
- <Modal darkMode={true} className="editor-modal">
352
- <ModalHeader title="Dependency Explorer" />
353
- <ModalBody>
354
- <div className="panel project-dependency-explorer">
355
- <div className="panel__header">
356
- <div className="panel__header__title">
357
- <div className="panel__header__title__label">explorer</div>
358
- </div>
359
- <div className="panel__header__actions">
360
- <button
361
- className="panel__header__action"
362
- onClick={collapseTree}
363
- tabIndex={-1}
364
- >
365
- {viewAsTree && <CompressIcon title="Collapse Tree" />}
366
- </button>
367
- <div className="panel__header__action query-builder__functions-explorer__custom-icon">
368
- {!viewAsTree ? (
369
- <SubjectIcon
370
- title="View as Tree"
371
- onClick={toggleViewAsListOrAsTree}
372
- />
373
- ) : (
374
- <ViewHeadlineIcon
375
- title="View as Flatten List"
376
- onClick={toggleViewAsListOrAsTree}
377
- />
378
- )}
379
- </div>
380
- </div>
381
- </div>
382
- <div className="project-dependency-explorer__content">
383
- {treeData && (
384
- <DependencyTreeView
385
- configState={dependencyEditorState}
386
- treeData={treeData}
387
- setTreeData={setTreeData}
388
- />
389
- )}
390
- </div>
398
+ <div
399
+ className={clsx(
400
+ 'tree-view__node__icon project-dependency-explorer-tree__node__icon',
401
+ {
402
+ 'tree-view__node__icon project-dependency-explorer-tree__node__icon__with__type':
403
+ node instanceof ConflictTreeNodeData ||
404
+ node instanceof ConflictVersionNodeData,
405
+ },
406
+ )}
407
+ >
408
+ <div className="project-dependency-explorer-tree__node__icon__expand">
409
+ {nodeExpandIcon}
410
+ </div>
411
+ {node instanceof ConflictTreeNodeData && (
412
+ <div className="project-dependency-explorer-tree__node__icon__type">
413
+ <RepoIcon />
391
414
  </div>
392
- </ModalBody>
393
- <ModalFooter>
415
+ )}
416
+ {node instanceof ConflictVersionNodeData && (
417
+ <div className="project-dependency-explorer-tree__node__icon__type">
418
+ <VersionsIcon />
419
+ </div>
420
+ )}
421
+ </div>
422
+ <button
423
+ className="tree-view__node__label project-dependency-explorer-tree__node__label"
424
+ tabIndex={-1}
425
+ title={node.description}
426
+ >
427
+ {node.label}
428
+ </button>
429
+ {node instanceof ProjectDependencyTreeNodeData && (
430
+ <div className="project-dependency-explorer-tree__node__version">
394
431
  <button
395
- className="btn modal__footer__close-btn"
396
- onClick={closeModal}
432
+ className="project-dependency-explorer-tree__node__version-btn"
433
+ title={node.value.versionId}
434
+ tabIndex={-1}
397
435
  >
398
- Close
436
+ {node.value.versionId}
399
437
  </button>
400
- </ModalFooter>
401
- </Modal>
402
- </Dialog>
403
- );
404
- },
405
- );
438
+ </div>
439
+ )}
440
+ </div>
441
+ </ContextMenu>
442
+ );
443
+ };
444
+
445
+ const ConflictDependencyTreeView: React.FC<{
446
+ treeData: TreeData<ProjectDependencyConflictTreeNodeData>;
447
+ setTreeData: (
448
+ treeData: TreeData<ProjectDependencyConflictTreeNodeData>,
449
+ ) => void;
450
+ }> = (props) => {
451
+ const { treeData, setTreeData } = props;
452
+ const onNodeExpand = (node: ProjectDependencyConflictTreeNodeData): void => {
453
+ if (node.childrenIds?.length) {
454
+ node.isOpen = !node.isOpen;
455
+ }
456
+ setTreeData({ ...treeData });
457
+ };
458
+ const onNodeSelect = (node: ProjectDependencyConflictTreeNodeData): void => {
459
+ onNodeExpand(node);
460
+ setTreeData({ ...treeData });
461
+ };
462
+ const getChildNodes = (
463
+ node: ProjectDependencyConflictTreeNodeData,
464
+ ): ProjectDependencyConflictTreeNodeData[] => {
465
+ if (!node.childrenIds || node.childrenIds.length === 0) {
466
+ return [];
467
+ }
468
+ const childrenNodes = node.childrenIds
469
+ .map((id) => treeData.nodes.get(id))
470
+ .filter(isNonNullable);
471
+ return childrenNodes;
472
+ };
473
+ return (
474
+ <TreeView
475
+ components={{
476
+ TreeNodeContainer: ConflictTreeNodeContainer,
477
+ }}
478
+ treeData={treeData}
479
+ getChildNodes={getChildNodes}
480
+ onNodeSelect={onNodeSelect}
481
+ innerProps={{
482
+ onNodeExpand,
483
+ }}
484
+ />
485
+ );
486
+ };
487
+
488
+ const collapseTreeData = (
489
+ treeData: TreeData<ProjectDependencyTreeNodeData>,
490
+ ): void => {
491
+ Array.from(treeData.nodes.values()).forEach((node) => {
492
+ node.isOpen = false;
493
+ });
494
+ };
406
495
 
407
496
  export const getConflictsString = (
408
497
  report: ProjectDependencyGraphReport,
409
498
  ): string =>
410
- Array.from(report.conflictPaths.entries())
499
+ Array.from(report.conflictInfo.entries())
411
500
  .map(([k, conflictVersionPaths]) => {
412
501
  const base = `project:\n${
413
502
  ' '.repeat(TAB_SIZE) +
@@ -415,8 +504,8 @@ export const getConflictsString = (
415
504
  }`;
416
505
  const versionConflictString = conflictVersionPaths
417
506
  .map((conflictVersion) => {
418
- const versions = `version: ${conflictVersion.versionNode.versionId}\n`;
419
- const paths = `paths:\n${conflictVersion.paths
507
+ const versions = `version: ${conflictVersion.version.versionId}\n`;
508
+ const paths = `paths:\n${conflictVersion.pathsToVersion
420
509
  .map(
421
510
  (p, idx) =>
422
511
  `${' '.repeat(TAB_SIZE) + (idx + 1)}:\n${p
@@ -432,15 +521,115 @@ export const getConflictsString = (
432
521
  })
433
522
  .join('\n\n');
434
523
 
435
- const ProjectDependencyConflictModal = observer(
436
- (props: { dependencyEditorState: ProjectDependencyEditorState }) => {
524
+ const ProjectDependencyConflictViewer = observer(
525
+ (props: {
526
+ dependencyEditorState: ProjectDependencyEditorState;
527
+ report: ProjectDependencyGraphReport;
528
+ }) => {
529
+ const { report, dependencyEditorState } = props;
530
+ const hasConflict = Boolean(report.conflicts.length);
531
+ const collapseTree = (): void => {
532
+ dependencyEditorState.conflictStates.forEach((c) => {
533
+ const treeData = c.treeData;
534
+ Array.from(treeData.nodes.values()).forEach((n) => (n.isOpen = false));
535
+ c.setTreeData({ ...treeData });
536
+ });
537
+ };
538
+ const expandAllNodes = (): void => {
539
+ dependencyEditorState.expandAllConflicts();
540
+ };
541
+ return (
542
+ <div className="panel project-dependency-explorer">
543
+ <div className="panel__header">
544
+ <div className="panel__header__title">
545
+ <div className="panel__header__title__label">conflicts</div>
546
+ </div>
547
+ <div className="panel__header__actions">
548
+ <button
549
+ className="panel__header__action"
550
+ disabled={!hasConflict}
551
+ onClick={collapseTree}
552
+ tabIndex={-1}
553
+ >
554
+ <CompressIcon title="Collapse Tree" />
555
+ </button>
556
+ <button
557
+ className="panel__header__action"
558
+ disabled={!hasConflict}
559
+ onClick={expandAllNodes}
560
+ tabIndex={-1}
561
+ >
562
+ <ExpandAllIcon title="Expand All Conflict Paths" />
563
+ </button>
564
+ </div>
565
+ </div>
566
+ <div className="project-dependency-explorer__content">
567
+ {hasConflict && (
568
+ <div>
569
+ {dependencyEditorState.conflictStates.map((c) => (
570
+ <ConflictDependencyTreeView
571
+ key={c.uuid}
572
+ treeData={c.treeData}
573
+ setTreeData={(
574
+ treeData: TreeData<ProjectDependencyConflictTreeNodeData>,
575
+ ) => c.setTreeData(treeData)}
576
+ />
577
+ ))}
578
+ </div>
579
+ )}
580
+ {!hasConflict && <BlankPanelContent>No Conflicts</BlankPanelContent>}
581
+ </div>
582
+ </div>
583
+ );
584
+ },
585
+ );
586
+
587
+ const ProjectDependencyReportModal = observer(
588
+ (props: {
589
+ dependencyEditorState: ProjectDependencyEditorState;
590
+ tab: DEPENDENCY_REPORT_TAB;
591
+ }) => {
437
592
  const { dependencyEditorState } = props;
438
- const report = dependencyEditorState.dependencyReport;
593
+ const reportTab = dependencyEditorState.reportTab;
594
+ const tabs = Object.values(DEPENDENCY_REPORT_TAB);
595
+ const changeTab =
596
+ (tab: DEPENDENCY_REPORT_TAB): (() => void) =>
597
+ (): void =>
598
+ dependencyEditorState.setDependencyReport(tab);
599
+ const dependencyReport = dependencyEditorState.dependencyReport;
439
600
  const closeModal = (): void =>
440
- dependencyEditorState.setDependencyConflictModal(false);
601
+ dependencyEditorState.setDependencyReport(undefined);
602
+ const [flattenView, setFlattenView] = useState(false);
603
+ const [isExpandingDependencies, setIsExpandingDependencies] =
604
+ useState(false);
605
+ const setTreeData = (
606
+ treeData: TreeData<ProjectDependencyTreeNodeData>,
607
+ ): void => {
608
+ dependencyEditorState.setTreeData(treeData, flattenView);
609
+ };
610
+ const toggleViewAsListOrAsTree = (): void => {
611
+ setFlattenView(!flattenView);
612
+ };
613
+ const treeData = flattenView
614
+ ? dependencyEditorState.flattenDependencyTreeData
615
+ : dependencyEditorState.dependencyTreeData;
616
+ const collapseTree = (): void => {
617
+ if (treeData) {
618
+ collapseTreeData(treeData);
619
+ setTreeData({ ...treeData });
620
+ }
621
+ };
622
+ const openAllDependencyNodes = (): void => {
623
+ if (treeData && dependencyReport) {
624
+ setIsExpandingDependencies(true);
625
+ openAllDependencyNodesInTree(treeData, dependencyReport.graph);
626
+ setTreeData({ ...treeData });
627
+ setIsExpandingDependencies(false);
628
+ }
629
+ };
441
630
  return (
442
631
  <Dialog
443
- open={Boolean(dependencyEditorState.dependencyConflictModal)}
632
+ open={Boolean(dependencyEditorState.reportTab)}
444
633
  onClose={closeModal}
445
634
  classes={{
446
635
  root: 'editor-modal__root-container',
@@ -449,16 +638,95 @@ const ProjectDependencyConflictModal = observer(
449
638
  }}
450
639
  >
451
640
  <Modal darkMode={true} className="editor-modal">
452
- <ModalHeader title="Conflict Viewer" />
641
+ <ModalHeader title="Dependency Explorer" />
642
+
453
643
  <ModalBody>
454
- {report && (
455
- <TextInputEditor
456
- inputValue={getConflictsString(report)}
457
- isReadOnly={true}
458
- language={EDITOR_LANGUAGE.TEXT}
459
- showMiniMap={true}
644
+ <div className="panel project-dependency-report">
645
+ <PanelLoadingIndicator
646
+ isLoading={Boolean(
647
+ isExpandingDependencies ||
648
+ dependencyEditorState.expandConflictsState.isInProgress,
649
+ )}
460
650
  />
461
- )}
651
+
652
+ <div className="panel__header project-dependency-report__tabs__header">
653
+ <div className="project-dependency-report__tabs">
654
+ {tabs.map((tab) => (
655
+ <button
656
+ key={tab}
657
+ onClick={changeTab(tab)}
658
+ className={clsx('project-dependency-report__tab', {
659
+ 'project-dependency-report__tab--active':
660
+ tab === reportTab,
661
+ })}
662
+ >
663
+ {prettyCONSTName(tab)}
664
+ </button>
665
+ ))}
666
+ </div>
667
+ </div>
668
+ {reportTab === DEPENDENCY_REPORT_TAB.EXPLORER && (
669
+ <div className="panel project-dependency-explorer">
670
+ <div className="panel__header">
671
+ <div className="panel__header__title">
672
+ <div className="panel__header__title__label">
673
+ explorer
674
+ </div>
675
+ </div>
676
+ <div className="panel__header__actions">
677
+ {!flattenView && (
678
+ <>
679
+ <button
680
+ className="panel__header__action"
681
+ disabled={!treeData}
682
+ onClick={collapseTree}
683
+ tabIndex={-1}
684
+ >
685
+ <CompressIcon title="Collapse Tree" />
686
+ </button>
687
+ <button
688
+ className="panel__header__action"
689
+ disabled={!treeData || !dependencyReport}
690
+ onClick={openAllDependencyNodes}
691
+ tabIndex={-1}
692
+ >
693
+ <ExpandAllIcon title="Expand All Dependencies" />
694
+ </button>
695
+ </>
696
+ )}
697
+ <div className="panel__header__action query-builder__functions-explorer__custom-icon">
698
+ {flattenView ? (
699
+ <SubjectIcon
700
+ title="View as Tree"
701
+ onClick={toggleViewAsListOrAsTree}
702
+ />
703
+ ) : (
704
+ <ViewHeadlineIcon
705
+ title="View as Flatten List"
706
+ onClick={toggleViewAsListOrAsTree}
707
+ />
708
+ )}
709
+ </div>
710
+ </div>
711
+ </div>
712
+ <div className="project-dependency-explorer__content">
713
+ {treeData && (
714
+ <DependencyTreeView
715
+ treeData={treeData}
716
+ setTreeData={setTreeData}
717
+ />
718
+ )}
719
+ </div>
720
+ </div>
721
+ )}
722
+ {reportTab === DEPENDENCY_REPORT_TAB.CONFLICTS &&
723
+ dependencyReport && (
724
+ <ProjectDependencyConflictViewer
725
+ report={dependencyReport}
726
+ dependencyEditorState={dependencyEditorState}
727
+ />
728
+ )}
729
+ </div>
462
730
  </ModalBody>
463
731
  <ModalFooter>
464
732
  <button
@@ -716,19 +984,12 @@ export const ProjectDependencyEditor = observer(() => {
716
984
  />
717
985
  ),
718
986
  )}
719
- {dependencyEditorState.dependencyReport &&
720
- dependencyEditorState.dependencyTreeData &&
721
- dependencyEditorState.dependencyTreeReportModal && (
722
- <ProjectDependencyExplorer
723
- dependencyEditorState={dependencyEditorState}
724
- />
725
- )}
726
- {dependencyEditorState.dependencyConflictModal &&
727
- dependencyEditorState.dependencyReport?.conflictPaths.size && (
728
- <ProjectDependencyConflictModal
729
- dependencyEditorState={dependencyEditorState}
730
- />
731
- )}
987
+ {dependencyEditorState.reportTab && (
988
+ <ProjectDependencyReportModal
989
+ tab={dependencyEditorState.reportTab}
990
+ dependencyEditorState={dependencyEditorState}
991
+ />
992
+ )}
732
993
  </div>
733
994
  );
734
995
  });