@finos/legend-application-studio 28.13.13 → 28.13.14

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 (79) hide show
  1. package/lib/__lib__/LegendStudioEvent.d.ts +3 -0
  2. package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioEvent.js +4 -2
  4. package/lib/__lib__/LegendStudioEvent.js.map +1 -1
  5. package/lib/__lib__/LegendStudioNavigation.d.ts +7 -0
  6. package/lib/__lib__/LegendStudioNavigation.d.ts.map +1 -1
  7. package/lib/__lib__/LegendStudioNavigation.js +2 -0
  8. package/lib/__lib__/LegendStudioNavigation.js.map +1 -1
  9. package/lib/__lib__/LegendStudioTelemetryHelper.d.ts +10 -0
  10. package/lib/__lib__/LegendStudioTelemetryHelper.d.ts.map +1 -1
  11. package/lib/__lib__/LegendStudioTelemetryHelper.js +10 -0
  12. package/lib/__lib__/LegendStudioTelemetryHelper.js.map +1 -1
  13. package/lib/components/LegendStudioWebApplication.d.ts.map +1 -1
  14. package/lib/components/LegendStudioWebApplication.js +7 -1
  15. package/lib/components/LegendStudioWebApplication.js.map +1 -1
  16. package/lib/components/editor/ActivityBar.d.ts.map +1 -1
  17. package/lib/components/editor/ActivityBar.js +23 -14
  18. package/lib/components/editor/ActivityBar.js.map +1 -1
  19. package/lib/components/editor/editor-group/GrammarTextEditor.d.ts.map +1 -1
  20. package/lib/components/editor/editor-group/GrammarTextEditor.js +3 -2
  21. package/lib/components/editor/editor-group/GrammarTextEditor.js.map +1 -1
  22. package/lib/components/lazy-text-editor/LazyTextEditor.d.ts +18 -0
  23. package/lib/components/lazy-text-editor/LazyTextEditor.d.ts.map +1 -0
  24. package/lib/components/lazy-text-editor/LazyTextEditor.js +170 -0
  25. package/lib/components/lazy-text-editor/LazyTextEditor.js.map +1 -0
  26. package/lib/components/workspace-setup/WorkspaceSetup.js +6 -6
  27. package/lib/components/workspace-setup/WorkspaceSetup.js.map +1 -1
  28. package/lib/index.css +2 -2
  29. package/lib/index.css.map +1 -1
  30. package/lib/package.json +1 -1
  31. package/lib/stores/ShowcaseManagerState.d.ts +3 -1
  32. package/lib/stores/ShowcaseManagerState.d.ts.map +1 -1
  33. package/lib/stores/ShowcaseManagerState.js +29 -8
  34. package/lib/stores/ShowcaseManagerState.js.map +1 -1
  35. package/lib/stores/editor/EditorConfig.d.ts +2 -1
  36. package/lib/stores/editor/EditorConfig.d.ts.map +1 -1
  37. package/lib/stores/editor/EditorConfig.js +1 -0
  38. package/lib/stores/editor/EditorConfig.js.map +1 -1
  39. package/lib/stores/editor/EditorGraphState.d.ts +1 -0
  40. package/lib/stores/editor/EditorGraphState.d.ts.map +1 -1
  41. package/lib/stores/editor/EditorGraphState.js +17 -0
  42. package/lib/stores/editor/EditorGraphState.js.map +1 -1
  43. package/lib/stores/editor/EditorStore.d.ts +4 -0
  44. package/lib/stores/editor/EditorStore.d.ts.map +1 -1
  45. package/lib/stores/editor/EditorStore.js +62 -5
  46. package/lib/stores/editor/EditorStore.js.map +1 -1
  47. package/lib/stores/editor/GraphEditGrammarModeState.d.ts +6 -1
  48. package/lib/stores/editor/GraphEditGrammarModeState.d.ts.map +1 -1
  49. package/lib/stores/editor/GraphEditGrammarModeState.js +6 -1
  50. package/lib/stores/editor/GraphEditGrammarModeState.js.map +1 -1
  51. package/lib/stores/editor/GraphEditorMode.d.ts +6 -1
  52. package/lib/stores/editor/GraphEditorMode.d.ts.map +1 -1
  53. package/lib/stores/editor/GraphEditorMode.js +3 -0
  54. package/lib/stores/editor/GraphEditorMode.js.map +1 -1
  55. package/lib/stores/lazy-text-editor/LazyTextEditorStore.d.ts +30 -0
  56. package/lib/stores/lazy-text-editor/LazyTextEditorStore.d.ts.map +1 -0
  57. package/lib/stores/lazy-text-editor/LazyTextEditorStore.js +66 -0
  58. package/lib/stores/lazy-text-editor/LazyTextEditorStore.js.map +1 -0
  59. package/lib/stores/showcase/ShowcaseViewerStore.d.ts.map +1 -1
  60. package/lib/stores/showcase/ShowcaseViewerStore.js +3 -0
  61. package/lib/stores/showcase/ShowcaseViewerStore.js.map +1 -1
  62. package/package.json +6 -6
  63. package/src/__lib__/LegendStudioEvent.ts +4 -2
  64. package/src/__lib__/LegendStudioNavigation.ts +8 -0
  65. package/src/__lib__/LegendStudioTelemetryHelper.ts +32 -0
  66. package/src/components/LegendStudioWebApplication.tsx +13 -1
  67. package/src/components/editor/ActivityBar.tsx +118 -111
  68. package/src/components/editor/editor-group/GrammarTextEditor.tsx +6 -3
  69. package/src/components/lazy-text-editor/LazyTextEditor.tsx +458 -0
  70. package/src/components/workspace-setup/WorkspaceSetup.tsx +6 -6
  71. package/src/stores/ShowcaseManagerState.ts +41 -11
  72. package/src/stores/editor/EditorConfig.ts +1 -0
  73. package/src/stores/editor/EditorGraphState.ts +25 -0
  74. package/src/stores/editor/EditorStore.ts +108 -7
  75. package/src/stores/editor/GraphEditGrammarModeState.ts +14 -2
  76. package/src/stores/editor/GraphEditorMode.ts +9 -1
  77. package/src/stores/lazy-text-editor/LazyTextEditorStore.ts +99 -0
  78. package/src/stores/showcase/ShowcaseViewerStore.ts +6 -0
  79. package/tsconfig.json +2 -0
