@finos/legend-extension-dsl-service 0.0.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 (68) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +3 -0
  3. package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.d.ts +22 -0
  4. package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.d.ts.map +1 -0
  5. package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.js +59 -0
  6. package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.js.map +1 -0
  7. package/lib/components/studio/ServiceQueryEditor.d.ts +25 -0
  8. package/lib/components/studio/ServiceQueryEditor.d.ts.map +1 -0
  9. package/lib/components/studio/ServiceQueryEditor.js +190 -0
  10. package/lib/components/studio/ServiceQueryEditor.js.map +1 -0
  11. package/lib/components/studio/ServiceQueryEditorReviewAction.d.ts +19 -0
  12. package/lib/components/studio/ServiceQueryEditorReviewAction.d.ts.map +1 -0
  13. package/lib/components/studio/ServiceQueryEditorReviewAction.js +71 -0
  14. package/lib/components/studio/ServiceQueryEditorReviewAction.js.map +1 -0
  15. package/lib/components/studio/ServiceQueryEditorStoreProvider.d.ts +31 -0
  16. package/lib/components/studio/ServiceQueryEditorStoreProvider.d.ts.map +1 -0
  17. package/lib/components/studio/ServiceQueryEditorStoreProvider.js +40 -0
  18. package/lib/components/studio/ServiceQueryEditorStoreProvider.js.map +1 -0
  19. package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.d.ts +19 -0
  20. package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.d.ts.map +1 -0
  21. package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.js +69 -0
  22. package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.js.map +1 -0
  23. package/lib/components/studio/UpdateProjectServiceQuerySetup.d.ts +18 -0
  24. package/lib/components/studio/UpdateProjectServiceQuerySetup.d.ts.map +1 -0
  25. package/lib/components/studio/UpdateProjectServiceQuerySetup.js +182 -0
  26. package/lib/components/studio/UpdateProjectServiceQuerySetup.js.map +1 -0
  27. package/lib/components/studio/UpdateServiceQuerySetup.d.ts +18 -0
  28. package/lib/components/studio/UpdateServiceQuerySetup.d.ts.map +1 -0
  29. package/lib/components/studio/UpdateServiceQuerySetup.js +172 -0
  30. package/lib/components/studio/UpdateServiceQuerySetup.js.map +1 -0
  31. package/lib/index.css +17 -0
  32. package/lib/index.css.map +1 -0
  33. package/lib/index.d.ts +17 -0
  34. package/lib/index.d.ts.map +1 -0
  35. package/lib/index.js +17 -0
  36. package/lib/index.js.map +1 -0
  37. package/lib/package.json +84 -0
  38. package/lib/stores/studio/DSL_Service_LegendStudioRouter.d.ts +53 -0
  39. package/lib/stores/studio/DSL_Service_LegendStudioRouter.d.ts.map +1 -0
  40. package/lib/stores/studio/DSL_Service_LegendStudioRouter.js +62 -0
  41. package/lib/stores/studio/DSL_Service_LegendStudioRouter.js.map +1 -0
  42. package/lib/stores/studio/ServiceQueryEditorStore.d.ts +64 -0
  43. package/lib/stores/studio/ServiceQueryEditorStore.d.ts.map +1 -0
  44. package/lib/stores/studio/ServiceQueryEditorStore.js +260 -0
  45. package/lib/stores/studio/ServiceQueryEditorStore.js.map +1 -0
  46. package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.d.ts +46 -0
  47. package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.d.ts.map +1 -0
  48. package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.js +184 -0
  49. package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.js.map +1 -0
  50. package/lib/stores/studio/UpdateServiceQuerySetupStore.d.ts +48 -0
  51. package/lib/stores/studio/UpdateServiceQuerySetupStore.d.ts.map +1 -0
  52. package/lib/stores/studio/UpdateServiceQuerySetupStore.js +184 -0
  53. package/lib/stores/studio/UpdateServiceQuerySetupStore.js.map +1 -0
  54. package/package.json +84 -0
  55. package/src/components/studio/DSL_Service_LegendStudioApplicationPlugin.tsx +71 -0
  56. package/src/components/studio/ServiceQueryEditor.tsx +551 -0
  57. package/src/components/studio/ServiceQueryEditorReviewAction.tsx +172 -0
  58. package/src/components/studio/ServiceQueryEditorStoreProvider.tsx +89 -0
  59. package/src/components/studio/ServiceQueryEditorWorkspaceStatus.tsx +121 -0
  60. package/src/components/studio/UpdateProjectServiceQuerySetup.tsx +479 -0
  61. package/src/components/studio/UpdateServiceQuerySetup.tsx +476 -0
  62. package/src/index.ts +17 -0
  63. package/src/stores/studio/DSL_Service_LegendStudioRouter.ts +159 -0
  64. package/src/stores/studio/ServiceQueryEditorStore.ts +487 -0
  65. package/src/stores/studio/UpdateProjectServiceQuerySetupStore.ts +281 -0
  66. package/src/stores/studio/UpdateServiceQuerySetupStore.ts +314 -0
  67. package/tsconfig.json +58 -0
  68. package/tsconfig.package.json +38 -0
