@finos/legend-application-studio 28.9.0 → 28.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/lib/__lib__/LegendStudioCommand.d.ts +1 -0
  2. package/lib/__lib__/LegendStudioCommand.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioCommand.js +5 -0
  4. package/lib/__lib__/LegendStudioCommand.js.map +1 -1
  5. package/lib/components/ShowcaseManager.d.ts.map +1 -1
  6. package/lib/components/ShowcaseManager.js +5 -2
  7. package/lib/components/ShowcaseManager.js.map +1 -1
  8. package/lib/components/editor/ActivityBar.d.ts.map +1 -1
  9. package/lib/components/editor/ActivityBar.js +20 -17
  10. package/lib/components/editor/ActivityBar.js.map +1 -1
  11. package/lib/components/editor/editor-group/EditorGroup.d.ts.map +1 -1
  12. package/lib/components/editor/editor-group/EditorGroup.js +7 -1
  13. package/lib/components/editor/editor-group/EditorGroup.js.map +1 -1
  14. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.d.ts +5 -0
  15. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.d.ts.map +1 -1
  16. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js +29 -10
  17. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js.map +1 -1
  18. package/lib/components/editor/editor-group/connection-editor/DatabaseModelBuilder.d.ts +11 -0
  19. package/lib/components/editor/editor-group/connection-editor/DatabaseModelBuilder.d.ts.map +1 -1
  20. package/lib/components/editor/editor-group/connection-editor/DatabaseModelBuilder.js +22 -10
  21. package/lib/components/editor/editor-group/connection-editor/DatabaseModelBuilder.js.map +1 -1
  22. package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.d.ts +7 -0
  23. package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.d.ts.map +1 -1
  24. package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.js +3 -3
  25. package/lib/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.js.map +1 -1
  26. package/lib/components/editor/editor-group/end-to-end-flow-editor/ConnectionToQueryWorkflowEditor.d.ts +52 -0
  27. package/lib/components/editor/editor-group/end-to-end-flow-editor/ConnectionToQueryWorkflowEditor.d.ts.map +1 -0
  28. package/lib/components/editor/editor-group/end-to-end-flow-editor/ConnectionToQueryWorkflowEditor.js +150 -0
  29. package/lib/components/editor/editor-group/end-to-end-flow-editor/ConnectionToQueryWorkflowEditor.js.map +1 -0
  30. package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.js +1 -1
  31. package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.js.map +1 -1
  32. package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
  33. package/lib/components/editor/side-bar/Explorer.js +6 -6
  34. package/lib/components/editor/side-bar/Explorer.js.map +1 -1
  35. package/lib/components/editor/side-bar/SideBar.d.ts.map +1 -1
  36. package/lib/components/editor/side-bar/SideBar.js +4 -1
  37. package/lib/components/editor/side-bar/SideBar.js.map +1 -1
  38. package/lib/components/editor/side-bar/end-to-end-workflow/EndToEndWorkflows.d.ts +23 -0
  39. package/lib/components/editor/side-bar/end-to-end-workflow/EndToEndWorkflows.d.ts.map +1 -0
  40. package/lib/components/editor/side-bar/end-to-end-workflow/EndToEndWorkflows.js +43 -0
  41. package/lib/components/editor/side-bar/end-to-end-workflow/EndToEndWorkflows.js.map +1 -0
  42. package/lib/index.css +2 -2
  43. package/lib/index.css.map +1 -1
  44. package/lib/package.json +1 -1
  45. package/lib/stores/ShowcaseManagerState.d.ts +1 -0
  46. package/lib/stores/ShowcaseManagerState.d.ts.map +1 -1
  47. package/lib/stores/ShowcaseManagerState.js +11 -1
  48. package/lib/stores/ShowcaseManagerState.js.map +1 -1
  49. package/lib/stores/editor/EditorConfig.d.ts +3 -1
  50. package/lib/stores/editor/EditorConfig.d.ts.map +1 -1
  51. package/lib/stores/editor/EditorConfig.js +4 -1
  52. package/lib/stores/editor/EditorConfig.js.map +1 -1
  53. package/lib/stores/editor/EditorStore.d.ts +3 -0
  54. package/lib/stores/editor/EditorStore.d.ts.map +1 -1
  55. package/lib/stores/editor/EditorStore.js +17 -0
  56. package/lib/stores/editor/EditorStore.js.map +1 -1
  57. package/lib/stores/editor/ExplorerTreeState.d.ts.map +1 -1
  58. package/lib/stores/editor/ExplorerTreeState.js +1 -1
  59. package/lib/stores/editor/ExplorerTreeState.js.map +1 -1
  60. package/lib/stores/editor/GraphEditGrammarModeState.d.ts.map +1 -1
  61. package/lib/stores/editor/GraphEditGrammarModeState.js.map +1 -1
  62. package/lib/stores/editor/NewElementState.d.ts +1 -0
  63. package/lib/stores/editor/NewElementState.d.ts.map +1 -1
  64. package/lib/stores/editor/NewElementState.js +1 -1
  65. package/lib/stores/editor/NewElementState.js.map +1 -1
  66. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorState.d.ts.map +1 -1
  67. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorState.js +2 -1
  68. package/lib/stores/editor/editor-state/element-editor-state/ElementEditorState.js.map +1 -1
  69. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts +6 -2
  70. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts.map +1 -1
  71. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js +53 -34
  72. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js.map +1 -1
  73. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderWizardState.d.ts.map +1 -1
  74. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderWizardState.js +1 -1
  75. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderWizardState.js.map +1 -1
  76. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts +3 -2
  77. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts.map +1 -1
  78. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js +8 -5
  79. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js.map +1 -1
  80. package/lib/stores/editor/editor-state/end-to-end-workflow-state/EndToEndWorkflowEditorState.d.ts +22 -0
  81. package/lib/stores/editor/editor-state/end-to-end-workflow-state/EndToEndWorkflowEditorState.d.ts.map +1 -0
  82. package/lib/stores/editor/editor-state/end-to-end-workflow-state/EndToEndWorkflowEditorState.js +23 -0
  83. package/lib/stores/editor/editor-state/end-to-end-workflow-state/EndToEndWorkflowEditorState.js.map +1 -0
  84. package/lib/stores/editor/editor-state/end-to-end-workflow-state/QueryConnectionEndToEndWorkflowEditorState.d.ts +111 -0
  85. package/lib/stores/editor/editor-state/end-to-end-workflow-state/QueryConnectionEndToEndWorkflowEditorState.d.ts.map +1 -0
  86. package/lib/stores/editor/editor-state/end-to-end-workflow-state/QueryConnectionEndToEndWorkflowEditorState.js +453 -0
  87. package/lib/stores/editor/editor-state/end-to-end-workflow-state/QueryConnectionEndToEndWorkflowEditorState.js.map +1 -0
  88. package/lib/stores/editor/sidebar-state/end-to-end-workflow/GlobalEndToEndFlowState.d.ts +24 -0
  89. package/lib/stores/editor/sidebar-state/end-to-end-workflow/GlobalEndToEndFlowState.d.ts.map +1 -0
  90. package/lib/stores/editor/sidebar-state/end-to-end-workflow/GlobalEndToEndFlowState.js +37 -0
  91. package/lib/stores/editor/sidebar-state/end-to-end-workflow/GlobalEndToEndFlowState.js.map +1 -0
  92. package/lib/stores/showcase/ShowcaseViewerStore.d.ts.map +1 -1
  93. package/lib/stores/showcase/ShowcaseViewerStore.js +5 -1
  94. package/lib/stores/showcase/ShowcaseViewerStore.js.map +1 -1
  95. package/package.json +5 -5
  96. package/src/__lib__/LegendStudioCommand.ts +5 -0
  97. package/src/components/ShowcaseManager.tsx +18 -0
  98. package/src/components/editor/ActivityBar.tsx +56 -15
  99. package/src/components/editor/editor-group/EditorGroup.tsx +21 -1
  100. package/src/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.tsx +136 -103
  101. package/src/components/editor/editor-group/connection-editor/DatabaseModelBuilder.tsx +97 -53
  102. package/src/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.tsx +4 -3
  103. package/src/components/editor/editor-group/end-to-end-flow-editor/ConnectionToQueryWorkflowEditor.tsx +518 -0
  104. package/src/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.tsx +1 -1
  105. package/src/components/editor/side-bar/Explorer.tsx +7 -6
  106. package/src/components/editor/side-bar/SideBar.tsx +13 -1
  107. package/src/components/editor/side-bar/end-to-end-workflow/EndToEndWorkflows.tsx +102 -0
  108. package/src/stores/ShowcaseManagerState.ts +19 -1
  109. package/src/stores/editor/EditorConfig.ts +3 -0
  110. package/src/stores/editor/EditorStore.ts +21 -0
  111. package/src/stores/editor/ExplorerTreeState.ts +1 -0
  112. package/src/stores/editor/GraphEditGrammarModeState.ts +3 -3
  113. package/src/stores/editor/NewElementState.ts +1 -1
  114. package/src/stores/editor/editor-state/element-editor-state/ElementEditorState.ts +2 -1
  115. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +77 -49
  116. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderWizardState.ts +1 -2
  117. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.ts +12 -8
  118. package/src/stores/editor/editor-state/end-to-end-workflow-state/EndToEndWorkflowEditorState.ts +23 -0
  119. package/src/stores/editor/editor-state/end-to-end-workflow-state/QueryConnectionEndToEndWorkflowEditorState.ts +775 -0
  120. package/src/stores/editor/sidebar-state/end-to-end-workflow/GlobalEndToEndFlowState.ts +43 -0
  121. package/src/stores/showcase/ShowcaseViewerStore.ts +4 -0
  122. package/tsconfig.json +5 -0