@@ -0,0 +1,458 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { useEffect } from 'react';
18
+ import { observer } from 'mobx-react-lite';
19
+ import {
20
+ type ResizablePanelHandlerProps,
21
+ getCollapsiblePanelGroupProps,
22
+ ResizablePanel,
23
+ ResizablePanelGroup,
24
+ ResizablePanelSplitter,
25
+ useResizeDetector,
26
+ ResizablePanelSplitterLine,
27
+ clsx,
28
+ CodeBranchIcon,
29
+ ErrorIcon,
30
+ WarningIcon,
31
+ CloudUploadIcon,
32
+ TerminalIcon,
33
+ AssistantIcon,
34
+ HammerIcon,
35
+ } from '@finos/legend-art';
36
+ import {
37
+ generateSetupRoute,
38
+ type WorkspaceEditorPathParams,
39
+ } from '../../__lib__/LegendStudioNavigation.js';
40
+ import { guaranteeNonNullable } from '@finos/legend-shared';
41
+ import { flowResult } from 'mobx';
42
+ import {
43
+ useApplicationStore,
44
+ useApplicationNavigationContext,
45
+ useCommands,
46
+ } from '@finos/legend-application';
47
+ import { useParams } from '@finos/legend-application/browser';
48
+ import { WorkspaceType } from '@finos/legend-server-sdlc';
49
+ import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../__lib__/LegendStudioApplicationNavigationContext.js';
50
+ import {
51
+ useEditorStore,
52
+ withEditorStore,
53
+ } from '../editor/EditorStoreProvider.js';
54
+ import { ActivityBar } from '../editor/ActivityBar.js';
55
+ import { SideBar } from '../editor/side-bar/SideBar.js';
56
+ import { GrammarTextEditor } from '../editor/editor-group/GrammarTextEditor.js';
57
+ import { PanelGroup } from '../editor/panel-group/PanelGroup.js';
58
+ import {
59
+ ACTIVITY_MODE,
60
+ GRAPH_EDITOR_MODE,
61
+ PANEL_MODE,
62
+ } from '../../stores/editor/EditorConfig.js';
63
+ import { QuickInput } from '../editor/QuickInput.js';
64
+ import { useLegendStudioApplicationStore } from '../LegendStudioFrameworkProvider.js';
65
+ import { LEGEND_STUDIO_TEST_ID } from '../../__lib__/LegendStudioTesting.js';
66
+
67
+ const LazyStatusBar = observer((props: { actionsDisabled: boolean }) => {
68
+ const { actionsDisabled } = props;
69
+ const params = useParams<WorkspaceEditorPathParams>();
70
+ const editorStore = useEditorStore();
71
+ const applicationStore = useLegendStudioApplicationStore();
72
+ const isInConflictResolutionMode = editorStore.isInConflictResolutionMode;
73
+ // SDLC
74
+ const projectId = params.projectId;
75
+ const workspaceType = params.groupWorkspaceId
76
+ ? WorkspaceType.GROUP
77
+ : WorkspaceType.USER;
78
+ const patchReleaseVersionId = params.patchReleaseVersionId
79
+ ? `patch / ${params.patchReleaseVersionId} / `
80
+ : '';
81
+ const workspaceId = guaranteeNonNullable(
82
+ params.groupWorkspaceId ?? params.workspaceId,
83
+ `Workspace/group workspace ID is not provided`,
84
+ );
85
+ const currentProject = editorStore.sdlcState.currentProject;
86
+ const goToWorkspaceUpdater = (): void =>
87
+ editorStore.setActiveActivity(
88
+ isInConflictResolutionMode
89
+ ? ACTIVITY_MODE.CONFLICT_RESOLUTION
90
+ : ACTIVITY_MODE.WORKSPACE_UPDATER,
91
+ );
92
+
93
+ const goToLocalChanges = (): void =>
94
+ editorStore.setActiveActivity(ACTIVITY_MODE.LOCAL_CHANGES);
95
+ // Change Detection
96
+ const changes =
97
+ editorStore.changeDetectionState.workspaceLocalLatestRevisionState.changes
98
+ .length;
99
+
100
+ const configurationState = editorStore.projectConfigurationEditorState;
101
+ const pushLocalChanges = applicationStore.guardUnhandledError(() =>
102
+ flowResult(editorStore.localChangesState.pushLocalChanges()),
103
+ );
104
+ // TODO: we probably should refactor this, these messages are not that helpful and
105
+ // meant for different purposes
106
+ const pushStatusText =
107
+ editorStore.graphManagerState.graphBuildState.hasFailed ||
108
+ editorStore.changeDetectionState.initState.hasFailed
109
+ ? 'change detection halted'
110
+ : !editorStore.changeDetectionState.initState.hasSucceeded
111
+ ? editorStore.changeDetectionState.workspaceLocalLatestRevisionState
112
+ .isBuildingEntityHashesIndex
113
+ ? 'building indexes...'
114
+ : 'starting change detection...'
115
+ : editorStore.localChangesState.pushChangesState.isInProgress
116
+ ? 'pushing local changes...'
117
+ : configurationState.updatingConfigurationState.isInProgress
118
+ ? 'updating configuration...'
119
+ : changes
120
+ ? `${changes} unpushed changes`
121
+ : 'no changes detected';
122
+ const workspaceOutOfSync =
123
+ !actionsDisabled && editorStore.sdlcState.isWorkspaceOutOfSync;
124
+
125
+ // Problems
126
+ const error = editorStore.graphState.error;
127
+ const warnings = editorStore.graphState.warnings;
128
+
129
+ // Other actions
130
+ const togglePanel = (): void => editorStore.panelGroupDisplayState.toggle();
131
+
132
+ const showCompilationWarnings = (): void => {
133
+ editorStore.panelGroupDisplayState.open();
134
+ editorStore.setActivePanelMode(PANEL_MODE.PROBLEMS);
135
+ };
136
+ const compile = applicationStore.guardUnhandledError(() =>
137
+ flowResult(editorStore.graphEditorMode.globalCompile()),
138
+ );
139
+ const toggleAssistant = (): void =>
140
+ applicationStore.assistantService.toggleAssistant();
141
+
142
+ return (
143
+ <div
144
+ data-testid={LEGEND_STUDIO_TEST_ID.STATUS_BAR}
145
+ className={clsx('editor__status-bar', 'lazy-text-editor__status-bar')}
146
+ >
147
+ <div className="editor__status-bar__left">
148
+ <div className="editor__status-bar__workspace">
149
+ <div className="editor__status-bar__workspace__icon">
150
+ <CodeBranchIcon />
151
+ </div>
152
+ <button
153
+ className="editor__status-bar__workspace__project"
154
+ title="Go back to workspace setup using the specified project"
155
+ tabIndex={-1}
156
+ onClick={(): void =>
157
+ applicationStore.navigationService.navigator.visitAddress(
158
+ applicationStore.navigationService.navigator.generateAddress(
159
+ generateSetupRoute(projectId, undefined),
160
+ ),
161
+ )
162
+ }
163
+ >
164
+ {currentProject?.name ?? 'unknown'}
165
+ </button>
166
+ /
167
+ <button
168
+ className="editor__status-bar__workspace__workspace"
169
+ title="Go back to workspace setup using the specified workspace"
170
+ tabIndex={-1}
171
+ onClick={(): void =>
172
+ applicationStore.navigationService.navigator.visitAddress(
173
+ applicationStore.navigationService.navigator.generateAddress(
174
+ generateSetupRoute(projectId, workspaceId, workspaceType),
175
+ ),
176
+ )
177
+ }
178
+ >
179
+ {patchReleaseVersionId}
180
+ {workspaceId}
181
+ {editorStore.localChangesState.hasUnpushedChanges ? '*' : ''}
182
+ </button>
183
+ {workspaceOutOfSync && (
184
+ <button
185
+ className="editor__status-bar__workspace__status__btn"
186
+ tabIndex={-1}
187
+ onClick={goToLocalChanges}
188
+ title={
189
+ 'Local workspace is out-of-sync. Click to see incoming changes to your workspace.'
190
+ }
191
+ >
192
+ OUT-OF-SYNC
193
+ </button>
194
+ )}
195
+ {editorStore.sdlcState.isWorkspaceOutdated && !workspaceOutOfSync && (
196
+ <button
197
+ className="editor__status-bar__workspace__status__btn"
198
+ tabIndex={-1}
199
+ onClick={goToWorkspaceUpdater}
200
+ title={
201
+ 'Workspace is outdated. Click to see latest changes of the project'
202
+ }
203
+ >
204
+ OUTDATED
205
+ </button>
206
+ )}
207
+ <button
208
+ className="editor__status-bar__problems"
209
+ tabIndex={-1}
210
+ onClick={showCompilationWarnings}
211
+ title={`${error ? 'Error: 1, ' : ''}Warnings: ${warnings.length}`}
212
+ >
213
+ <div className="editor__status-bar__problems__icon">
214
+ <ErrorIcon />
215
+ </div>
216
+ <div className="editor__status-bar__problems__counter">
217
+ {error ? 1 : 0}
218
+ </div>
219
+ <div className="editor__status-bar__problems__icon">
220
+ <WarningIcon />
221
+ </div>
222
+ <div className="editor__status-bar__problems__counter">
223
+ {warnings.length}
224
+ </div>
225
+ </button>
226
+ </div>
227
+ </div>
228
+ <div
229
+ data-testid={LEGEND_STUDIO_TEST_ID.EDITOR__STATUS_BAR__RIGHT}
230
+ className="editor__status-bar__right"
231
+ >
232
+ {!isInConflictResolutionMode && (
233
+ <div className="editor__status-bar__workspace-sync">
234
+ <div className="editor__status-bar__workspace-sync__status">
235
+ {pushStatusText}
236
+ </div>
237
+ <button
238
+ className={clsx('editor__status-bar__push-changes__btn', {
239
+ 'editor__status-bar__push-changes__btn--loading':
240
+ editorStore.localChangesState.pushChangesState.isInProgress ||
241
+ configurationState.updatingConfigurationState.isInProgress,
242
+ })}
243
+ onClick={pushLocalChanges}
244
+ disabled={
245
+ !changes ||
246
+ configurationState.updatingConfigurationState.isInProgress ||
247
+ editorStore.localChangesState.pushChangesState.isInProgress ||
248
+ editorStore.changeDetectionState
249
+ .workspaceLocalLatestRevisionState
250
+ .isBuildingEntityHashesIndex ||
251
+ actionsDisabled
252
+ }
253
+ tabIndex={-1}
254
+ title="Push local changes (Ctrl + S)"
255
+ >
256
+ <CloudUploadIcon />
257
+ </button>
258
+ </div>
259
+ )}
260
+ <button
261
+ className={clsx(
262
+ 'editor__status-bar__action editor__status-bar__compile-btn',
263
+ {
264
+ 'editor__status-bar__compile-btn--wiggling':
265
+ editorStore.graphState.isRunningGlobalCompile,
266
+ },
267
+ )}
268
+ disabled={
269
+ editorStore.graphState.isApplicationUpdateOperationIsRunning ||
270
+ actionsDisabled
271
+ }
272
+ onClick={compile}
273
+ tabIndex={-1}
274
+ title="Compile (F9)"
275
+ >
276
+ <HammerIcon />
277
+ </button>
278
+ <button
279
+ className={clsx(
280
+ 'editor__status-bar__action editor__status-bar__action__toggler',
281
+ {
282
+ 'editor__status-bar__action__toggler--active':
283
+ editorStore.panelGroupDisplayState.isOpen,
284
+ },
285
+ )}
286
+ onClick={togglePanel}
287
+ tabIndex={-1}
288
+ title="Toggle panel (Ctrl + `)"
289
+ >
290
+ <TerminalIcon />
291
+ </button>
292
+ <button
293
+ className={clsx(
294
+ 'editor__status-bar__action editor__status-bar__action__toggler',
295
+ {
296
+ 'editor__status-bar__action__toggler--active':
297
+ !applicationStore.assistantService.isHidden,
298
+ },
299
+ )}
300
+ onClick={toggleAssistant}
301
+ tabIndex={-1}
302
+ title="Toggle assistant"
303
+ >
304
+ <AssistantIcon />
305
+ </button>
306
+ </div>
307
+ </div>
308
+ );
309
+ });
310
+
311
+ export const LazyTextEditor = withEditorStore(
312
+ observer(() => {
313
+ const params = useParams<WorkspaceEditorPathParams>();
314
+ const projectId = params.projectId;
315
+ const patchReleaseVersionId = params.patchReleaseVersionId;
316
+ const workspaceType = params.groupWorkspaceId
317
+ ? WorkspaceType.GROUP
318
+ : WorkspaceType.USER;
319
+ const workspaceId = guaranteeNonNullable(
320
+ params.groupWorkspaceId ?? params.workspaceId,
321
+ `Workspace/group workspace ID is not provided`,
322
+ );
323
+ const editorStore = useEditorStore();
324
+ const applicationStore = useApplicationStore();
325
+ const editable =
326
+ editorStore.graphManagerState.graphBuildState.hasCompleted &&
327
+ editorStore.isInitialized;
328
+
329
+ // layout
330
+ const { ref, width, height } = useResizeDetector<HTMLDivElement>();
331
+ // These create snapping effect on panel resizing
332
+ const resizeSideBar = (handleProps: ResizablePanelHandlerProps): void =>
333
+ editorStore.sideBarDisplayState.setSize(
334
+ (handleProps.domElement as HTMLDivElement).getBoundingClientRect()
335
+ .width,
336
+ );
337
+ const resizePanel = (handleProps: ResizablePanelHandlerProps): void =>
338
+ editorStore.panelGroupDisplayState.setSize(
339
+ (handleProps.domElement as HTMLDivElement).getBoundingClientRect()
340
+ .height,
341
+ );
342
+ const collapsibleSideBarGroupProps = getCollapsiblePanelGroupProps(
343
+ editorStore.sideBarDisplayState.size === 0,
344
+ {
345
+ onStopResize: resizeSideBar,
346
+ size: editorStore.sideBarDisplayState.size,
347
+ },
348
+ );
349
+ const collapsiblePanelGroupProps = getCollapsiblePanelGroupProps(
350
+ editorStore.panelGroupDisplayState.size === 0,
351
+ {
352
+ onStopResize: resizePanel,
353
+ size: editorStore.panelGroupDisplayState.size,
354
+ },
355
+ );
356
+ const maximizedCollapsiblePanelGroupProps = getCollapsiblePanelGroupProps(
357
+ editorStore.panelGroupDisplayState.isMaximized,
358
+ );
359
+ // Extensions
360
+ useEffect(() => {
361
+ if (ref.current) {
362
+ editorStore.panelGroupDisplayState.setMaxSize(ref.current.offsetHeight);
363
+ }
364
+ }, [editorStore, ref, height, width]);
365
+
366
+ // initialize
367
+ useEffect(() => {
368
+ editorStore.internalizeEntityPath(params);
369
+ }, [editorStore, params]);
370
+ useEffect(() => {
371
+ flowResult(
372
+ editorStore.lazyTextEditorStore.init(
373
+ projectId,
374
+ patchReleaseVersionId,
375
+ workspaceId,
376
+ workspaceType,
377
+ ),
378
+ ).catch(applicationStore.alertUnhandledError);
379
+ }, [
380
+ editorStore,
381
+ patchReleaseVersionId,
382
+ applicationStore,
383
+ projectId,
384
+ workspaceId,
385
+ workspaceType,
386
+ ]);
387
+
388
+ useApplicationNavigationContext(
389
+ LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.EDITOR,
390
+ );
391
+
392
+ useCommands(editorStore);
393
+
394
+ // Cleanup the editor
395
+ useEffect(() => (): void => editorStore.cleanUp(), [editorStore]);
396
+ return (
397
+ <div className="app__page">
398
+ <div className="editor">
399
+ <div className="editor__body">
400
+ <ActivityBar />
401
+ <div ref={ref} className="editor__content-container">
402
+ <div className="editor__content">
403
+ <ResizablePanelGroup orientation="vertical">
404
+ <ResizablePanel
405
+ {...collapsibleSideBarGroupProps.collapsiblePanel}
406
+ direction={1}
407
+ >
408
+ <SideBar />
409
+ </ResizablePanel>
410
+ <ResizablePanelSplitter />
411
+ <ResizablePanel
412
+ {...collapsibleSideBarGroupProps.remainingPanel}
413
+ minSize={300}
414
+ >
415
+ <ResizablePanelGroup orientation="horizontal">
416
+ <ResizablePanel
417
+ {...maximizedCollapsiblePanelGroupProps.collapsiblePanel}
418
+ {...(editorStore.panelGroupDisplayState.size === 0
419
+ ? collapsiblePanelGroupProps.remainingPanel
420
+ : {})}
421
+ >
422
+ {editable &&
423
+ editorStore.graphEditorMode.mode ===
424
+ GRAPH_EDITOR_MODE.GRAMMAR_TEXT && (
425
+ <GrammarTextEditor />
426
+ )}
427
+ </ResizablePanel>
428
+ <ResizablePanelSplitter>
429
+ <ResizablePanelSplitterLine
430
+ color={
431
+ editorStore.panelGroupDisplayState.isMaximized
432
+ ? 'transparent'
433
+ : 'var(--color-dark-grey-250)'
434
+ }
435
+ />
436
+ </ResizablePanelSplitter>
437
+ <ResizablePanel
438
+ {...collapsiblePanelGroupProps.collapsiblePanel}
439
+ {...(editorStore.panelGroupDisplayState.isMaximized
440
+ ? maximizedCollapsiblePanelGroupProps.remainingPanel
441
+ : {})}
442
+ direction={-1}
443
+ >
444
+ <PanelGroup />
445
+ </ResizablePanel>
446
+ </ResizablePanelGroup>
447
+ </ResizablePanel>
448
+ </ResizablePanelGroup>
449
+ </div>
450
+ </div>
451
+ </div>
452
+ <QuickInput />
453
+ <LazyStatusBar actionsDisabled={!editable} />
454
+ </div>
455
+ </div>
456
+ );
457
+ }),
458
+ );
@@ -32,8 +32,8 @@ import {
32
32
  LongArrowRightIcon,
33
33
  DividerWithText,
34
34
  SearchIcon,
35
- FileImportIcon,
36
35
  BaseCard,
36
+ OpenIcon,
37
37
  } from '@finos/legend-art';
