@finos/legend-application-studio 23.0.3 → 23.1.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 (70) hide show
  1. package/lib/application/LegendStudioApplicationConfig.d.ts +0 -4
  2. package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
  3. package/lib/application/LegendStudioApplicationConfig.js +0 -5
  4. package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
  5. package/lib/application/LegendStudioNavigation.d.ts +9 -4
  6. package/lib/application/LegendStudioNavigation.d.ts.map +1 -1
  7. package/lib/application/LegendStudioNavigation.js +12 -8
  8. package/lib/application/LegendStudioNavigation.js.map +1 -1
  9. package/lib/application/LegendStudioTesting.d.ts +1 -0
  10. package/lib/application/LegendStudioTesting.d.ts.map +1 -1
  11. package/lib/application/LegendStudioTesting.js +1 -0
  12. package/lib/application/LegendStudioTesting.js.map +1 -1
  13. package/lib/components/LegendStudioApplication.d.ts.map +1 -1
  14. package/lib/components/LegendStudioApplication.js.map +1 -1
  15. package/lib/components/editor/edit-panel/mapping-editor/MappingTestEditor.js +1 -1
  16. package/lib/components/editor/edit-panel/mapping-editor/MappingTestEditor.js.map +1 -1
  17. package/lib/components/editor/edit-panel/service-editor/BulkServiceRegistrationEditor.d.ts.map +1 -1
  18. package/lib/components/editor/edit-panel/service-editor/BulkServiceRegistrationEditor.js +41 -33
  19. package/lib/components/editor/edit-panel/service-editor/BulkServiceRegistrationEditor.js.map +1 -1
  20. package/lib/components/editor/edit-panel/service-editor/ServiceExecutionQueryEditor.js +1 -1
  21. package/lib/components/editor/edit-panel/service-editor/ServiceExecutionQueryEditor.js.map +1 -1
  22. package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
  23. package/lib/components/editor/side-bar/Explorer.js +1 -1
  24. package/lib/components/editor/side-bar/Explorer.js.map +1 -1
  25. package/lib/components/editor/side-bar/RegisterService.d.ts.map +1 -1
  26. package/lib/components/editor/side-bar/RegisterService.js +4 -8
  27. package/lib/components/editor/side-bar/RegisterService.js.map +1 -1
  28. package/lib/components/project-view/ProjectViewer.js.map +1 -1
  29. package/lib/components/workspace-review/WorkspaceReview.js.map +1 -1
  30. package/lib/components/workspace-setup/WorkspaceSetup.js.map +1 -1
  31. package/lib/index.css +2 -2
  32. package/lib/index.css.map +1 -1
  33. package/lib/package.json +6 -6
  34. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts +8 -5
  35. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.d.ts.map +1 -1
  36. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js +19 -12
  37. package/lib/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js.map +1 -1
  38. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts.map +1 -1
  39. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js +3 -3
  40. package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js.map +1 -1
  41. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.d.ts +7 -41
  42. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.d.ts.map +1 -1
  43. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js +23 -185
  44. package/lib/stores/editor/sidebar-state/BulkServiceRegistrationState.js.map +1 -1
  45. package/lib/stores/project-view/ProjectViewerStore.d.ts +3 -3
  46. package/lib/stores/project-view/ProjectViewerStore.d.ts.map +1 -1
  47. package/lib/stores/project-view/ProjectViewerStore.js.map +1 -1
  48. package/package.json +15 -15
  49. package/src/application/LegendStudioApplicationConfig.ts +0 -6
  50. package/src/application/LegendStudioNavigation.ts +40 -21
  51. package/src/application/LegendStudioTesting.ts +1 -0
  52. package/src/components/LegendStudioApplication.tsx +0 -7
  53. package/src/components/editor/edit-panel/mapping-editor/MappingTestEditor.tsx +1 -1
  54. package/src/components/editor/edit-panel/service-editor/BulkServiceRegistrationEditor.tsx +100 -71
  55. package/src/components/editor/edit-panel/service-editor/ServiceExecutionQueryEditor.tsx +1 -1
  56. package/src/components/editor/side-bar/Explorer.tsx +1 -3
  57. package/src/components/editor/side-bar/RegisterService.tsx +26 -38
  58. package/src/components/project-view/ProjectViewer.tsx +3 -3
  59. package/src/components/workspace-review/WorkspaceReview.tsx +2 -2
  60. package/src/components/workspace-setup/WorkspaceSetup.tsx +2 -2
  61. package/src/stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.ts +28 -15
  62. package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.ts +5 -0
  63. package/src/stores/editor/sidebar-state/BulkServiceRegistrationState.ts +47 -289
  64. package/src/stores/project-view/ProjectViewerStore.ts +3 -3
  65. package/tsconfig.json +0 -1
  66. package/lib/components/element-preview/ElementPreview.d.ts +0 -2
  67. package/lib/components/element-preview/ElementPreview.d.ts.map +0 -1
  68. package/lib/components/element-preview/ElementPreview.js +0 -2
  69. package/lib/components/element-preview/ElementPreview.js.map +0 -1
  70. package/src/components/element-preview/ElementPreview.tsx +0 -0
