@finos/legend-application-studio 28.7.1 → 28.9.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 (132) hide show
  1. package/lib/__lib__/LegendStudioNavigation.d.ts +6 -0
  2. package/lib/__lib__/LegendStudioNavigation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioNavigation.js +5 -0
  4. package/lib/__lib__/LegendStudioNavigation.js.map +1 -1
  5. package/lib/application/LegendStudioApplicationConfig.d.ts +0 -5
  6. package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
  7. package/lib/application/LegendStudioApplicationConfig.js +0 -6
  8. package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
  9. package/lib/components/LegendStudioWebApplication.d.ts.map +1 -1
  10. package/lib/components/LegendStudioWebApplication.js +4 -1
  11. package/lib/components/LegendStudioWebApplication.js.map +1 -1
  12. package/lib/components/ShowcaseManager.d.ts.map +1 -1
  13. package/lib/components/ShowcaseManager.js +6 -1
  14. package/lib/components/ShowcaseManager.js.map +1 -1
  15. package/lib/components/editor/editor-group/GrammarTextEditor.js +1 -1
  16. package/lib/components/editor/editor-group/GrammarTextEditor.js.map +1 -1
  17. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.d.ts.map +1 -1
  18. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js +41 -4
  19. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js.map +1 -1
  20. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts +2 -0
  21. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts.map +1 -1
  22. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js +13 -3
  23. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js.map +1 -1
  24. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts +18 -0
  25. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts.map +1 -0
  26. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js +54 -0
  27. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js.map +1 -0
  28. package/lib/components/editor/panel-group/PanelGroup.d.ts.map +1 -1
  29. package/lib/components/editor/panel-group/PanelGroup.js +1 -5
  30. package/lib/components/editor/panel-group/PanelGroup.js.map +1 -1
  31. package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
  32. package/lib/components/editor/side-bar/Explorer.js +11 -4
  33. package/lib/components/editor/side-bar/Explorer.js.map +1 -1
  34. package/lib/components/editor/side-bar/ProjectOverview.d.ts.map +1 -1
  35. package/lib/components/editor/side-bar/ProjectOverview.js +1 -1
  36. package/lib/components/editor/side-bar/ProjectOverview.js.map +1 -1
  37. package/lib/components/project-view/ProjectViewer.d.ts.map +1 -1
  38. package/lib/components/project-view/ProjectViewer.js +37 -5
  39. package/lib/components/project-view/ProjectViewer.js.map +1 -1
  40. package/lib/components/showcase/ShowcaseViewer.d.ts +18 -0
  41. package/lib/components/showcase/ShowcaseViewer.d.ts.map +1 -0
  42. package/lib/components/showcase/ShowcaseViewer.js +147 -0
  43. package/lib/components/showcase/ShowcaseViewer.js.map +1 -0
  44. package/lib/components/showcase/ShowcaseViewerStoreProvider.d.ts +23 -0
  45. package/lib/components/showcase/ShowcaseViewerStoreProvider.d.ts.map +1 -0
  46. package/lib/components/showcase/ShowcaseViewerStoreProvider.js +36 -0
  47. package/lib/components/showcase/ShowcaseViewerStoreProvider.js.map +1 -0
  48. package/lib/index.css +2 -2
  49. package/lib/index.css.map +1 -1
  50. package/lib/package.json +1 -1
  51. package/lib/stores/LegendStudioBaseStore.d.ts.map +1 -1
  52. package/lib/stores/LegendStudioBaseStore.js +1 -0
  53. package/lib/stores/LegendStudioBaseStore.js.map +1 -1
  54. package/lib/stores/editor/EditorMode.d.ts +4 -0
  55. package/lib/stores/editor/EditorMode.d.ts.map +1 -1
  56. package/lib/stores/editor/EditorMode.js +9 -0
  57. package/lib/stores/editor/EditorMode.js.map +1 -1
  58. package/lib/stores/editor/EditorSDLCState.d.ts +1 -2
  59. package/lib/stores/editor/EditorSDLCState.d.ts.map +1 -1
  60. package/lib/stores/editor/EditorSDLCState.js +3 -14
  61. package/lib/stores/editor/EditorSDLCState.js.map +1 -1
  62. package/lib/stores/editor/EditorStore.d.ts.map +1 -1
  63. package/lib/stores/editor/EditorStore.js +1 -3
  64. package/lib/stores/editor/EditorStore.js.map +1 -1
  65. package/lib/stores/editor/StandardEditorMode.d.ts +1 -0
  66. package/lib/stores/editor/StandardEditorMode.d.ts.map +1 -1
  67. package/lib/stores/editor/StandardEditorMode.js +4 -0
  68. package/lib/stores/editor/StandardEditorMode.js.map +1 -1
  69. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts +5 -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 +209 -2
  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/DatabaseModelBuilderState.d.ts +1 -2
  74. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts.map +1 -1
  75. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js +2 -2
  76. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js.map +1 -1
  77. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts +37 -0
  78. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts.map +1 -0
  79. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js +127 -0
  80. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js.map +1 -0
  81. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts.map +1 -1
  82. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js +20 -4
  83. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js.map +1 -1
  84. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts +3 -0
  85. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts.map +1 -1
  86. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js +17 -2
  87. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js.map +1 -1
  88. package/lib/stores/project-view/ProjectViewerEditorMode.d.ts +3 -0
  89. package/lib/stores/project-view/ProjectViewerEditorMode.d.ts.map +1 -1
  90. package/lib/stores/project-view/ProjectViewerEditorMode.js +10 -0
  91. package/lib/stores/project-view/ProjectViewerEditorMode.js.map +1 -1
  92. package/lib/stores/project-view/ProjectViewerStore.d.ts.map +1 -1
  93. package/lib/stores/project-view/ProjectViewerStore.js +1 -0
  94. package/lib/stores/project-view/ProjectViewerStore.js.map +1 -1
  95. package/lib/stores/showcase/ShowcaseViewerEditorMode.d.ts +28 -0
  96. package/lib/stores/showcase/ShowcaseViewerEditorMode.d.ts.map +1 -0
  97. package/lib/stores/showcase/ShowcaseViewerEditorMode.js +40 -0
  98. package/lib/stores/showcase/ShowcaseViewerEditorMode.js.map +1 -0
  99. package/lib/stores/showcase/ShowcaseViewerStore.d.ts +32 -0
  100. package/lib/stores/showcase/ShowcaseViewerStore.d.ts.map +1 -0
  101. package/lib/stores/showcase/ShowcaseViewerStore.js +189 -0
  102. package/lib/stores/showcase/ShowcaseViewerStore.js.map +1 -0
  103. package/package.json +7 -7
  104. package/src/__lib__/LegendStudioNavigation.ts +11 -0
  105. package/src/application/LegendStudioApplicationConfig.ts +0 -7
  106. package/src/components/LegendStudioWebApplication.tsx +11 -1
  107. package/src/components/ShowcaseManager.tsx +26 -2
  108. package/src/components/editor/editor-group/GrammarTextEditor.tsx +1 -1
  109. package/src/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.tsx +117 -16
  110. package/src/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.tsx +40 -1
  111. package/src/components/editor/editor-group/database/IsolatedQueryDatabase.tsx +138 -0
  112. package/src/components/editor/panel-group/PanelGroup.tsx +3 -8
  113. package/src/components/editor/side-bar/Explorer.tsx +41 -18
  114. package/src/components/editor/side-bar/ProjectOverview.tsx +0 -19
  115. package/src/components/project-view/ProjectViewer.tsx +139 -4
  116. package/src/components/showcase/ShowcaseViewer.tsx +418 -0
  117. package/src/components/showcase/ShowcaseViewerStoreProvider.tsx +56 -0
  118. package/src/stores/LegendStudioBaseStore.ts +1 -0
  119. package/src/stores/editor/EditorMode.ts +14 -0
  120. package/src/stores/editor/EditorSDLCState.ts +6 -19
  121. package/src/stores/editor/EditorStore.ts +1 -8
  122. package/src/stores/editor/StandardEditorMode.ts +7 -0
  123. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +288 -2
  124. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.ts +2 -5
  125. package/src/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.ts +234 -0
  126. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts +31 -9
  127. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.ts +23 -0
  128. package/src/stores/project-view/ProjectViewerEditorMode.ts +17 -0
  129. package/src/stores/project-view/ProjectViewerStore.ts +1 -0
  130. package/src/stores/showcase/ShowcaseViewerEditorMode.ts +51 -0
  131. package/src/stores/showcase/ShowcaseViewerStore.ts +285 -0
  132. package/tsconfig.json +6 -0