@@ -0,0 +1,551 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { useEffect, useRef, useState } from 'react';
18
+ import { flushSync } from 'react-dom';
19
+ import { useParams } from 'react-router';
20
+ import { flowResult } from 'mobx';
21
+ import { observer } from 'mobx-react-lite';
22
+ import { useApplicationStore } from '@finos/legend-application';
23
+ import {
24
+ type SelectComponent,
25
+ BlankPanelContent,
26
+ CustomSelectorInput,
27
+ Dialog,
28
+ ExternalLinkSquareIcon,
29
+ Panel,
30
+ PanelLoadingIndicator,
31
+ PlusIcon,
32
+ RobotIcon,
33
+ RocketIcon,
34
+ SaveIcon,
35
+ clsx,
36
+ CheckSquareIcon,
37
+ SquareIcon,
38
+ } from '@finos/legend-art';
39
+ import {
40
+ type ProjectServiceQueryUpdaterPathParams,
41
+ type ServiceQueryUpdaterPathParams,
42
+ DSL_SERVICE_PATH_PARAM_TOKEN,
43
+ generateServiceQueryUpdaterRoute,
44
+ generateProjectServiceQueryUpdaterRoute,
45
+ } from '../../stores/studio/DSL_Service_LegendStudioRouter.js';
46
+ import {
47
+ ProjectServiceQueryUpdaterStoreProvider,
48
+ ServiceQueryUpdaterStoreProvider,
49
+ useServiceQueryEditorStore,
50
+ } from './ServiceQueryEditorStoreProvider.js';
51
+ import { QueryBuilder } from '@finos/legend-query-builder';
52
+ import {
53
+ ELEMENT_PATH_DELIMITER,
54
+ extractElementNameFromPath,
55
+ resolvePackagePathAndElementName,
56
+ validate_ServicePattern,
57
+ } from '@finos/legend-graph';
58
+ import {
59
+ type ServiceRegistrationEnvironmentConfig,
60
+ generateEditorRoute,
61
+ useLegendStudioApplicationStore,
62
+ } from '@finos/legend-application-studio';
63
+ import { guaranteeNonEmptyString, uuid } from '@finos/legend-shared';
64
+ import { WorkspaceType } from '@finos/legend-server-sdlc';
65
+ import { ServiceQueryEditorReviewAction } from './ServiceQueryEditorReviewAction.js';
66
+ import { ServiceQueryEditorWorkspaceStatus } from './ServiceQueryEditorWorkspaceStatus.js';
67
+
68
+ const NewServiceModal = observer(() => {
69
+ const editorStore = useServiceQueryEditorStore();
70
+ const applicationStore = useApplicationStore();
71
+ const [packagePath] = resolvePackagePathAndElementName(
72
+ editorStore.service.path,
73
+ );
74
+ const servicePackagePath = guaranteeNonEmptyString(packagePath);
75
+ const pathRef = useRef<HTMLInputElement>(null);
76
+
77
+ // service name
78
+ const [serviceName, setServiceName] = useState<string>('MyNewService');
79
+ const servicePath = `${servicePackagePath}${ELEMENT_PATH_DELIMITER}${serviceName}`;
80
+ const elementAlreadyExists =
81
+ editorStore.graphManagerState.graph.allOwnElements
82
+ .map((s) => s.path)
83
+ .includes(servicePackagePath + ELEMENT_PATH_DELIMITER + serviceName);
84
+ const changeName: React.ChangeEventHandler<HTMLInputElement> = (event) =>
85
+ setServiceName(event.target.value);
86
+
87
+ // pattern
88
+ const [pattern, setPattern] = useState<string>(`/${uuid()}`);
89
+ const changePattern: React.ChangeEventHandler<HTMLInputElement> = (event) =>
90
+ setPattern(event.target.value);
91
+ const patternValidationResult = validate_ServicePattern(pattern);
92
+
93
+ // actions
94
+ const handleEnter = (): void => pathRef.current?.focus();
95
+ const create = (): void => {
96
+ if (!elementAlreadyExists && !patternValidationResult) {
97
+ editorStore.updateServiceQuery();
98
+ const serviceEntity =
99
+ editorStore.graphManagerState.graphManager.elementToEntity(
100
+ editorStore.service,
101
+ {
102
+ pruneSourceInformation: true,
103
+ },
104
+ );
105
+ serviceEntity.path = servicePath;
106
+ // NOTE: this does look a bit sketchy, but it's simple
107
+ serviceEntity.content.name = serviceName;
108
+ serviceEntity.content.pattern = pattern;
109
+
110
+ flowResult(
111
+ editorStore.saveWorkspace(serviceEntity, true, (): void => {
112
+ applicationStore.navigator.jumpTo(
113
+ generateProjectServiceQueryUpdaterRoute(
114
+ editorStore.sdlcState.activeProject.projectId,
115
+ editorStore.sdlcState.activeWorkspace.workspaceId,
116
+ servicePath,
117
+ ),
118
+ );
119
+ }),
120
+ ).catch(applicationStore.alertUnhandledError);
121
+ }
122
+ };
123
+ const onSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
124
+ event.preventDefault();
125
+ create();
126
+ };
127
+ const onClose = (): void => editorStore.setShowNewServiceModal(false);
128
+
129
+ return (
130
+ <Dialog
131
+ open={editorStore.showNewServiceModal}
132
+ onClose={onClose}
133
+ TransitionProps={{
134
+ onEnter: handleEnter,
135
+ }}
136
+ PaperProps={{
137
+ classes: {
138
+ root: 'search-modal__inner-container',
139
+ },
140
+ }}
141
+ >
142
+ <form onSubmit={onSubmit} className="modal search-modal modal--dark">
143
+ <div className="modal__title">Create New Service</div>
144
+ <Panel>
145
+ <div className="panel__content__form">
146
+ <div className="panel__content__form__section">
147
+ <div className="panel__content__form__section__header__label">
148
+ Service Name
149
+ </div>
150
+ <div className="input-group">
151
+ <input
152
+ ref={pathRef}
153
+ className="input input--dark input-group__input"
154
+ value={serviceName}
155
+ spellCheck={false}
156
+ onChange={changeName}
157
+ placeholder={`Enter a name, use ${ELEMENT_PATH_DELIMITER} to create new package(s) for the service`}
158
+ />
159
+ {elementAlreadyExists && (
160
+ <div className="input-group__error-message">
161
+ Element with same path already exists
162
+ </div>
163
+ )}
164
+ </div>
165
+ </div>
166
+ <div className="panel__content__form__section">
167
+ <div className="panel__content__form__section__header__label">
168
+ Service URL Pattern
169
+ </div>
170
+ <div className="input-group">
171
+ <input
172
+ className="input input--dark input-group__input"
173
+ value={pattern}
174
+ spellCheck={false}
175
+ onChange={changePattern}
176
+ placeholder="Enter as service URL pattern, e.g. /myService"
177
+ />
178
+ {patternValidationResult && (
179
+ <div className="input-group__error-message">
180
+ URL pattern is not valid
181
+ </div>
182
+ )}
183
+ </div>
184
+ </div>
185
+ </div>
186
+ </Panel>
187
+ <div className="search-modal__actions">
188
+ <button
189
+ className="btn btn--dark"
190
+ disabled={elementAlreadyExists}
191
+ onClick={create}
192
+ >
193
+ Create
194
+ </button>
195
+ </div>
196
+ </form>
197
+ </Dialog>
198
+ );
199
+ });
200
+
201
+ type ServiceRegistrationEnvironmentConfigOption = {
202
+ label: string;
203
+ value: ServiceRegistrationEnvironmentConfig;
204
+ };
205
+ const buildServiceRegistrationEnvironmentConfigOption = (
206
+ value: ServiceRegistrationEnvironmentConfig,
207
+ ): ServiceRegistrationEnvironmentConfigOption => ({
208
+ label: value.env.toUpperCase(),
209
+ value,
210
+ });
211
+ const formatServiceRegistrationEnvironmentConfigOptionLabel = (
212
+ option: ServiceRegistrationEnvironmentConfigOption,
213
+ ): React.ReactNode => (
214
+ <div className="service-query-editor__registration-env-config__option">
215
+ <div className="service-query-editor__registration-env-config__option">
216
+ {option.label}
217
+ </div>
218
+ <div className="service-query-editor__registration-env-config__option__url">
219
+ {option.value.executionUrl}
220
+ </div>
221
+ </div>
222
+ );
223
+
224
+ const RegisterServiceModal = observer(() => {
225
+ const editorStore = useServiceQueryEditorStore();
226
+ const applicationStore = useApplicationStore();
227
+ const envConfigSelectorRef = useRef<SelectComponent>(null);
228
+
229
+ const envConfigOptions = editorStore.serviceRegistrationEnvConfigs.map(
230
+ buildServiceRegistrationEnvironmentConfigOption,
231
+ );
232
+ const selectedEnvConfigOption =
233
+ editorStore.currentServiceRegistrationEnvConfig
234
+ ? buildServiceRegistrationEnvironmentConfigOption(
235
+ editorStore.currentServiceRegistrationEnvConfig,
236
+ )
237
+ : null;
238
+ const onEnvConfigChange = (
239
+ val: ServiceRegistrationEnvironmentConfigOption | null,
240
+ ): void => {
241
+ editorStore.setCurrentServiceRegistrationEnvConfig(val?.value);
242
+ };
243
+
244
+ // pattern
245
+ const patternRef = useRef<HTMLInputElement>(null);
246
+ const [pattern, setPattern] = useState<string>(editorStore.service.pattern);
247
+ const [overridePattern, setOverridePattern] = useState<boolean>(false);
248
+ const toggleOverridePattern = (): void => {
249
+ const newVal = !overridePattern;
250
+ flushSync(() => {
251
+ setOverridePattern(newVal);
252
+ setPattern(editorStore.service.pattern);
253
+ });
254
+ if (newVal) {
255
+ patternRef.current?.focus();
256
+ }
257
+ };
258
+ const changePattern: React.ChangeEventHandler<HTMLInputElement> = (event) => {
259
+ if (overridePattern) {
260
+ setPattern(event.target.value);
261
+ }
262
+ };
263
+ const patternValidationResult = validate_ServicePattern(pattern);
264
+
265
+ // actions
266
+ const handleEnter = (): void => envConfigSelectorRef.current?.focus();
267
+ const registerService = (): void => {
268
+ if (editorStore.currentServiceRegistrationEnvConfig) {
269
+ flowResult(
270
+ editorStore.registerService(overridePattern ? pattern : undefined),
271
+ ).catch(applicationStore.alertUnhandledError);
272
+ }
273
+ };
274
+ const onSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
275
+ event.preventDefault();
276
+ registerService();
277
+ };
278
+ const onClose = (): void =>
279
+ editorStore.setShowServiceRegistrationModal(false);
280
+
281
+ return (
282
+ <Dialog
283
+ open={editorStore.showServiceRegistrationModal}
284
+ onClose={onClose}
285
+ TransitionProps={{
286
+ onEnter: handleEnter,
287
+ }}
288
+ PaperProps={{
289
+ classes: {
290
+ root: 'search-modal__inner-container',
291
+ },
292
+ }}
293
+ >
294
+ <form onSubmit={onSubmit} className="modal search-modal modal--dark">
295
+ <div className="modal__title">Register Service</div>
296
+ <Panel>
297
+ <div className="panel__content__form">
298
+ <div className="panel__content__form__section">
299
+ <div className="panel__content__form__section__header__label">
300
+ Environment
301
+ </div>
302
+ <CustomSelectorInput
303
+ ref={envConfigSelectorRef}
304
+ options={envConfigOptions}
305
+ onChange={onEnvConfigChange}
306
+ value={selectedEnvConfigOption}
307
+ darkMode={true}
308
+ isClearable={true}
309
+ escapeClearsValue={true}
310
+ placeholder="Choose a registration environment"
311
+ formatOptionLabel={
312
+ formatServiceRegistrationEnvironmentConfigOptionLabel
313
+ }
314
+ />
315
+ </div>
316
+ <div className="panel__content__form__section">
317
+ <div className="panel__content__form__section__header__label">
318
+ Service URL Pattern
319
+ </div>
320
+ <div className="service-query-editor__registration__pattern">
321
+ <div className="input-group">
322
+ <input
323
+ ref={patternRef}
324
+ className="input input--dark input-group__input"
325
+ value={pattern}
326
+ disabled={!overridePattern}
327
+ spellCheck={false}
328
+ onChange={changePattern}
329
+ placeholder="Enter as service URL pattern, e.g. /myService"
330
+ />
331
+ {patternValidationResult && (
332
+ <div className="input-group__error-message">
333
+ URL pattern is not valid
334
+ </div>
335
+ )}
336
+ </div>
337
+ <div className="panel__content__form__section__toggler service-query-editor__registration__pattern__override">
338
+ <button
339
+ type="button" // prevent this toggler being activated on form submission
340
+ className={clsx(
341
+ 'panel__content__form__section__toggler__btn',
342
+ {
343
+ 'panel__content__form__section__toggler__btn--toggled':
344
+ overridePattern,
345
+ },
346
+ )}
347
+ onClick={toggleOverridePattern}
348
+ >
349
+ {overridePattern ? <CheckSquareIcon /> : <SquareIcon />}
350
+ </button>
351
+ <div className="panel__content__form__section__toggler__prompt">
352
+ Override
353
+ </div>
354
+ </div>
355
+ </div>
356
+ </div>
357
+ </div>
358
+ </Panel>
359
+ <div className="search-modal__actions">
360
+ <button
361
+ className="btn btn--dark"
362
+ disabled={
363
+ !editorStore.currentServiceRegistrationEnvConfig ||
364
+ editorStore.registerServiceState.isInProgress
365
+ }
366
+ onClick={registerService}
367
+ >
368
+ Register
369
+ </button>
370
+ </div>
371
+ </form>
372
+ </Dialog>
373
+ );
374
+ });
375
+
376
+ const ServiceQueryEditorHeaderContent = observer(() => {
377
+ const editorStore = useServiceQueryEditorStore();
378
+ const applicationStore = useLegendStudioApplicationStore();
379
+ const viewProject = (): void =>
380
+ applicationStore.navigator.openNewWindow(
381
+ applicationStore.navigator.generateLocation(
382
+ generateEditorRoute(
383
+ editorStore.sdlcState.activeProject.projectId,
384
+ editorStore.sdlcState.activeWorkspace.workspaceId,
385
+ WorkspaceType.GROUP,
386
+ ),
387
+ ),
388
+ );
389
+ const showNewServiceModal = (): void =>
390
+ editorStore.setShowNewServiceModal(true);
391
+ const saveWorkspace = (): void => {
392
+ editorStore.updateServiceQuery();
393
+ const serviceEntity =
394
+ editorStore.graphManagerState.graphManager.elementToEntity(
395
+ editorStore.service,
396
+ {
397
+ pruneSourceInformation: true,
398
+ },
399
+ );
400
+ flowResult(
401
+ editorStore.saveWorkspace(serviceEntity, false, (): void => {
402
+ applicationStore.navigator.jumpTo(
403
+ generateServiceQueryUpdaterRoute(
404
+ editorStore.projectConfigurationEditorState
405
+ .currentProjectConfiguration.groupId,
406
+ editorStore.projectConfigurationEditorState
407
+ .currentProjectConfiguration.artifactId,
408
+ editorStore.service.path,
409
+ editorStore.sdlcState.activeWorkspace.workspaceId,
410
+ ),
411
+ );
412
+ }),
413
+ ).catch(applicationStore.alertUnhandledError);
414
+ };
415
+
416
+ // register service
417
+ const showServiceRegistrationModal = (): void =>
418
+ editorStore.setShowServiceRegistrationModal(true);
419
+ const canRegisterService = Boolean(
420
+ editorStore.applicationStore.config.options
421
+ .TEMPORARY__serviceRegistrationConfig.length,
422
+ );
423
+
424
+ return (
425
+ <div className="service-query-editor__header__content">
426
+ <div className="service-query-editor__header__content__main">
427
+ <div className="service-query-editor__header__label service-query-editor__header__label--service-query">
428
+ <RobotIcon className="service-query-editor__header__label__icon" />
429
+ {extractElementNameFromPath(editorStore.service.path)}
430
+ </div>
431
+ </div>
432
+
433
+ <div className="service-query-editor__header__actions">
434
+ <button
435
+ className="service-query-editor__header__action service-query-editor__header__action--simple btn--dark"
436
+ tabIndex={-1}
437
+ disabled={!canRegisterService}
438
+ title="Register service"
439
+ onClick={showServiceRegistrationModal}
440
+ >
441
+ <RocketIcon />
442
+ </button>
443
+ {canRegisterService && editorStore.showServiceRegistrationModal && (
444
+ <RegisterServiceModal />
445
+ )}
446
+ <div className="service-query-editor__header__actions__divider" />
447
+ <ServiceQueryEditorWorkspaceStatus />
448
+ <button
449
+ className="service-query-editor__header__action service-query-editor__header__action--simple btn--dark"
450
+ tabIndex={-1}
451
+ title="View project"
452
+ onClick={viewProject}
453
+ >
454
+ <ExternalLinkSquareIcon />
455
+ </button>
456
+ <div className="service-query-editor__header__actions__divider" />
457
+ <ServiceQueryEditorReviewAction />
458
+ <button
459
+ className="service-query-editor__header__action service-query-editor__header__action--simple btn--dark"
460
+ tabIndex={-1}
461
+ title="Save as a new service"
462
+ onClick={showNewServiceModal}
463
+ >
464
+ <PlusIcon />
465
+ </button>
466
+ {editorStore.showNewServiceModal && <NewServiceModal />}
467
+ <button
468
+ className="service-query-editor__header__action service-query-editor__header__action--simple btn--dark"
469
+ tabIndex={-1}
470
+ // TODO: we should disable this when we have change detection for query builder
471
+ // See https://github.com/finos/legend-studio/pull/1456
472
+ onClick={saveWorkspace}
473
+ title="Save workspace"
474
+ >
475
+ <SaveIcon />
476
+ </button>
477
+ </div>
478
+ </div>
479
+ );
480
+ });
481
+
482
+ export const ServiceQueryEditor = observer(() => {
483
+ const applicationStore = useApplicationStore();
484
+ const editorStore = useServiceQueryEditorStore();
485
+
486
+ useEffect(() => {
487
+ flowResult(editorStore.initializeWithServiceQuery()).catch(
488
+ applicationStore.alertUnhandledError,
489
+ );
490
+ }, [editorStore, applicationStore]);
491
+
492
+ return (
493
+ <div className="service-query-editor">
494
+ <div className="service-query-editor__header">
495
+ {editorStore.queryBuilderState && editorStore._service && (
496
+ <ServiceQueryEditorHeaderContent />
497
+ )}
498
+ </div>
499
+ <div className="service-query-editor__content">
500
+ <PanelLoadingIndicator isLoading={editorStore.initState.isInProgress} />
501
+ {editorStore.queryBuilderState && (
502
+ <QueryBuilder queryBuilderState={editorStore.queryBuilderState} />
503
+ )}
504
+ {!editorStore.queryBuilderState && (
505
+ <BlankPanelContent>
506
+ {editorStore.initState.message ??
507
+ editorStore.graphManagerState.systemBuildState.message ??
508
+ editorStore.graphManagerState.dependenciesBuildState.message ??
509
+ editorStore.graphManagerState.generationsBuildState.message ??
510
+ editorStore.graphManagerState.graphBuildState.message}
511
+ </BlankPanelContent>
512
+ )}
513
+ </div>
514
+ </div>
515
+ );
516
+ });
517
+
518
+ export const ServiceQueryUpdater = observer(() => {
519
+ const params = useParams<ServiceQueryUpdaterPathParams>();
520
+ const serviceCoordinates =
521
+ params[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_COORDINATES];
522
+ const groupWorkspaceId =
523
+ params[DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID];
524
+
525
+ return (
526
+ <ServiceQueryUpdaterStoreProvider
527
+ serviceCoordinates={serviceCoordinates}
528
+ groupWorkspaceId={groupWorkspaceId}
529
+ >
530
+ <ServiceQueryEditor />
531
+ </ServiceQueryUpdaterStoreProvider>
532
+ );
533
+ });
534
+
535
+ export const ProjectServiceQueryUpdater = observer(() => {
536
+ const params = useParams<ProjectServiceQueryUpdaterPathParams>();
537
+ const projectId = params[DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID];
538
+ const groupWorkspaceId =
539
+ params[DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID];
540
+ const servicePath = params[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_PATH];
541
+
542
+ return (
543
+ <ProjectServiceQueryUpdaterStoreProvider
544
+ projectId={projectId}
545
+ groupWorkspaceId={groupWorkspaceId}
546
+ servicePath={servicePath}
547
+ >
548
+ <ServiceQueryEditor />
549
+ </ProjectServiceQueryUpdaterStoreProvider>
550
+ );
551
+ });