38
38
  import { LEGEND_STUDIO_TEST_ID } from '../../__lib__/LegendStudioTesting.js';
39
39
  import {
@@ -108,7 +108,7 @@ export const ShowcaseCard: React.FC<{ hideDocumentation?: boolean }> = (
108
108
  title: 'Showcase explorer',
109
109
  content: (
110
110
  <div className="workspace-setup__content__card__action__icon">
111
- <FileImportIcon />
111
+ <OpenIcon />
112
112
  </div>
113
113
  ),
114
114
  action: () => openShowcaseManager(applicationStore),
@@ -145,7 +145,7 @@ export const DocumentationCard: React.FC = () => {
145
145
  title: 'Review documentation',
146
146
  content: (
147
147
  <div className="workspace-setup__content__card__action__icon">
148
- <FileImportIcon />
148
+ <OpenIcon />
149
149
  </div>
150
150
  ),
151
151
  action: () => {
@@ -180,7 +180,7 @@ export const ProductionCard: React.FC = () => {
180
180
  title: productionDocument.text,
181
181
  content: (
182
182
  <div className="workspace-setup__content__card__action__icon">
183
- <FileImportIcon />
183
+ <OpenIcon />
184
184
  </div>
185
185
  ),
186
186
  action: () => {
@@ -216,7 +216,7 @@ export const SandboxCard: React.FC = () => {
216
216
  title: sandboxDocument.text,
217
217
  content: (
218
218
  <div className="workspace-setup__content__card__action__icon">
219
- <FileImportIcon />
219
+ <OpenIcon />
220
220
  </div>
221
221
  ),
222
222
  action: () => {
@@ -254,7 +254,7 @@ export const RuleEngagementCard: React.FC = () => {
254
254
  title: ruleEngagementDocument.text,
255
255
  content: (
256
256
  <div className="workspace-setup__content__card__action__icon">
257
- <FileImportIcon />
257
+ <OpenIcon />
258
258
  </div>
259
259
  ),
260
260
  action: () => {
@@ -22,7 +22,7 @@ import {
22
22
  guaranteeNonNullable,
23
23
  isNonNullable,
24
24
  } from '@finos/legend-shared';
25
- import { action, flow, makeObservable, observable } from 'mobx';
25
+ import { action, computed, flow, makeObservable, observable } from 'mobx';
26
26
  import { LEGEND_STUDIO_APP_EVENT } from '../__lib__/LegendStudioEvent.js';
27
27
  import {
28
28
  type Showcase,
@@ -40,6 +40,7 @@ import {
40
40
  import type { TreeData, TreeNodeData } from '@finos/legend-art';
41
41
  import { DIRECTORY_PATH_DELIMITER } from '@finos/legend-graph';
42
42
  import { SHOWCASE_MANAGER_VIRTUAL_ASSISTANT_TAB_KEY } from '../components/extensions/Core_LegendStudioApplicationPlugin.js';
43
+ import { LegendStudioTelemetryHelper } from '../__lib__/LegendStudioTelemetryHelper.js';
43
44
 
44
45
  export enum SHOWCASE_MANAGER_VIEW {
45
46
  EXPLORER = 'EXPLORER',
@@ -160,7 +161,7 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
160
161
 
161
162
  private readonly showcaseServerClient?: ShowcaseRegistryServerClient;
162
163
 
163
- showcases: ShowcaseMetadata[] = [];
164
+ allShowcases: ShowcaseMetadata[] | undefined;
164
165
  currentShowcase?: Showcase | undefined;
165
166
  showcaseLineToScroll?: number | undefined;
166
167
 
@@ -176,7 +177,7 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
176
177
  super();
177
178
 
178
179
  makeObservable(this, {
179
- showcases: observable,
180
+ allShowcases: observable,
180
181
  currentShowcase: observable,
181
182
  currentView: observable,
182
183
  explorerTreeData: observable.ref,
@@ -185,6 +186,8 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
185
186
  showcaseSearchResults: observable.ref,
186
187
  currentSearchCaterogy: observable,
187
188
  showcaseLineToScroll: observable,
189
+ nonDevShowcases: computed,
190
+ logOpenManager: action,
188
191
  setCurrentView: action,
189
192
  closeShowcase: action,
190
193
  setExplorerTreeData: action,
@@ -209,6 +212,10 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
209
212
  return ShowcaseManagerState.IDENTIFIER;
210
213
  }
211
214
 
215
+ get nonDevShowcases(): ShowcaseMetadata[] {
216
+ return this.allShowcases?.filter((showcase) => !showcase.development) ?? [];
217
+ }
218
+
212
219
  static retrieveNullableState(
213
220
  applicationStore: GenericLegendApplicationStore,
214
221
  ): ShowcaseManagerState | undefined {
@@ -263,9 +270,16 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
263
270
  this.fetchShowcaseState.inProgress();
264
271
 
265
272
  try {
266
- this.currentShowcase = (yield this.client.getShowcase(
273
+ const showcase = (yield this.client.getShowcase(
267
274
  metadata.path,
268
275
  )) as Showcase;
276
+ this.currentShowcase = showcase;
277
+ LegendStudioTelemetryHelper.logEvent_ShowcaseManagerShowcaseProjectLaunch(
278
+ this.applicationStore.telemetryService,
279
+ {
280
+ showcasePath: showcase.path,
281
+ },
282
+ );
269
283
  this.showcaseLineToScroll = showcaseLineToScroll;
270
284
  this.fetchShowcaseState.pass();
271
285
  } catch (error) {
@@ -278,6 +292,19 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
278
292
  }
279
293
  }
280
294
 
295
+ logOpenManager(): void {
296
+ if (this.allShowcases) {
297
+ const report = {
298
+ showcasesTotalCount: this.allShowcases.length,
299
+ showcasesDevelopmentCount: this.nonDevShowcases.length,
300
+ };
301
+ LegendStudioTelemetryHelper.logEvent_ShowcaseManagerLaunch(
302
+ this.applicationStore.telemetryService,
303
+ report,
304
+ );
305
+ }
306
+ }
307
+
281
308
  closeShowcase(): void {
282
309
  this.currentShowcase = undefined;
283
310
  this.showcaseLineToScroll = undefined;
@@ -308,10 +335,11 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
308
335
  this.initState.inProgress();
309
336
 
310
337
  try {
311
- this.showcases = (
312
- (yield this.client.getShowcases()) as ShowcaseMetadata[]
313
- ).filter((showcase) => !showcase.development);
314
- this.explorerTreeData = buildShowcasesExplorerTreeData(this.showcases);
338
+ this.allShowcases =
339
+ (yield this.client.getShowcases()) as ShowcaseMetadata[];
340
+ this.explorerTreeData = buildShowcasesExplorerTreeData(
341
+ this.nonDevShowcases,
342
+ );
315
343
  // expand all the root nodes by default
316
344
  this.explorerTreeData.rootIds.forEach((rootId) => {
317
345
  const rootNode = this.explorerTreeData?.nodes.get(rootId);
@@ -320,7 +348,6 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
320
348
  }
321
349
  });
322
350
  this.setExplorerTreeData({ ...this.explorerTreeData });
323
-
324
351
  this.initState.pass();
325
352
  } catch (error) {
326
353
  assertErrorThrown(error);
@@ -347,7 +374,7 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
347
374
  )) as ShowcaseTextSearchResult;
348
375
  this.textSearchResults = result.textMatches
349
376
  .map((match) => {
350
- const matchingShowcase = this.showcases.find(
377
+ const matchingShowcase = this.nonDevShowcases.find(
351
378
  (showcase) => showcase.path === match.path,
352
379
  );
353
380
  if (matchingShowcase) {
@@ -361,7 +388,9 @@ export class ShowcaseManagerState extends ApplicationExtensionState {
361
388
  .filter(isNonNullable);
362
389
  this.showcaseSearchResults = result.showcases
363
390
  .map((showcasePath) =>
364
- this.showcases.find((showcase) => showcase.path === showcasePath),
391
+ this.nonDevShowcases.find(
392
+ (showcase) => showcase.path === showcasePath,
393
+ ),
365
394
  )
366
395
  .filter(isNonNullable);
367
396
  } catch (error) {
@@ -388,5 +417,6 @@ export const openShowcaseManager = (
388
417
  applicationStore.assistantService.setSelectedTab(
389
418
  SHOWCASE_MANAGER_VIRTUAL_ASSISTANT_TAB_KEY,
390
419
  );
420
+ showcaseManagerState.logOpenManager();
391
421
  }
392
422
  };
@@ -19,6 +19,7 @@ export enum EDITOR_MODE {
19
19
  CONFLICT_RESOLUTION = 'CONFLICT_RESOLUTION',
20
20
  REVIEW = 'REVIEW',
21
21
  VIEWER = 'VIEWER',
22
+ LAZY_TEXT_EDITOR = 'LAZY_TEXT_EDITOR',
22
23
  }
23
24
 
24
25
  export enum TEST_RUNNER_TABS {
@@ -491,6 +491,31 @@ export class EditorGraphState {
491
491
  }
492
492
  }
493
493
 
494
+ *buildGraphForLazyText(): GeneratorFn<void> {
495
+ this.isInitializingGraph = true;
496
+ const stopWatch = new StopWatch();
497
+ // reset
498
+ this.editorStore.graphManagerState.resetGraph();
499
+ // fetch and build dependencies
500
+ stopWatch.record();
501
+ const dependencyManager =
502
+ this.editorStore.graphManagerState.graphManager.createDependencyManager();
503
+ this.editorStore.graphManagerState.graph.dependencyManager =
504
+ dependencyManager;
505
+ this.editorStore.graphManagerState.dependenciesBuildState.setMessage(
506
+ `Fetching dependencies...`,
507
+ );
508
+ const dependencyEntitiesIndex = (yield flowResult(
509
+ this.getIndexedDependencyEntities(),
510
+ )) as Map<string, EntitiesWithOrigin>;
511
+ stopWatch.record(GRAPH_MANAGER_EVENT.FETCH_GRAPH_DEPENDENCIES__SUCCESS);
512
+ dependencyManager.initialize(dependencyEntitiesIndex);
513
+ this.isInitializingGraph = false;
514
+ this.editorStore.graphManagerState.dependenciesBuildState.sync(
515
+ ActionState.create().pass(),
516
+ );
517
+ }
518
+
494
519
  private redirectToModelImporterForDebugging(error: Error): void {
495
520
  if (this.editorStore.isInConflictResolutionMode) {
496
521
  this.editorStore.applicationStore.alertService.setBlockingAlert({