@@ -26,6 +26,7 @@ import {
26
26
  CheckCircleIcon,
27
27
  EmptyCircleIcon,
28
28
  KeyIcon,
29
+ EyeIcon,
29
30
  } from '@finos/legend-art';
30
31
  import {
31
32
  type DatabaseExplorerTreeData,
@@ -70,6 +71,10 @@ export type DatabaseSchemaExplorerTreeNodeContainerProps =
70
71
  isPartiallySelected: (
71
72
  node: DatabaseSchemaExplorerTreeNodeData,
72
73
  ) => boolean;
74
+ previewData: (node: DatabaseSchemaExplorerTreeNodeData) => void;
75
+ isPreviewDataDisabled: (
76
+ node: DatabaseSchemaExplorerTreeNodeData,
77
+ ) => boolean;
73
78
  }
74
79
  >;
75
80
 
@@ -77,7 +82,12 @@ export const DatabaseSchemaExplorerTreeNodeContainer = observer(
77
82
  forwardRef<HTMLDivElement, DatabaseSchemaExplorerTreeNodeContainerProps>(
78
83
  function DatabaseSchemaExplorerTreeNodeContainer(props, ref) {
79
84
  const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
80
- const { toggleCheckedNode, isPartiallySelected } = innerProps;
85
+ const {
86
+ toggleCheckedNode,
87
+ isPartiallySelected,
88
+ isPreviewDataDisabled,
89
+ previewData,
90
+ } = innerProps;
81
91
  const isExpandable =
82
92
  Boolean(!node.childrenIds || node.childrenIds.length) &&
83
93
  !(node instanceof DatabaseSchemaExplorerTreeColumnNodeData);
@@ -158,6 +168,19 @@ export const DatabaseSchemaExplorerTreeNodeContainer = observer(
158
168
  <KeyIcon />
159
169
  </div>
160
170
  )}
171
+ {!isPreviewDataDisabled(node) && (
172
+ <button
173
+ className="query-builder-explorer-tree__node__action"
174
+ tabIndex={-1}
175
+ onClick={(event) => {
176
+ event.stopPropagation();
177
+ previewData(node);
178
+ }}
179
+ title="Preview Table Data"
180
+ >
181
+ <EyeIcon />
182
+ </button>
183
+ )}
161
184
  </div>
162
185
  </div>
163
186
  );
@@ -206,6 +229,20 @@ export const DatabaseSchemaExplorer = observer(
206
229
  node: DatabaseSchemaExplorerTreeNodeData,
207
230
  ): void => schemaExplorerState.toggleCheckedNode(node, treeData);
208
231
 
232
+ const previewData = (node: DatabaseSchemaExplorerTreeNodeData): void => {
233
+ flowResult(schemaExplorerState.previewData(node)).catch(
234
+ applicationStore.alertUnhandledError,
235
+ );
236
+ };
237
+
238
+ const isPreviewDataDisabled = (
239
+ node: DatabaseSchemaExplorerTreeNodeData,
240
+ ): boolean =>
241
+ !(
242
+ node instanceof DatabaseSchemaExplorerTreeTableNodeData ||
243
+ node instanceof DatabaseSchemaExplorerTreeColumnNodeData
244
+ );
245
+
209
246
  return (
210
247
  <TreeView
211
248
  className="database-schema-explorer"
@@ -217,6 +254,8 @@ export const DatabaseSchemaExplorer = observer(
217
254
  innerProps={{
218
255
  toggleCheckedNode,
219
256
  isPartiallySelected,
257
+ previewData,
258
+ isPreviewDataDisabled,
220
259
  }}
221
260
  treeData={treeData}
222
261
  onNodeSelect={onNodeSelect}
@@ -0,0 +1,138 @@
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 {
18
+ type PackageableConnection,
19
+ getMappingCompatibleClasses,
20
+ } from '@finos/legend-graph';
21
+ import { QueryBuilderClassSelector } from '@finos/legend-query-builder';
22
+ import type { IsolatedDatabaseBuilderState } from '../../../../stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js';
23
+ import { observer } from 'mobx-react-lite';
24
+ import {
25
+ CustomSelectorInput,
26
+ PURE_ConnectionIcon,
27
+ PURE_DatabaseIcon,
28
+ } from '@finos/legend-art';
29
+ import { returnUndefOnError } from '@finos/legend-shared';
30
+
31
+ const IsolatedDatabseQueryBuilderSetupPanelContext = observer(
32
+ (props: { queryBuilderState: IsolatedDatabaseBuilderState }) => {
33
+ const { queryBuilderState } = props;
34
+ const globalGraphManagerState = queryBuilderState.globalGraphManagerState;
35
+ const getConnectionValue = (
36
+ val: string,
37
+ ): PackageableConnection | undefined =>
38
+ returnUndefOnError(() =>
39
+ globalGraphManagerState.graph.getConnection(val),
40
+ );
41
+ const database = queryBuilderState.database;
42
+ const compConnections = queryBuilderState.compatibleConnections;
43
+ const compConnectionsOptions = Array.from(compConnections.keys()).map(
44
+ (e) => ({ value: e, label: getConnectionValue(e)?.name ?? e }),
45
+ );
46
+ const changeConnection = (
47
+ val: { value: string; label: string } | null,
48
+ ): void => {
49
+ if (val) {
50
+ queryBuilderState.changeConnection(val.value);
51
+ }
52
+ };
53
+ const connection = compConnections.get(queryBuilderState.connectionKey);
54
+ const selectedConnection = connection
55
+ ? {
56
+ label: queryBuilderState.connectionKey,
57
+ value:
58
+ getConnectionValue(queryBuilderState.connectionKey)?.name ??
59
+ queryBuilderState.connectionKey,
60
+ }
61
+ : undefined;
62
+ const databaseOption = {
63
+ value: database,
64
+ label: database.path,
65
+ };
66
+ const classes = queryBuilderState.executionContextState.mapping
67
+ ? getMappingCompatibleClasses(
68
+ queryBuilderState.executionContextState.mapping,
69
+ queryBuilderState.graphManagerState.usableClasses,
70
+ )
71
+ : [];
72
+ return (
73
+ <>
74
+ <QueryBuilderClassSelector
75
+ queryBuilderState={queryBuilderState}
76
+ classes={classes}
77
+ noMatchMessage="No classes selected from"
78
+ />
79
+ <div className="query-builder__setup__config-group">
80
+ <div className="query-builder__setup__config-group__header">
81
+ <div className="query-builder__setup__config-group__header__title">
82
+ database/connection
83
+ </div>
84
+ </div>
85
+ <div className="query-builder__setup__config-group__content">
86
+ <div className="query-builder__setup__config-group__item">
87
+ <div
88
+ className="btn--sm query-builder__setup__config-group__item__label"
89
+ title="mapping"
90
+ >
91
+ <PURE_DatabaseIcon />
92
+ </div>
93
+ <CustomSelectorInput
94
+ className="panel__content__form__section__dropdown query-builder__setup__config-group__item__selector"
95
+ noMatchMessage="No compatible mapping found for specified class"
96
+ disabled={true}
97
+ options={[]}
98
+ value={databaseOption}
99
+ darkMode={
100
+ !queryBuilderState.applicationStore.layoutService
101
+ .TEMPORARY__isLightColorThemeEnabled
102
+ }
103
+ />
104
+ </div>
105
+ <div className="query-builder__setup__config-group__item">
106
+ <div
107
+ className="btn--sm query-builder__setup__config-group__item__label"
108
+ title="connection"
109
+ >
110
+ <PURE_ConnectionIcon />
111
+ </div>
112
+ <CustomSelectorInput
113
+ className="panel__content__form__section__dropdown query-builder__setup__config-group__item__selector"
114
+ noMatchMessage="No compatible mapping found for specified class"
115
+ disabled={compConnectionsOptions.length < 2}
116
+ options={compConnectionsOptions}
117
+ onChange={changeConnection}
118
+ value={selectedConnection}
119
+ darkMode={
120
+ !queryBuilderState.applicationStore.layoutService
121
+ .TEMPORARY__isLightColorThemeEnabled
122
+ }
123
+ />
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </>
128
+ );
129
+ },
130
+ );
131
+
132
+ export const renderDatabaseQueryBuilderSetupPanelContent = (
133
+ queryBuilderState: IsolatedDatabaseBuilderState,
134
+ ): React.ReactNode => (
135
+ <IsolatedDatabseQueryBuilderSetupPanelContext
136
+ queryBuilderState={queryBuilderState}
137
+ />
138
+ );
@@ -95,14 +95,9 @@ export const PanelGroup = observer(() => {
95
95
  },
96
96
  };
97
97
 
98
- const tabsToShow = Object.values(PANEL_MODE)
99
- .filter((tab) => isNonNullable(tabs[tab]) && tabs[tab].isVisible)
100
- .filter(
101
- (tab) =>
102
- tab !== PANEL_MODE.SQL_PLAYGROUND ||
103
- editorStore.applicationStore.config.options
104
- .TEMPORARY__enableRawSQLExecutor,
105
- );
98
+ const tabsToShow = Object.values(PANEL_MODE).filter(
99
+ (tab) => isNonNullable(tabs[tab]) && tabs[tab].isVisible,
100
+ );
106
101
  const isTabVisible = (tabType: PANEL_MODE): boolean =>
107
102
  editorStore.activePanelMode === tabType && tabsToShow.includes(tabType);
108
103
 
@@ -147,6 +147,7 @@ import { DatabaseBuilderWizard } from '../editor-group/connection-editor/Databas
147
147
  import { FunctionEditorState } from '../../../stores/editor/editor-state/element-editor-state/FunctionEditorState.js';
148
148
  import { DatabaseModelBuilder } from '../editor-group/connection-editor/DatabaseModelBuilder.js';
149
149
  import { queryService } from '../editor-group/service-editor/ServiceExecutionQueryEditor.js';
150
+ import { QueryDatabaseState } from '../../../stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js';
150
151
 
151
152
  const ElementRenamer = observer(() => {
152
153
  const editorStore = useEditorStore();
@@ -529,6 +530,19 @@ const ExplorerContextMenu = observer(
529
530
  }
530
531
  },
531
532
  );
533
+ const buildDatabaseQuery = editorStore.applicationStore.guardUnhandledError(
534
+ async () => {
535
+ if (node?.packageableElement instanceof Database) {
536
+ const state = new QueryDatabaseState(
537
+ node.packageableElement,
538
+ editorStore,
539
+ );
540
+ flowResult(state.init()).catch(
541
+ editorStore.applicationStore.alertUnhandledError,
542
+ );
543
+ }
544
+ },
545
+ );
532
546
  const generateSampleData = editorStore.applicationStore.guardUnhandledError(
533
547
  async () => {
534
548
  if (node?.packageableElement instanceof Class) {
@@ -884,12 +898,10 @@ const ExplorerContextMenu = observer(
884
898
  )}
885
899
  {isRelationalDatabaseConnection(node.packageableElement) && (
886
900
  <>
887
- {editorStore.applicationStore.config.options
888
- .TEMPORARY__enableRawSQLExecutor && (
889
- <MenuContentItem onClick={openSQLPlayground}>
890
- Execute SQL...
891
- </MenuContentItem>
892
- )}
901
+ <MenuContentItem onClick={openSQLPlayground}>
902
+ Execute SQL...
903
+ </MenuContentItem>
904
+
893
905
  <MenuContentItem onClick={buildDatabase}>
894
906
  Build Database...
895
907
  </MenuContentItem>
@@ -901,6 +913,9 @@ const ExplorerContextMenu = observer(
901
913
  <MenuContentItem onClick={generateModelsFromDatabaseSpecification}>
902
914
  Build Models
903
915
  </MenuContentItem>
916
+ <MenuContentItem onClick={buildDatabaseQuery}>
917
+ Query (Beta)...
918
+ </MenuContentItem>
904
919
  <MenuContentDivider />
905
920
  </>
906
921
  )}
@@ -1361,7 +1376,7 @@ const ProjectExplorerActionPanel = observer((props: { disabled: boolean }) => {
1361
1376
 
1362
1377
  return (
1363
1378
  <div className="panel__header__actions">
1364
- {!editorStore.isInViewerMode && (
1379
+ {
1365
1380
  <button
1366
1381
  className="panel__header__action"
1367
1382
  disabled={disabled}
@@ -1370,15 +1385,17 @@ const ProjectExplorerActionPanel = observer((props: { disabled: boolean }) => {
1370
1385
  >
1371
1386
  <FileImportIcon />
1372
1387
  </button>
1388
+ }
1389
+ {editorStore.editorMode.supportSdlcOperations && (
1390
+ <button
1391
+ className="panel__header__action panel__header__action--config"
1392
+ disabled={disabled}
1393
+ title="Project Configuration Panel"
1394
+ onClick={openConfigurationEditor}
1395
+ >
1396
+ <SettingsEthernetIcon />
1397
+ </button>
1373
1398
  )}
1374
- <button
1375
- className="panel__header__action panel__header__action--config"
1376
- disabled={disabled}
1377
- title="Project Configuration Panel"
1378
- onClick={openConfigurationEditor}
1379
- >
1380
- <SettingsEthernetIcon />
1381
- </button>
1382
1399
  {!editorStore.isInViewerMode && (
1383
1400
  <DropdownMenu
1384
1401
  className="panel__header__action"
@@ -1462,10 +1479,16 @@ export const Explorer = observer(() => {
1462
1479
  EXPLORER
1463
1480
  </div>
1464
1481
  </div>
1465
- {editorStore.isInViewerMode && (
1482
+ {editorStore.editorMode.disableEditing &&
1483
+ !editorStore.editorMode.label && (
1484
+ <div className="panel__header__title side-bar__header__title__viewer-mode-badge">
1485
+ <LockIcon />
1486
+ READ-ONLY
1487
+ </div>
1488
+ )}
1489
+ {editorStore.editorMode.label && (
1466
1490
  <div className="panel__header__title side-bar__header__title__viewer-mode-badge">
1467
- <LockIcon />
1468
- READ-ONLY
1491
+ {editorStore.editorMode.label}
1469
1492
  </div>
1470
1493
  )}
1471
1494
  </div>
@@ -999,25 +999,6 @@ const OverviewViewer = observer(() => {
999
999
  onChange={changeProjectIdentifier}
1000
1000
  />
1001
1001
  </div>
1002
- {
1003
- <div className="panel__content__form__section">
1004
- <div className="panel__content__form__section__header__label">
1005
- Project User Role
1006
- <DocumentationLink
1007
- documentationKey={
1008
- LEGEND_STUDIO_DOCUMENTATION_KEY.QUESTION_WHAT_ARE_PROJECT_ROLES
1009
- }
1010
- />
1011
- </div>
1012
- <input
1013
- className="panel__content__form__section__input"
1014
- title="Project User Role"
1015
- disabled={true}
1016
- spellCheck={false}
1017
- value={sdlcState.accessRole?.accessRole ?? '(unknown)'}
1018
- />
1019
- </div>
1020
- }
1021
1002
  </div>
1022
1003
  <div className="panel__content__form">
1023
1004
  <div className="panel__content__form__section">
@@ -37,6 +37,11 @@ import {
37
37
  FileTrayIcon,
38
38
  AssistantIcon,
39
39
  useResizeDetector,
40
+ FireIcon,
41
+ TrashIcon,
42
+ HammerIcon,
43
+ TerminalIcon,
44
+ ResizablePanelSplitterLine,
40
45
  } from '@finos/legend-art';
41
46
  import { isNonNullable } from '@finos/legend-shared';
42
47
  import {
@@ -65,6 +70,7 @@ import {
65
70
  import { EmbeddedQueryBuilder } from '../editor/EmbeddedQueryBuilder.js';
66
71
  import type { ActivityBarItemConfig } from '@finos/legend-lego/application';
67
72
  import { ActivityBarMenu } from '../editor/ActivityBar.js';
73
+ import { PanelGroup } from '../editor/panel-group/PanelGroup.js';
68
74
 
69
75
  const ProjectViewerStatusBar = observer(() => {
70
76
  const params = useParams<ProjectViewerPathParams>();
@@ -90,11 +96,26 @@ const ProjectViewerStatusBar = observer(() => {
90
96
  ? 'current'
91
97
  : ''
92
98
  }`;
99
+
100
+ const editable =
101
+ editorStore.graphManagerState.graphBuildState.hasCompleted &&
102
+ editorStore.isInitialized;
93
103
  const handleTextModeClick = applicationStore.guardUnhandledError(() =>
94
104
  flowResult(editorStore.toggleTextMode()),
95
105
  );
106
+ const compile = applicationStore.guardUnhandledError(() =>
107
+ flowResult(editorStore.graphEditorMode.globalCompile()),
108
+ );
109
+ const generate = applicationStore.guardUnhandledError(() =>
110
+ flowResult(editorStore.graphState.graphGenerationState.globalGenerate()),
111
+ );
112
+ const emptyGenerationEntities = applicationStore.guardUnhandledError(() =>
113
+ flowResult(editorStore.graphState.graphGenerationState.clearGenerations()),
114
+ );
115
+
96
116
  const toggleAssistant = (): void =>
97
117
  applicationStore.assistantService.toggleAssistant();
118
+ const togglePanel = (): void => editorStore.panelGroupDisplayState.toggle();
98
119
 
99
120
  return (
100
121
  <div
@@ -136,6 +157,76 @@ const ProjectViewerStatusBar = observer(() => {
136
157
  )}
137
158
  </div>
138
159
  <div className="editor__status-bar__right">
160
+ <button
161
+ className={clsx(
162
+ 'editor__status-bar__action editor__status-bar__generate-btn',
163
+ {
164
+ 'editor__status-bar__generate-btn--wiggling':
165
+ editorStore.graphState.graphGenerationState
166
+ .isRunningGlobalGenerate,
167
+ },
168
+ )}
169
+ disabled={
170
+ editorStore.graphState.isApplicationUpdateOperationIsRunning
171
+ }
172
+ onClick={generate}
173
+ tabIndex={-1}
174
+ title="Generate (F10)"
175
+ >
176
+ <FireIcon />
177
+ </button>
178
+ <button
179
+ className={clsx(
180
+ 'editor__status-bar__action editor__status-bar__clear__generation-btn ',
181
+
182
+ {
183
+ 'editor__status-bar__action editor__status-bar__clear__generation-btn--wiggling':
184
+ editorStore.graphState.graphGenerationState
185
+ .clearingGenerationEntitiesState.isInProgress,
186
+ },
187
+ )}
188
+ disabled={
189
+ editorStore.graphState.isApplicationUpdateOperationIsRunning ||
190
+ !editable
191
+ }
192
+ onClick={emptyGenerationEntities}
193
+ tabIndex={-1}
194
+ title="Clear generation entities"
195
+ >
196
+ <TrashIcon />
197
+ </button>
198
+ <button
199
+ className={clsx(
200
+ 'editor__status-bar__action editor__status-bar__compile-btn',
201
+ {
202
+ 'editor__status-bar__compile-btn--wiggling':
203
+ editorStore.graphState.isRunningGlobalCompile,
204
+ },
205
+ )}
206
+ disabled={
207
+ editorStore.graphState.isApplicationUpdateOperationIsRunning ||
208
+ !editable
209
+ }
210
+ onClick={compile}
211
+ tabIndex={-1}
212
+ title="Compile (F9)"
213
+ >
214
+ <HammerIcon />
215
+ </button>
216
+ <button
217
+ className={clsx(
218
+ 'editor__status-bar__action editor__status-bar__action__toggler',
219
+ {
220
+ 'editor__status-bar__action__toggler--active':
221
+ editorStore.panelGroupDisplayState.isOpen,
222
+ },
223
+ )}
224
+ onClick={togglePanel}
225
+ tabIndex={-1}
226
+ title="Toggle panel (Ctrl + `)"
227
+ >
228
+ <TerminalIcon />
229
+ </button>
139
230
  <button
140
231
  className={clsx(
141
232
  'editor__status-bar__action editor__status-bar__action__toggler',
@@ -288,6 +379,21 @@ export const ProjectViewer = withEditorStore(
288
379
  size: editorStore.sideBarDisplayState.size,
289
380
  },
290
381
  );
382
+ const resizePanel = (handleProps: ResizablePanelHandlerProps): void =>
383
+ editorStore.panelGroupDisplayState.setSize(
384
+ (handleProps.domElement as HTMLDivElement).getBoundingClientRect()
385
+ .height,
386
+ );
387
+ const maximizedCollapsiblePanelGroupProps = getCollapsiblePanelGroupProps(
388
+ editorStore.panelGroupDisplayState.isMaximized,
389
+ );
390
+ const collapsiblePanelGroupProps = getCollapsiblePanelGroupProps(
391
+ editorStore.panelGroupDisplayState.size === 0,
392
+ {
393
+ onStopResize: resizePanel,
394
+ size: editorStore.panelGroupDisplayState.size,
395
+ },
396
+ );
291
397
  const { ref, width, height } = useResizeDetector<HTMLDivElement>();
292
398
  useEffect(() => {
293
399
  if (ref.current) {
@@ -330,10 +436,39 @@ export const ProjectViewer = withEditorStore(
330
436
  {...sideBarCollapsiblePanelGroupProps.remainingPanel}
331
437
  minSize={300}
332
438
  >
333
- {editorStore.graphEditorMode.mode ===
334
- GRAPH_EDITOR_MODE.FORM && <EditorGroup />}
335
- {editorStore.graphEditorMode.mode ===
336
- GRAPH_EDITOR_MODE.GRAMMAR_TEXT && <GrammarTextEditor />}
439
+ <ResizablePanelGroup orientation="horizontal">
440
+ <ResizablePanel
441
+ {...maximizedCollapsiblePanelGroupProps.collapsiblePanel}
442
+ {...(editorStore.panelGroupDisplayState.size === 0
443
+ ? collapsiblePanelGroupProps.remainingPanel
444
+ : {})}
445
+ >
446
+ {editorStore.graphEditorMode.mode ===
447
+ GRAPH_EDITOR_MODE.FORM && <EditorGroup />}
448
+ {editorStore.graphEditorMode.mode ===
449
+ GRAPH_EDITOR_MODE.GRAMMAR_TEXT && (
450
+ <GrammarTextEditor />
451
+ )}
452
+ </ResizablePanel>
453
+ <ResizablePanelSplitter>
454
+ <ResizablePanelSplitterLine
455
+ color={
456
+ editorStore.panelGroupDisplayState.isMaximized
457
+ ? 'transparent'
458
+ : 'var(--color-dark-grey-250)'
459
+ }
460
+ />
461
+ </ResizablePanelSplitter>
462
+ <ResizablePanel
463
+ {...collapsiblePanelGroupProps.collapsiblePanel}
464
+ {...(editorStore.panelGroupDisplayState.isMaximized
465
+ ? maximizedCollapsiblePanelGroupProps.remainingPanel
466
+ : {})}
467
+ direction={-1}
468
+ >
469
+ <PanelGroup />
470
+ </ResizablePanel>
471
+ </ResizablePanelGroup>
337
472
  </ResizablePanel>
338
473
  </ResizablePanelGroup>
339
474
  </div>