@@ -26,96 +26,119 @@ import {
26
26
  ModalBody,
27
27
  TimesIcon,
28
28
  } from '@finos/legend-art';
29
- import { prettyCONSTName } from '@finos/legend-shared';
29
+ import {
30
+ filterByType,
31
+ guaranteeNonNullable,
32
+ prettyCONSTName,
33
+ } from '@finos/legend-shared';
30
34
  import { LEGEND_STUDIO_TEST_ID } from '../../../../application/LegendStudioTesting.js';
31
- import { ServiceExecutionMode } from '@finos/legend-graph';
35
+ import {
36
+ ServiceRegistrationFail,
37
+ ServiceRegistrationSuccess,
38
+ ServiceExecutionMode,
39
+ } from '@finos/legend-graph';
32
40
  import { flowResult } from 'mobx';
33
41
  import { Version } from '@finos/legend-server-sdlc';
34
42
  import { useEditorStore } from '../../EditorStoreProvider.js';
35
43
  import { useApplicationStore } from '@finos/legend-application';
44
+ import { generateServiceManagementUrl } from '../../../../stores/editor/editor-state/element-editor-state/service/ServiceRegistrationState.js';
36
45
 
37
46
  export const BulkServiceRegistrationEditor = observer(() => {
38
47
  const editorStore = useEditorStore();
39
48
  const applicationStore = useApplicationStore();
40
- const serviceState = editorStore.bulkServiceRegistrationState;
41
- const registrationState = serviceState.serviceConfigState;
49
+ const bulkServiceRegistrationState = editorStore.bulkServiceRegistrationState;
42
50
  // env & execution server
43
- const envOptions = registrationState.options.map((info) => ({
44
- label: info.env.toUpperCase(),
45
- value: info.env,
46
- }));
47
- const selectedEnvOption = registrationState.serviceEnv
51
+ const envOptions = bulkServiceRegistrationState.options
52
+ .filter((info) => info.env !== 'prod')
53
+ .map((info) => ({
54
+ label: info.env.toUpperCase(),
55
+ value: info.env,
56
+ }));
57
+ const selectedEnvOption = bulkServiceRegistrationState.serviceEnv
48
58
  ? {
49
- label: registrationState.serviceEnv.toUpperCase(),
50
- value: registrationState.serviceEnv,
59
+ label: bulkServiceRegistrationState.serviceEnv.toUpperCase(),
60
+ value: bulkServiceRegistrationState.serviceEnv,
51
61
  }
52
62
  : null;
53
63
  const onServerEnvChange = (
54
64
  val: { label: string; value: string } | null,
55
65
  ): void => {
56
- registrationState.updateEnv(val?.value);
66
+ bulkServiceRegistrationState.updateEnv(val?.value);
57
67
  };
58
68
 
59
69
  // execution mode
60
- const serviceTypesOptions = registrationState.executionModes.map((mode) => ({
61
- label: prettyCONSTName(mode),
62
- value: mode,
63
- }));
64
- const selectedServiceType = registrationState.serviceExecutionMode
70
+ const serviceTypesOptions = bulkServiceRegistrationState.executionModes
71
+ .filter((mode) => mode !== ServiceExecutionMode.PROD)
72
+ .map((mode) => ({
73
+ label: prettyCONSTName(mode),
74
+ value: mode,
75
+ }));
76
+ const selectedServiceType = bulkServiceRegistrationState.serviceExecutionMode
65
77
  ? {
66
- label: prettyCONSTName(registrationState.serviceExecutionMode),
67
- value: registrationState.serviceExecutionMode,
78
+ label: prettyCONSTName(
79
+ bulkServiceRegistrationState.serviceExecutionMode,
80
+ ),
81
+ value: bulkServiceRegistrationState.serviceExecutionMode,
68
82
  }
69
83
  : null;
70
84
  const onServiceTypeSelectionChange = (
71
85
  val: { label: ServiceExecutionMode; value: ServiceExecutionMode } | null,
72
86
  ): void => {
73
- registrationState.updateType(val?.value);
87
+ bulkServiceRegistrationState.updateType(val?.value);
74
88
  };
75
89
 
76
90
  // version
77
- const selectedVersion = registrationState.projectVersion
91
+ const selectedVersion = bulkServiceRegistrationState.projectVersion
78
92
  ? {
79
93
  label:
80
- registrationState.projectVersion instanceof Version
81
- ? registrationState.projectVersion.id.id
82
- : registrationState.projectVersion,
83
- value: registrationState.projectVersion,
94
+ bulkServiceRegistrationState.projectVersion instanceof Version
95
+ ? bulkServiceRegistrationState.projectVersion.id.id
96
+ : bulkServiceRegistrationState.projectVersion,
97
+ value: bulkServiceRegistrationState.projectVersion,
84
98
  }
85
99
  : null;
86
100
  const onVersionSelectionChange = (
87
101
  val: { label: string; value: Version | string } | null,
88
102
  ): void => {
89
- registrationState.setProjectVersion(val?.value);
103
+ bulkServiceRegistrationState.setProjectVersion(val?.value);
90
104
  };
91
105
  const versionPlaceholder =
92
- registrationState.versionOptions === undefined
106
+ bulkServiceRegistrationState.versionOptions === undefined
93
107
  ? `Only valid for ${prettyCONSTName(
94
108
  ServiceExecutionMode.SEMI_INTERACTIVE,
95
109
  )} and ${prettyCONSTName(ServiceExecutionMode.PROD)} service types`
96
- : !registrationState.versionOptions.length
110
+ : !bulkServiceRegistrationState.versionOptions.length
97
111
  ? 'Project has no versions'
98
112
  : undefined;
99
113
 
100
114
  // store model for full interactive
101
115
  const toggleUseStoreModel = (): void => {
102
- registrationState.setUseStoreModelWithFullInteractive(
103
- !registrationState.TEMPORARY__useStoreModel,
116
+ bulkServiceRegistrationState.setUseStoreModelWithFullInteractive(
117
+ !bulkServiceRegistrationState.TEMPORARY__useStoreModel,
104
118
  );
105
119
  };
106
120
 
121
+ const config = guaranteeNonNullable(
122
+ bulkServiceRegistrationState.options.find(
123
+ (info) => info.env === bulkServiceRegistrationState.serviceEnv,
124
+ ),
125
+ );
126
+
107
127
  // actions
108
128
  const registerService = (): void => {
109
129
  if (selectedEnvOption && selectedServiceType) {
110
- flowResult(serviceState.registerServices()).catch(
130
+ flowResult(bulkServiceRegistrationState.registerServices()).catch(
111
131
  applicationStore.alertUnhandledError,
112
132
  );
113
133
  }
114
134
  };
135
+ const closeModal = (): void => {
136
+ editorStore.bulkServiceRegistrationState.setSuccessModal(false);
137
+ };
115
138
  const disableRegistration =
116
139
  !selectedEnvOption ||
117
140
  !selectedServiceType ||
118
- registrationState.registrationState.isInProgress;
141
+ bulkServiceRegistrationState.registrationState.isInProgress;
119
142
 
120
143
  return (
121
144
  <div
@@ -140,51 +163,57 @@ export const BulkServiceRegistrationEditor = observer(() => {
140
163
  <Dialog
141
164
  open={editorStore.bulkServiceRegistrationState.showSuccessModel}
142
165
  >
143
- <Modal darkMode={true} className="blocking-alert__summary-text">
144
- <div>
166
+ <Modal
167
+ darkMode={true}
168
+ className="editor-modal bulk-service-registration__service__response"
169
+ >
170
+ <div className="bulk-service-registration__header">
145
171
  <button
146
- className="query-builder__dialog__header__action"
172
+ className="bulk-service-registration__header__action"
147
173
  tabIndex={-1}
148
- onClick={() => {
149
- editorStore.bulkServiceRegistrationState.setSuccessModal(
150
- false,
151
- );
152
- }}
174
+ onClick={closeModal}
153
175
  >
154
176
  <TimesIcon />
155
177
  </button>
156
178
  </div>
157
179
  <ModalBody>
158
- <div>
159
- Successful Services:
160
- {editorStore.bulkServiceRegistrationState.serviceConfigState.registrationResult?.successfulServices.map(
161
- (service) => (
162
- <div key={service}>
180
+ <div className="bulk-service-registration__service__result__header">
181
+ Successful Services
182
+ {editorStore.bulkServiceRegistrationState.registrationResult
183
+ ?.filter(filterByType(ServiceRegistrationSuccess))
184
+ .map((service) => (
185
+ <div
186
+ className="bulk-service-registration__service__link__label"
187
+ key={service.pattern}
188
+ >
163
189
  <a
164
- href={editorStore.bulkServiceRegistrationState.serviceConfigState.registrationResult?.serviceLinks.at(
165
- editorStore.bulkServiceRegistrationState.serviceConfigState.registrationResult.successfulServices.indexOf(
166
- service,
167
- ),
190
+ className="bulk-service-registration__service__link__label__service__link"
191
+ href={generateServiceManagementUrl(
192
+ config.managementUrl,
193
+ service.pattern,
168
194
  )}
169
195
  >
170
- {service}
196
+ {service.pattern}
171
197
  </a>
172
198
  </div>
173
- ),
174
- )}
199
+ ))}
175
200
  </div>
176
- <>
177
- {editorStore.bulkServiceRegistrationState.serviceConfigState.registrationResult?.successfulServices.forEach(
178
- (element) => {
179
- <div>{element}</div>;
180
- },
181
- )}
182
- </>
183
201
  <div>
184
- Failed Services:{' '}
185
- {editorStore.bulkServiceRegistrationState.serviceConfigState.registrationResult?.failedServices.join(
186
- '\n',
187
- )}
202
+ <div className="bulk-service-registration__service__result__header">
203
+ Failed Services
204
+ </div>
205
+ <div>
206
+ {editorStore.bulkServiceRegistrationState.registrationResult
207
+ ?.filter(filterByType(ServiceRegistrationFail))
208
+ .map((service) => (
209
+ <div
210
+ key={service.errorMessage}
211
+ className="bulk-service-registration__service__link__label"
212
+ >
213
+ {`${service.service?.path} ${service.errorMessage}`}
214
+ </div>
215
+ ))}
216
+ </div>
188
217
  </div>
189
218
  </ModalBody>
190
219
  </Modal>
@@ -193,12 +222,12 @@ export const BulkServiceRegistrationEditor = observer(() => {
193
222
  </div>
194
223
  </div>
195
224
  <PanelLoadingIndicator
196
- isLoading={registrationState.registrationState.isInProgress}
225
+ isLoading={bulkServiceRegistrationState.registrationState.isInProgress}
197
226
  />
198
227
  <div className="panel__content__form">
199
- {registrationState.registrationState.message && (
228
+ {bulkServiceRegistrationState.registrationState.message && (
200
229
  <div className="service-registration-editor__progress-msg">
201
- {`${registrationState.registrationState.message}...`}
230
+ {`${bulkServiceRegistrationState.registrationState.message}...`}
202
231
  </div>
203
232
  )}
204
233
  <div className="panel__content__form__section">
@@ -230,7 +259,7 @@ export const BulkServiceRegistrationEditor = observer(() => {
230
259
  darkMode={true}
231
260
  />
232
261
  </div>
233
- {registrationState.serviceExecutionMode ===
262
+ {bulkServiceRegistrationState.serviceExecutionMode ===
234
263
  ServiceExecutionMode.FULL_INTERACTIVE && (
235
264
  <div className="panel__content__form__section">
236
265
  <div className="panel__content__form__section__header__label">
@@ -243,11 +272,11 @@ export const BulkServiceRegistrationEditor = observer(() => {
243
272
  <button
244
273
  className={clsx('panel__content__form__section__toggler__btn', {
245
274
  'panel__content__form__section__toggler__btn--toggled':
246
- registrationState.TEMPORARY__useStoreModel,
275
+ bulkServiceRegistrationState.TEMPORARY__useStoreModel,
247
276
  })}
248
277
  tabIndex={-1}
249
278
  >
250
- {registrationState.TEMPORARY__useStoreModel ? (
279
+ {bulkServiceRegistrationState.TEMPORARY__useStoreModel ? (
251
280
  <CheckSquareIcon />
252
281
  ) : (
253
282
  <SquareIcon />
@@ -268,11 +297,11 @@ export const BulkServiceRegistrationEditor = observer(() => {
268
297
  relevant for semi-interactive and production services.
269
298
  </div>
270
299
  <CustomSelectorInput
271
- options={registrationState.versionOptions ?? []}
300
+ options={bulkServiceRegistrationState.versionOptions ?? []}
272
301
  onChange={onVersionSelectionChange}
273
302
  value={selectedVersion}
274
303
  darkMode={true}
275
- disabled={registrationState.versionOptions === undefined}
304
+ disabled={bulkServiceRegistrationState.versionOptions === undefined}
276
305
  placeholder={versionPlaceholder}
277
306
  isLoading={editorStore.sdlcState.isFetchingProjectVersions}
278
307
  />
@@ -597,7 +597,7 @@ export const ServiceExecutionQueryEditor = observer(
597
597
  />
598
598
  <div
599
599
  className="service-execution-query-editor__content"
600
- title={'double click to edit query in query builder'}
600
+ title="Double click to edit in query builder"
601
601
  onDoubleClick={(event) => {
602
602
  event.preventDefault();
603
603
  event.stopPropagation();
@@ -1299,9 +1299,7 @@ export const Explorer = observer(() => {
1299
1299
  ) && (
1300
1300
  <div className="explorer__content--empty">
1301
1301
  <div className="explorer__content--empty__text">
1302
- Can&apos;t build graph as workspace contains merge
1303
- conflicts, please resolve them before trying to build the
1304
- graph again
1302
+ {`Can't build graph as workspace contains merge conflicts, please resolve them before trying to build the graph again`}
1305
1303
  </div>
1306
1304
  <button
1307
1305
  className="btn--dark btn--conflict btn--important explorer__content--empty__btn"
@@ -26,8 +26,6 @@ import {
26
26
  Dialog,
27
27
  Modal,
28
28
  TimesIcon,
29
- EmptyWindowRestoreIcon,
30
- WindowMaximizeIcon,
31
29
  } from '@finos/legend-art';
32
30
  import type { BulkServiceRegistrationState } from '../../../stores/editor/sidebar-state/BulkServiceRegistrationState.js';
33
31
  import { BulkServiceRegistrationEditor } from '../edit-panel/service-editor/BulkServiceRegistrationEditor.js';
@@ -37,25 +35,22 @@ export const RegisterService = observer(
37
35
  (props: { bulkServiceRegistrationState: BulkServiceRegistrationState }) => {
38
36
  const editorStore = useEditorStore();
39
37
  const services = editorStore.graphManagerState.graph.ownServices;
40
- const [open, setOpen] = useState(false);
38
+ const [showRegistrationModel, setShowRegistrationModel] = useState(false);
41
39
 
42
- const [isMaximized, setIsMaximized] = useState(false);
43
- const toggleMaximize = (): void => setIsMaximized(!isMaximized);
44
-
45
- const renderTestables = (): React.ReactNode => (
40
+ const serviceItems = (): React.ReactNode => (
46
41
  <>
47
42
  {services.map((service) => (
48
43
  <ContextMenu key={service._UUID}>
49
44
  <div
50
45
  className={clsx(
51
- 'tree-view__node__container global-test-runner__explorer__testable-tree__node__container',
46
+ 'bulk-service-registration__service__container bulk-service-registration__explorer__service__container',
52
47
  )}
53
48
  >
54
- <div className="global-test-runner__explorer__testable-tree__node__result__icon__type">
49
+ <div className="bulk-service-registration__explorer__service__result__icon__type">
55
50
  <PURE_ServiceIcon />
56
51
  </div>
57
- <div className="global-test-runner__item__link__content">
58
- <span className="global-test-runner__item__link__content__id">
52
+ <div className="bulk-service-registration__item__link__content">
53
+ <span className="bulk-service-registration__item__link__content__id">
59
54
  {service.name}
60
55
  </span>
61
56
  </div>
@@ -67,53 +62,44 @@ export const RegisterService = observer(
67
62
 
68
63
  return (
69
64
  <div
70
- data-testid={LEGEND_STUDIO_TEST_ID.GLOBAL_TEST_RUNNER}
71
- className="panel global-test-runner"
65
+ data-testid={LEGEND_STUDIO_TEST_ID.BULK_REGISTRATION}
66
+ className="panel bulk-service-registration"
72
67
  >
73
68
  <div className="panel__header side-bar__header">
74
- <div className="panel__header__title global-test-runner__header__title">
69
+ <div className="panel__header__title bulk-service-registration__header__title">
75
70
  <div className="panel__header__title__content side-bar__header__title__content">
76
71
  REGISTER SERVICES
77
72
  </div>
78
73
  </div>
79
74
  <div className="panel__header__actions side-bar__header__actions"></div>
80
75
  <button
81
- className="panel__header__action side-bar__header__action global-test-runner__refresh-btn"
82
- onClick={() => setOpen(true)}
76
+ className="panel__header__action side-bar__header__action bulk-service-registration__play-btn"
77
+ onClick={() => setShowRegistrationModel(true)}
83
78
  tabIndex={-1}
84
79
  title="Register All Services"
85
80
  >
86
81
  <PlayIcon />
87
82
  </button>
88
- <Dialog onClose={noop} open={open}>
83
+ <Dialog onClose={noop} open={showRegistrationModel}>
89
84
  <Modal
90
85
  darkMode={true}
91
- className={clsx('editor-modal query-builder__dialog', {
92
- 'query-builder__dialog--expanded': isMaximized,
93
- })}
86
+ className={clsx(
87
+ 'editor-modal bulk-service-registration__service__editor',
88
+ )}
94
89
  >
95
- <div className="query-builder__dialog__header">
96
- <div className="query-builder__dialog__header__actions"></div>
90
+ <div className="bulk-service-registration__header">
91
+ <div className="bulk-service-registration__header__actions"></div>
97
92
  <button
98
- className="query-builder__dialog__header__action"
93
+ className="bulk-service-registration__header__action"
99
94
  tabIndex={-1}
100
- onClick={toggleMaximize}
101
- >
102
- {isMaximized ? (
103
- <EmptyWindowRestoreIcon />
104
- ) : (
105
- <WindowMaximizeIcon />
106
- )}
107
- </button>
108
- <button
109
- className="query-builder__dialog__header__action"
110
- tabIndex={-1}
111
- onClick={() => setOpen(false)}
95
+ onClick={() => setShowRegistrationModel(false)}
112
96
  >
113
97
  <TimesIcon />
114
98
  </button>
115
99
  </div>
116
- <BulkServiceRegistrationEditor />;
100
+ <div className="bulk-service-registration__panel__content__form">
101
+ <BulkServiceRegistrationEditor />
102
+ </div>
117
103
  </Modal>
118
104
  </Dialog>
119
105
  </div>
@@ -128,9 +114,11 @@ export const RegisterService = observer(
128
114
  data-testid={
129
115
  LEGEND_STUDIO_TEST_ID.SIDEBAR_PANEL_HEADER__CHANGES_COUNT
130
116
  }
131
- ></div>
117
+ >
118
+ {services.length}
119
+ </div>
132
120
  </div>
133
- <PanelContent>{renderTestables()}</PanelContent>
121
+ <PanelContent>{serviceItems()}</PanelContent>
134
122
  </div>
135
123
  </div>
136
124
  </div>
@@ -44,7 +44,7 @@ import {
44
44
  withProjectViewerStore,
45
45
  } from './ProjectViewerStoreProvider.js';
46
46
  import {
47
- type ViewerPathParams,
47
+ type ProjectViewerPathParams,
48
48
  generateSetupRoute,
49
49
  } from '../../application/LegendStudioNavigation.js';
50
50
  import { ProjectSearchCommand } from '../editor/command-center/ProjectSearchCommand.js';
@@ -72,7 +72,7 @@ import {
72
72
  import { EmbeddedQueryBuilder } from '../EmbeddedQueryBuilder.js';
73
73
 
74
74
  const ProjectViewerStatusBar = observer(() => {
75
- const params = useParams<ViewerPathParams>();
75
+ const params = useParams<ProjectViewerPathParams>();
76
76
  const viewerStore = useProjectViewerStore();
77
77
  const editorStore = useEditorStore();
78
78
  const applicationStore = useLegendStudioApplicationStore();
@@ -262,7 +262,7 @@ const ProjectViewerActivityBar = observer(() => {
262
262
  export const ProjectViewer = withEditorStore(
263
263
  withProjectViewerStore(
264
264
  observer(() => {
265
- const params = useParams<ViewerPathParams>();
265
+ const params = useParams<ProjectViewerPathParams>();
266
266
  const viewerStore = useProjectViewerStore();
267
267
  const editorStore = useEditorStore();
268
268
  const applicationStore = useApplicationStore();
@@ -38,7 +38,7 @@ import {
38
38
  AssistantIcon,
39
39
  } from '@finos/legend-art';
40
40
  import {
41
- type ReviewPathParams,
41
+ type WorkspaceReviewPathParams,
42
42
  generateSetupRoute,
43
43
  } from '../../application/LegendStudioNavigation.js';
44
44
  import { flowResult } from 'mobx';
@@ -194,7 +194,7 @@ const WorkspaceReviewExplorer = observer(() => {
194
194
  export const WorkspaceReview = withEditorStore(
195
195
  withWorkspaceReviewStore(
196
196
  observer(() => {
197
- const params = useParams<ReviewPathParams>();
197
+ const params = useParams<WorkspaceReviewPathParams>();
198
198
  const projectId = params.projectId;
199
199
  const reviewId = params.reviewId;
200
200
  const reviewStore = useWorkspaceReviewStore();
@@ -28,7 +28,7 @@ import {
28
28
  } from '@finos/legend-art';
29
29
  import { LEGEND_STUDIO_TEST_ID } from '../../application/LegendStudioTesting.js';
30
30
  import {
31
- type SetupPathParams,
31
+ type WorkspaceSetupPathParams,
32
32
  generateEditorRoute,
33
33
  LEGEND_STUDIO_ROUTE_PATTERN_TOKEN,
34
34
  } from '../../application/LegendStudioNavigation.js';
@@ -94,7 +94,7 @@ const withWorkspaceSetupStore = (WrappedComponent: React.FC): React.FC =>
94
94
 
95
95
  export const WorkspaceSetup = withWorkspaceSetupStore(
96
96
  observer(() => {
97
- const params = useParams<SetupPathParams>();
97
+ const params = useParams<WorkspaceSetupPathParams>();
98
98
  const projectId = params[LEGEND_STUDIO_ROUTE_PATTERN_TOKEN.PROJECT_ID];
99
99
  const workspaceId = params[LEGEND_STUDIO_ROUTE_PATTERN_TOKEN.WORKSPACE_ID];
100
100
  const groupWorkspaceId =
@@ -35,7 +35,6 @@ import { LEGEND_STUDIO_APP_EVENT } from '../../../../../application/LegendStudio
35
35
  import { Version } from '@finos/legend-server-sdlc';
36
36
  import {
37
37
  type Service,
38
- type ServiceRegistrationResult,
39
38
  type PureExecution,
40
39
  ServiceExecutionMode,
41
40
  buildLambdaVariableExpressions,
@@ -43,6 +42,7 @@ import {
43
42
  generateMultiplicityString,
44
43
  areMultiplicitiesEqual,
45
44
  Multiplicity,
45
+ type ServiceRegistrationSuccess,
46
46
  } from '@finos/legend-graph';
47
47
  import { ServiceRegistrationEnvironmentConfig } from '../../../../../application/LegendStudioApplicationConfig.js';
48
48
  import {
@@ -85,22 +85,19 @@ interface ServiceVersionOption {
85
85
  value: Version | string;
86
86
  }
87
87
 
88
- export class ServiceRegistrationState {
88
+ export class ServiceConfigState {
89
89
  readonly editorStore: EditorStore;
90
- readonly service: Service;
91
90
  readonly registrationOptions: ServiceRegistrationEnvironmentConfig[] = [];
92
91
  readonly registrationState = ActionState.create();
93
92
 
94
93
  serviceEnv?: string | undefined;
95
94
  serviceExecutionMode?: ServiceExecutionMode | undefined;
96
95
  projectVersion?: Version | string | undefined;
97
- activatePostRegistration = true;
98
96
  enableModesWithVersioning: boolean;
99
97
  TEMPORARY__useStoreModel = false;
100
98
 
101
99
  constructor(
102
100
  editorStore: EditorStore,
103
- service: Service,
104
101
  registrationOptions: ServiceRegistrationEnvironmentConfig[],
105
102
  enableModesWithVersioning: boolean,
106
103
  ) {
@@ -108,7 +105,6 @@ export class ServiceRegistrationState {
108
105
  serviceEnv: observable,
109
106
  serviceExecutionMode: observable,
110
107
  projectVersion: observable,
111
- activatePostRegistration: observable,
112
108
  enableModesWithVersioning: observable,
113
109
  TEMPORARY__useStoreModel: observable,
114
110
  executionModes: computed,
@@ -117,21 +113,18 @@ export class ServiceRegistrationState {
117
113
  setServiceEnv: action,
118
114
  setServiceExecutionMode: action,
119
115
  setProjectVersion: action,
120
- setActivatePostRegistration: action,
121
116
  setUseStoreModelWithFullInteractive: action,
122
117
  initialize: action,
123
118
  updateVersion: action,
124
119
  updateType: action,
125
120
  updateEnv: action,
126
- registerService: flow,
127
121
  });
128
122
 
129
123
  this.editorStore = editorStore;
130
- this.service = service;
131
124
  this.registrationOptions = registrationOptions;
132
125
  this.enableModesWithVersioning = enableModesWithVersioning;
133
- this.initialize();
134
126
  this.registrationState.setMessageFormatter(prettyCONSTName);
127
+ this.initialize();
135
128
  }
136
129
 
137
130
  get options(): ServiceRegistrationEnvironmentConfig[] {
@@ -195,10 +188,6 @@ export class ServiceRegistrationState {
195
188
  this.projectVersion = val;
196
189
  }
197
190
 
198
- setActivatePostRegistration(val: boolean): void {
199
- this.activatePostRegistration = val;
200
- }
201
-
202
191
  setUseStoreModelWithFullInteractive(val: boolean): void {
203
192
  this.TEMPORARY__useStoreModel = val;
204
193
  }
@@ -228,6 +217,30 @@ export class ServiceRegistrationState {
228
217
  this.setServiceEnv(val);
229
218
  this.setServiceExecutionMode(this.executionModes[0]);
230
219
  }
220
+ }
221
+
222
+ export class ServiceRegistrationState extends ServiceConfigState {
223
+ readonly service: Service;
224
+ activatePostRegistration = true;
225
+
226
+ constructor(
227
+ editorStore: EditorStore,
228
+ service: Service,
229
+ registrationOptions: ServiceRegistrationEnvironmentConfig[],
230
+ enableModesWithVersioning: boolean,
231
+ ) {
232
+ super(editorStore, registrationOptions, enableModesWithVersioning);
233
+ makeObservable(this, {
234
+ activatePostRegistration: observable,
235
+ setActivatePostRegistration: action,
236
+ registerService: flow,
237
+ });
238
+
239
+ this.service = service;
240
+ }
241
+ setActivatePostRegistration(val: boolean): void {
242
+ this.activatePostRegistration = val;
243
+ }
231
244
 
232
245
  *registerService(): GeneratorFn<void> {
233
246
  try {
@@ -257,7 +270,7 @@ export class ServiceRegistrationState {
257
270
  {
258
271
  TEMPORARY__useStoreModel: this.TEMPORARY__useStoreModel,
259
272
  },
260
- )) as ServiceRegistrationResult;
273
+ )) as ServiceRegistrationSuccess;
261
274
  if (this.activatePostRegistration) {
262
275
  this.registrationState.setMessage(`Activating service...`);
263
276
  yield this.editorStore.graphManagerState.graphManager.activateService(
@@ -103,6 +103,7 @@ export class ServiceTestParameterState {
103
103
  export class ServiceValueSpecificationTestParameterState extends ServiceTestParameterState {
104
104
  valueSpec: ValueSpecification;
105
105
  varExpression: VariableExpression;
106
+
106
107
  constructor(
107
108
  parameterValue: ParameterValue,
108
109
  editorStore: EditorStore,
@@ -147,6 +148,7 @@ export class ServiceValueSpecificationTestParameterState extends ServiceTestPara
147
148
  const mockValue = generateVariableExpressionMockValue(
148
149
  this.varExpression,
149
150
  this.editorStore.graphManagerState.graph,
151
+ this.editorStore.changeDetectionState.observerContext,
150
152
  );
151
153
  if (mockValue) {
152
154
  this.updateValueSpecification(mockValue);
@@ -157,6 +159,7 @@ export class ServiceValueSpecificationTestParameterState extends ServiceTestPara
157
159
  export class ServiceTestSetupState {
158
160
  readonly editorStore: EditorStore;
159
161
  readonly testState: ServiceTestState;
162
+
160
163
  parameterValueStates: ServiceTestParameterState[] = [];
161
164
  newParameterValueName = '';
162
165
  showNewParameterModal = false;
@@ -294,6 +297,7 @@ export class ServiceTestSetupState {
294
297
  generateVariableExpressionMockValue(
295
298
  expression,
296
299
  this.editorStore.graphManagerState.graph,
300
+ this.editorStore.changeDetectionState.observerContext,
297
301
  ),
298
302
  );
299
303
  const paramValue = new ParameterValue();
@@ -380,6 +384,7 @@ export class ServiceTestSetupState {
380
384
  const mockValue = generateVariableExpressionMockValue(
381
385
  varExpression,
382
386
  this.editorStore.graphManagerState.graph,
387
+ this.editorStore.changeDetectionState.observerContext,
383
388
  );
384
389
  if (mockValue) {
385
390
  const paramValue = new ParameterValue();