@@ -20,6 +20,7 @@ export enum LEGEND_STUDIO_COMMAND_KEY {
20
20
  SYNC_WITH_WORKSPACE = 'editor.sync-workspace',
21
21
  CREATE_ELEMENT = 'editor.create-new-element',
22
22
  SEARCH_ELEMENT = 'editor.search-element',
23
+ OPEN_SHOWCASES = 'editor.show-showcases',
23
24
  TOGGLE_TEXT_MODE = 'editor.toggle-text-mode',
24
25
  GENERATE = 'editor.generate',
25
26
  COMPILE = 'editor.compile',
@@ -48,6 +49,10 @@ export const LEGEND_STUDIO_COMMAND_CONFIG: CommandConfigData = {
48
49
  title: 'Toggle model loader',
49
50
  defaultKeyboardShortcut: 'F2',
50
51
  },
52
+ [LEGEND_STUDIO_COMMAND_KEY.OPEN_SHOWCASES]: {
53
+ title: 'Open Showcases',
54
+ defaultKeyboardShortcut: 'F7',
55
+ },
51
56
  [LEGEND_STUDIO_COMMAND_KEY.TOGGLE_TEXT_MODE]: {
52
57
  title: 'Toggle text mode',
53
58
  defaultKeyboardShortcut: 'F8',
@@ -32,6 +32,7 @@ import {
32
32
  TimesIcon,
33
33
  CodeIcon,
34
34
  clsx,
35
+ CopyIcon,
35
36
  } from '@finos/legend-art';
36
37
  import {
37
38
  SHOWCASE_MANAGER_SEARCH_CATEGORY,
@@ -545,6 +546,15 @@ const ShowcaseViewer = observer(
545
546
  ),
546
547
  );
547
548
  };
549
+ const handleCopy =
550
+ showcaseManagerState.applicationStore.guardUnhandledError(() =>
551
+ showcaseManagerState.applicationStore.clipboardService.copyTextToClipboard(
552
+ showcase.code,
553
+ {
554
+ notifySuccessMessage: 'Showcase grammar copied to clipboard',
555
+ },
556
+ ),
557
+ );
548
558
  return (
549
559
  <div className="showcase-manager__view">
550
560
  <div className="showcase-manager__view__header">
@@ -608,6 +618,14 @@ const ShowcaseViewer = observer(
608
618
  </button>
609
619
  </div>
610
620
  </div>
621
+ <div className="showcase-manager__viewer__title__action">
622
+ <div
623
+ onClick={handleCopy}
624
+ className="showcase-manager__viewer__title__action-icon"
625
+ >
626
+ <CopyIcon />
627
+ </div>
628
+ </div>
611
629
  </div>
612
630
  <div className="showcase-manager__viewer__path">{prettyPath}</div>
613
631
  <div className="showcase-manager__viewer__code">
@@ -15,7 +15,11 @@
15
15
  */
16
16
 
17
17
  import { observer } from 'mobx-react-lite';
18
- import { ACTIVITY_MODE, PANEL_MODE } from '../../stores/editor/EditorConfig.js';
18
+ import {
19
+ ACTIVITY_MODE,
20
+ PANEL_MODE,
21
+ USER_JOURNEYS,
22
+ } from '../../stores/editor/EditorConfig.js';
19
23
  import { LEGEND_STUDIO_TEST_ID } from '../../__lib__/LegendStudioTesting.js';
20
24
  import {
21
25
  clsx,
@@ -36,6 +40,8 @@ import {
36
40
  MenuContentDivider,
37
41
  FlaskIcon,
38
42
  RobotIcon,
43
+ WorkflowIcon,
44
+ ReadMeIcon,
39
45
  } from '@finos/legend-art';
40
46
  import { useEditorStore } from './EditorStoreProvider.js';
41
47
  import { forwardRef, useState } from 'react';
@@ -47,8 +53,10 @@ import {
47
53
  ActivityBarItemExperimentalBadge,
48
54
  type ActivityBarItemConfig,
49
55
  } from '@finos/legend-lego/application';
50
- import { ShowcaseManagerState } from '../../stores/ShowcaseManagerState.js';
51
- import { SHOWCASE_MANAGER_VIRTUAL_ASSISTANT_TAB_KEY } from '../extensions/Core_LegendStudioApplicationPlugin.js';
56
+ import {
57
+ ShowcaseManagerState,
58
+ openShowcaseManager,
59
+ } from '../../stores/ShowcaseManagerState.js';
52
60
 
53
61
  const SettingsMenu = observer(
54
62
  forwardRef<HTMLDivElement, unknown>(function SettingsMenu(props, ref) {
@@ -103,17 +111,6 @@ export const ActivityBarMenu: React.FC = () => {
103
111
  // showcases
104
112
  const showcaseManagerState =
105
113
  ShowcaseManagerState.retrieveNullableState(applicationStore);
106
- const openShowcaseManager = (): void => {
107
- if (showcaseManagerState?.isEnabled) {
108
- applicationStore.assistantService.setIsHidden(false);
109
- applicationStore.assistantService.setIsOpen(true);
110
- applicationStore.assistantService.setIsPanelMaximized(true);
111
- applicationStore.assistantService.setSelectedTab(
112
- SHOWCASE_MANAGER_VIRTUAL_ASSISTANT_TAB_KEY,
113
- );
114
- }
115
- };
116
-
117
114
  return (
118
115
  <>
119
116
  <div className="activity-bar__menu">
@@ -128,7 +125,9 @@ export const ActivityBarMenu: React.FC = () => {
128
125
  <MenuContent>
129
126
  <MenuContentItem onClick={showAppInfo}>About</MenuContentItem>
130
127
  {showcaseManagerState?.isEnabled && (
131
- <MenuContentItem onClick={openShowcaseManager}>
128
+ <MenuContentItem
129
+ onClick={() => openShowcaseManager(applicationStore)}
130
+ >
132
131
  See Showcases
133
132
  </MenuContentItem>
134
133
  )}
@@ -363,6 +362,23 @@ export const ActivityBar = observer(() => {
363
362
  ] as (ActivityBarItemConfig | boolean)[]
364
363
  ).filter((activity): activity is ActivityBarItemConfig => Boolean(activity));
365
364
 
365
+ const userJourneys: ActivityBarItemConfig[] = (
366
+ [
367
+ !editorStore.isInConflictResolutionMode &&
368
+ editorStore.applicationStore.config.options
369
+ .TEMPORARY__enableEndtoEndWorkflow && {
370
+ mode: USER_JOURNEYS.END_TO_END_WORKFLOWS,
371
+ title: 'End to End Workflows (Beta)',
372
+ icon: (
373
+ <div>
374
+ <WorkflowIcon className="activity-bar__icon--service-registrar" />
375
+ <ActivityBarItemExperimentalBadge />
376
+ </div>
377
+ ),
378
+ },
379
+ ] as (ActivityBarItemConfig | boolean)[]
380
+ ).filter((activity): activity is ActivityBarItemConfig => Boolean(activity));
381
+
366
382
  return (
367
383
  <div className="activity-bar">
368
384
  <ActivityBarMenu />
@@ -382,9 +398,34 @@ export const ActivityBar = observer(() => {
382
398
  {activity.icon}
383
399
  </button>
384
400
  ))}
401
+ <MenuContentDivider />
402
+ {userJourneys.map((activity) => (
403
+ <button
404
+ key={activity.mode}
405
+ className={clsx('activity-bar__item', {
406
+ 'activity-bar__item--active':
407
+ editorStore.sideBarDisplayState.isOpen &&
408
+ editorStore.activeActivity === activity.mode,
409
+ })}
410
+ onClick={changeActivity(activity.mode)}
411
+ tabIndex={-1}
412
+ title={activity.title}
413
+ >
414
+ {activity.icon}
415
+ </button>
416
+ ))}
385
417
  </div>
418
+ <button
419
+ className={clsx('activity-bar__item')}
420
+ onClick={() => openShowcaseManager(editorStore.applicationStore)}
421
+ tabIndex={-1}
422
+ title={'Open Showcases'}
423
+ >
424
+ <ReadMeIcon />
425
+ </button>
386
426
  <DropdownMenu
387
427
  className="activity-bar__item"
428
+ title="Settings"
388
429
  content={<SettingsMenu />}
389
430
  menuProps={{
390
431
  anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
@@ -77,6 +77,8 @@ import { INTERNAL__UnknownFunctionActivatorEdtiorState } from '../../../stores/e
77
77
  import { INTERNAL__UnknownFunctionActivatorEdtior } from './INTERNAL__UnknownFunctionActivatorEdtior.js';
78
78
  import { getElementIcon } from '../../ElementIconUtils.js';
79
79
  import { ArtifactGenerationViewerState } from '../../../stores/editor/editor-state/ArtifactGenerationViewerState.js';
80
+ import { QueryConnectionWorflowEditor } from './end-to-end-flow-editor/ConnectionToQueryWorkflowEditor.js';
81
+ import { QueryConnectionEndToEndWorkflowEditorState } from '../../../stores/editor/editor-state/end-to-end-workflow-state/QueryConnectionEndToEndWorkflowEditorState.js';
80
82
 
81
83
  export const ViewerEditorGroupSplashScreen: React.FC = () => {
82
84
  const commandListWidth = 300;
@@ -119,7 +121,6 @@ export const EditorGroupSplashScreen: React.FC = () => {
119
121
  const commandListHeight = 180;
120
122
  const [showCommandList, setShowCommandList] = useState(false);
121
123
  const { ref, width, height } = useResizeDetector<HTMLDivElement>();
122
-
123
124
  useEffect(() => {
124
125
  setShowCommandList(
125
126
  (width ?? 0) > commandListWidth && (height ?? 0) > commandListHeight,
@@ -157,6 +158,14 @@ export const EditorGroupSplashScreen: React.FC = () => {
157
158
  <div className="hotkey__key">S</div>
158
159
  </div>
159
160
  </div>
161
+ <div className="editor-group__splash-screen__content__item">
162
+ <div className="editor-group__splash-screen__content__item__label">
163
+ Open Showcases
164
+ </div>
165
+ <div className="editor-group__splash-screen__content__item__hot-keys">
166
+ <div className="hotkey__key">F7</div>
167
+ </div>
168
+ </div>
160
169
  <div className="editor-group__splash-screen__content__item">
161
170
  <div className="editor-group__splash-screen__content__item__label">
162
171
  Toggle Hackermode
@@ -315,6 +324,17 @@ export const EditorGroup = observer(() => {
315
324
  return <ModelImporter />;
316
325
  } else if (currentTabState instanceof ProjectConfigurationEditorState) {
317
326
  return <ProjectConfigurationEditor />;
327
+ } else if (
328
+ currentTabState instanceof QueryConnectionEndToEndWorkflowEditorState
329
+ ) {
330
+ return (
331
+ <QueryConnectionWorflowEditor
332
+ connectionToQueryWorkflowState={
333
+ editorStore.globalEndToEndWorkflowState
334
+ .queryToConnectionWorkflowEditorState
335
+ }
336
+ />
337
+ );
318
338
  }
319
339
  // TODO: create an editor for unsupported tab
320
340
  return null;
@@ -127,6 +127,139 @@ const QueryBuilderGridResult = observer(
127
127
  },
128
128
  );
129
129
 
130
+ export const DatabaseBuilderModalContent = observer(
131
+ (props: { databaseBuilderState: DatabaseBuilderWizardState }) => {
132
+ const { databaseBuilderState } = props;
133
+ const applicationStore = useApplicationStore();
134
+ const schemaExplorerState = databaseBuilderState.schemaExplorerState;
135
+ const isCreatingNewDatabase = schemaExplorerState.isCreatingNewDatabase;
136
+ const elementAlreadyExistsMessage =
137
+ isCreatingNewDatabase &&
138
+ databaseBuilderState.editorStore.graphManagerState.graph.allElements
139
+ .map((s) => s.path)
140
+ .includes(schemaExplorerState.targetDatabasePath)
141
+ ? 'Element with same path already exists'
142
+ : undefined;
143
+
144
+ const isExecutingAction =
145
+ schemaExplorerState.isGeneratingDatabase ||
146
+ schemaExplorerState.isUpdatingDatabase ||
147
+ schemaExplorerState.previewDataState.isInProgress;
148
+
149
+ const onTargetPathChange: React.ChangeEventHandler<HTMLInputElement> = (
150
+ event,
151
+ ) => {
152
+ schemaExplorerState.setTargetDatabasePath(event.target.value);
153
+ };
154
+
155
+ useEffect(() => {
156
+ flowResult(schemaExplorerState.fetchDatabaseMetadata()).catch(
157
+ applicationStore.alertUnhandledError,
158
+ );
159
+ }, [applicationStore, schemaExplorerState]);
160
+
161
+ useConditionedApplicationNavigationContext(
162
+ LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.DATABASE_BUILDER,
163
+ databaseBuilderState.showModal,
164
+ );
165
+
166
+ return (
167
+ <ModalBody className="database-builder__content">
168
+ <PanelLoadingIndicator isLoading={isExecutingAction} />
169
+ <ResizablePanelGroup orientation="vertical">
170
+ <ResizablePanel size={450}>
171
+ <ResizablePanelGroup>
172
+ <ResizablePanel>
173
+ <div className="database-builder__config">
174
+ <PanelHeader title="schema explorer" />
175
+ <PanelContent className="database-builder__config__content">
176
+ {schemaExplorerState.treeData && (
177
+ <DatabaseSchemaExplorer
178
+ treeData={schemaExplorerState.treeData}
179
+ isReadOnly={false}
180
+ schemaExplorerState={
181
+ databaseBuilderState.schemaExplorerState
182
+ }
183
+ />
184
+ )}
185
+ </PanelContent>
186
+ </div>
187
+ </ResizablePanel>
188
+ <ResizablePanelSplitter>
189
+ <ResizablePanelSplitterLine
190
+ color={'var(--color-dark-grey-250)'}
191
+ />
192
+ </ResizablePanelSplitter>
193
+ <ResizablePanel>
194
+ <div className="database-builder__config">
195
+ <PanelHeader title="preview" />
196
+ <PanelContent className="database-builder__config__content">
197
+ {databaseBuilderState.schemaExplorerState.previewer && (
198
+ <QueryBuilderGridResult
199
+ executionResult={
200
+ databaseBuilderState.schemaExplorerState.previewer
201
+ }
202
+ />
203
+ )}
204
+ </PanelContent>
205
+ </div>
206
+ </ResizablePanel>
207
+ </ResizablePanelGroup>
208
+ </ResizablePanel>
209
+ <ResizablePanelSplitter />
210
+ <ResizablePanel>
211
+ <Panel className="database-builder__model">
212
+ <PanelHeader title="database model" />
213
+ <PanelContent>
214
+ <div className="database-builder__modeler">
215
+ <div className="panel__content__form__section database-builder__modeler__path">
216
+ <div className="panel__content__form__section__header__label">
217
+ Target Database Path
218
+ </div>
219
+ <InputWithInlineValidation
220
+ className="panel__content__form__section__input"
221
+ spellCheck={false}
222
+ onChange={onTargetPathChange}
223
+ disabled={
224
+ schemaExplorerState.makeTargetDatabasePathEditable
225
+ ? false
226
+ : !isCreatingNewDatabase
227
+ }
228
+ value={
229
+ schemaExplorerState.makeTargetDatabasePathEditable ||
230
+ isCreatingNewDatabase
231
+ ? schemaExplorerState.targetDatabasePath
232
+ : schemaExplorerState.database.path
233
+ }
234
+ error={elementAlreadyExistsMessage}
235
+ showEditableIcon={true}
236
+ />
237
+ </div>
238
+ <div className="database-builder__modeler__preview">
239
+ <div className="database-builder__modeler__preview__header">
240
+ readonly
241
+ </div>
242
+ {databaseBuilderState.databaseGrammarCode && (
243
+ <CodeEditor
244
+ language={CODE_EDITOR_LANGUAGE.PURE}
245
+ inputValue={databaseBuilderState.databaseGrammarCode}
246
+ isReadOnly={true}
247
+ />
248
+ )}
249
+ {!databaseBuilderState.databaseGrammarCode && (
250
+ <BlankPanelContent>No database preview</BlankPanelContent>
251
+ )}
252
+ </div>
253
+ </div>
254
+ </PanelContent>
255
+ </Panel>
256
+ </ResizablePanel>
257
+ </ResizablePanelGroup>
258
+ </ModalBody>
259
+ );
260
+ },
261
+ );
262
+
130
263
  export const DatabaseBuilderWizard = observer(
131
264
  (props: {
132
265
  databaseBuilderState: DatabaseBuilderWizardState;
@@ -147,11 +280,6 @@ export const DatabaseBuilderWizard = observer(
147
280
  const preview = applicationStore.guardUnhandledError(() =>
148
281
  flowResult(databaseBuilderState.previewDatabaseModel()),
149
282
  );
150
- const onTargetPathChange: React.ChangeEventHandler<HTMLInputElement> = (
151
- event,
152
- ) => {
153
- schemaExplorerState.setTargetDatabasePath(event.target.value);
154
- };
155
283
  const updateDatabase = applicationStore.guardUnhandledError(() =>
156
284
  flowResult(databaseBuilderState.updateDatabase()),
157
285
  );
@@ -166,17 +294,6 @@ export const DatabaseBuilderWizard = observer(
166
294
  schemaExplorerState.isUpdatingDatabase ||
167
295
  schemaExplorerState.previewDataState.isInProgress;
168
296
 
169
- useEffect(() => {
170
- flowResult(schemaExplorerState.fetchDatabaseMetadata()).catch(
171
- applicationStore.alertUnhandledError,
172
- );
173
- }, [applicationStore, schemaExplorerState]);
174
-
175
- useConditionedApplicationNavigationContext(
176
- LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.DATABASE_BUILDER,
177
- databaseBuilderState.showModal,
178
- );
179
-
180
297
  return (
181
298
  <Dialog
182
299
  open={databaseBuilderState.showModal}
@@ -201,93 +318,9 @@ export const DatabaseBuilderWizard = observer(
201
318
  </button>
202
319
  </ModalHeaderActions>
203
320
  </ModalHeader>
204
- <ModalBody className="database-builder__content">
205
- <PanelLoadingIndicator isLoading={isExecutingAction} />
206
- <ResizablePanelGroup orientation="vertical">
207
- <ResizablePanel size={450}>
208
- <ResizablePanelGroup>
209
- <ResizablePanel>
210
- <div className="database-builder__config">
211
- <PanelHeader title="schema explorer" />
212
- <PanelContent className="database-builder__config__content">
213
- {schemaExplorerState.treeData && (
214
- <DatabaseSchemaExplorer
215
- treeData={schemaExplorerState.treeData}
216
- isReadOnly={false}
217
- schemaExplorerState={
218
- databaseBuilderState.schemaExplorerState
219
- }
220
- />
221
- )}
222
- </PanelContent>
223
- </div>
224
- </ResizablePanel>
225
- <ResizablePanelSplitter>
226
- <ResizablePanelSplitterLine
227
- color={'var(--color-dark-grey-250)'}
228
- />
229
- </ResizablePanelSplitter>
230
- <ResizablePanel>
231
- <div className="database-builder__config">
232
- <PanelHeader title="preview" />
233
- <PanelContent className="database-builder__config__content">
234
- {databaseBuilderState.schemaExplorerState.previewer && (
235
- <QueryBuilderGridResult
236
- executionResult={
237
- databaseBuilderState.schemaExplorerState.previewer
238
- }
239
- />
240
- )}
241
- </PanelContent>
242
- </div>
243
- </ResizablePanel>
244
- </ResizablePanelGroup>
245
- </ResizablePanel>
246
- <ResizablePanelSplitter />
247
- <ResizablePanel>
248
- <Panel className="database-builder__model">
249
- <PanelHeader title="database model" />
250
- <PanelContent>
251
- <div className="database-builder__modeler">
252
- <div className="panel__content__form__section database-builder__modeler__path">
253
- <div className="panel__content__form__section__header__label">
254
- Target Database Path
255
- </div>
256
- <InputWithInlineValidation
257
- className="panel__content__form__section__input"
258
- spellCheck={false}
259
- onChange={onTargetPathChange}
260
- disabled={!isCreatingNewDatabase}
261
- value={
262
- isCreatingNewDatabase
263
- ? schemaExplorerState.targetDatabasePath
264
- : schemaExplorerState.database.path
265
- }
266
- error={elementAlreadyExistsMessage}
267
- />
268
- </div>
269
- <div className="database-builder__modeler__preview">
270
- {databaseBuilderState.databaseGrammarCode && (
271
- <CodeEditor
272
- language={CODE_EDITOR_LANGUAGE.PURE}
273
- inputValue={
274
- databaseBuilderState.databaseGrammarCode
275
- }
276
- isReadOnly={true}
277
- />
278
- )}
279
- {!databaseBuilderState.databaseGrammarCode && (
280
- <BlankPanelContent>
281
- No database preview
282
- </BlankPanelContent>
283
- )}
284
- </div>
285
- </div>
286
- </PanelContent>
287
- </Panel>
288
- </ResizablePanel>
289
- </ResizablePanelGroup>
290
- </ModalBody>
321
+ <DatabaseBuilderModalContent
322
+ databaseBuilderState={databaseBuilderState}
323
+ />
291
324
  <ModalFooter>
292
325
  <ModalFooterButton
293
326
  className="database-builder__action--btn"
@@ -50,6 +50,95 @@ import {
50
50
  import { debounce, noop } from '@finos/legend-shared';
51
51
  import { isValidPath } from '@finos/legend-graph';
52
52
 
53
+ export const DatabaseModelPackageInput = observer(
54
+ (props: { databaseModelBuilderState: DatabaseModelBuilderState }) => {
55
+ const { databaseModelBuilderState } = props;
56
+
57
+ const applicationStore = useApplicationStore();
58
+ const debouncedRegenerate = useMemo(
59
+ () =>
60
+ debounce(
61
+ () => flowResult(databaseModelBuilderState.previewDatabaseModels()),
62
+ 500,
63
+ ),
64
+ [databaseModelBuilderState],
65
+ );
66
+
67
+ const changeTargetPackage: React.ChangeEventHandler<HTMLInputElement> = (
68
+ event,
69
+ ) => {
70
+ databaseModelBuilderState.setTargetPackage(event.target.value);
71
+ debouncedRegenerate()?.catch(applicationStore.alertUnhandledError);
72
+ };
73
+
74
+ const targetPackageValidationMessage =
75
+ !databaseModelBuilderState.targetPackage
76
+ ? `Target package path can't be empty`
77
+ : !isValidPath(databaseModelBuilderState.targetPackage)
78
+ ? 'Invalid target package path'
79
+ : undefined;
80
+
81
+ return (
82
+ <div className="panel__content__form__section">
83
+ <div className="panel__content__form__section__header__label">
84
+ Target Package
85
+ </div>
86
+ <div className="panel__content__form__section__header__prompt">
87
+ Target Package of Mapping and Models Generated
88
+ </div>
89
+ <InputWithInlineValidation
90
+ className="query-builder__variables__variable__name__input input-group__input"
91
+ spellCheck={false}
92
+ value={databaseModelBuilderState.targetPackage}
93
+ onChange={changeTargetPackage}
94
+ placeholder="Target package path"
95
+ error={targetPackageValidationMessage}
96
+ showEditableIcon={true}
97
+ />
98
+ </div>
99
+ );
100
+ },
101
+ );
102
+
103
+ export const DatabaseModelPreviewEditor = observer(
104
+ (props: {
105
+ databaseModelBuilderState: DatabaseModelBuilderState;
106
+ grammarCode: string;
107
+ }) => {
108
+ const { databaseModelBuilderState, grammarCode } = props;
109
+
110
+ const isExecutingAction =
111
+ databaseModelBuilderState.generatingModelState.isInProgress ||
112
+ databaseModelBuilderState.saveModelState.isInProgress;
113
+
114
+ return (
115
+ <Panel className="database-builder__model">
116
+ <PanelHeader title="database model" />
117
+ <PanelContent>
118
+ <PanelLoadingIndicator isLoading={isExecutingAction} />
119
+ <div className="database-builder__modeler">
120
+ <div className="database-builder__modeler__preview">
121
+ <div className="database-builder__modeler__preview__header">
122
+ readonly
123
+ </div>
124
+ {databaseModelBuilderState.generatedGrammarCode && (
125
+ <CodeEditor
126
+ language={CODE_EDITOR_LANGUAGE.PURE}
127
+ inputValue={grammarCode}
128
+ isReadOnly={true}
129
+ />
130
+ )}
131
+ {!databaseModelBuilderState.generatedGrammarCode && (
132
+ <BlankPanelContent>No model preview</BlankPanelContent>
133
+ )}
134
+ </div>
135
+ </div>
136
+ </PanelContent>
137
+ </Panel>
138
+ );
139
+ },
140
+ );
141
+
53
142
  export const DatabaseModelBuilder = observer(
54
143
  (props: {
55
144
  databaseModelBuilderState: DatabaseModelBuilderState;
@@ -66,6 +155,7 @@ export const DatabaseModelBuilder = observer(
66
155
  ),
67
156
  [databaseModelBuilderState],
68
157
  );
158
+
69
159
  const preview = (): void => {
70
160
  debouncedRegenerate.cancel();
71
161
  debouncedRegenerate()?.catch(applicationStore.alertUnhandledError);
@@ -78,19 +168,6 @@ export const DatabaseModelBuilder = observer(
78
168
  databaseModelBuilderState.close();
79
169
  };
80
170
 
81
- const targetPackageValidationMessage =
82
- !databaseModelBuilderState.targetPackage
83
- ? `Target package path can't be empty`
84
- : !isValidPath(databaseModelBuilderState.targetPackage)
85
- ? 'Invalid target package path'
86
- : undefined;
87
-
88
- const changeTargetPackage: React.ChangeEventHandler<HTMLInputElement> = (
89
- event,
90
- ) => {
91
- databaseModelBuilderState.setTargetPackage(event.target.value);
92
- debouncedRegenerate()?.catch(applicationStore.alertUnhandledError);
93
- };
94
171
  const isExecutingAction =
95
172
  databaseModelBuilderState.generatingModelState.isInProgress ||
96
173
  databaseModelBuilderState.saveModelState.isInProgress;
@@ -136,51 +213,18 @@ export const DatabaseModelBuilder = observer(
136
213
  <div className="database-builder__config">
137
214
  <PanelHeader title="schema explorer" />
138
215
  <PanelContent className="database-builder__config__content">
139
- <div className="panel__content__form__section">
140
- <div className="panel__content__form__section__header__label">
141
- {'Target Package'}
142
- </div>
143
- <div className="panel__content__form__section__header__prompt">
144
- {'Target Package of Mapping and Models Generated'}
145
- </div>
146
- <InputWithInlineValidation
147
- className="query-builder__variables__variable__name__input input-group__input"
148
- spellCheck={false}
149
- value={databaseModelBuilderState.targetPackage}
150
- onChange={changeTargetPackage}
151
- placeholder="Target package path"
152
- error={targetPackageValidationMessage}
153
- />
154
- </div>
216
+ <DatabaseModelPackageInput
217
+ databaseModelBuilderState={databaseModelBuilderState}
218
+ />
155
219
  </PanelContent>
156
220
  </div>
157
221
  </ResizablePanel>
158
222
  <ResizablePanelSplitter />
159
223
  <ResizablePanel>
160
- <Panel className="database-builder__model">
161
- <PanelHeader title="database model" />
162
- <PanelContent>
163
- <PanelLoadingIndicator isLoading={isExecutingAction} />
164
- <div className="database-builder__modeler">
165
- <div className="database-builder__modeler__preview">
166
- {databaseModelBuilderState.generatedGrammarCode && (
167
- <CodeEditor
168
- language={CODE_EDITOR_LANGUAGE.PURE}
169
- inputValue={
170
- databaseModelBuilderState.generatedGrammarCode
171
- }
172
- isReadOnly={true}
173
- />
174
- )}
175
- {!databaseModelBuilderState.generatedGrammarCode && (
176
- <BlankPanelContent>
177
- No model preview
178
- </BlankPanelContent>
179
- )}
180
- </div>
181
- </div>
182
- </PanelContent>
183
- </Panel>
224
+ <DatabaseModelPreviewEditor
225
+ databaseModelBuilderState={databaseModelBuilderState}
226
+ grammarCode={databaseModelBuilderState.generatedGrammarCode}
227
+ />
184
228
  </ResizablePanel>
185
229
  </ResizablePanelGroup>
186
230
  </ModalBody>