@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.
- package/LICENSE +201 -0
- package/README.md +3 -0
- package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.d.ts +22 -0
- package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.d.ts.map +1 -0
- package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.js +59 -0
- package/lib/components/studio/DSL_Service_LegendStudioApplicationPlugin.js.map +1 -0
- package/lib/components/studio/ServiceQueryEditor.d.ts +25 -0
- package/lib/components/studio/ServiceQueryEditor.d.ts.map +1 -0
- package/lib/components/studio/ServiceQueryEditor.js +190 -0
- package/lib/components/studio/ServiceQueryEditor.js.map +1 -0
- package/lib/components/studio/ServiceQueryEditorReviewAction.d.ts +19 -0
- package/lib/components/studio/ServiceQueryEditorReviewAction.d.ts.map +1 -0
- package/lib/components/studio/ServiceQueryEditorReviewAction.js +71 -0
- package/lib/components/studio/ServiceQueryEditorReviewAction.js.map +1 -0
- package/lib/components/studio/ServiceQueryEditorStoreProvider.d.ts +31 -0
- package/lib/components/studio/ServiceQueryEditorStoreProvider.d.ts.map +1 -0
- package/lib/components/studio/ServiceQueryEditorStoreProvider.js +40 -0
- package/lib/components/studio/ServiceQueryEditorStoreProvider.js.map +1 -0
- package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.d.ts +19 -0
- package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.d.ts.map +1 -0
- package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.js +69 -0
- package/lib/components/studio/ServiceQueryEditorWorkspaceStatus.js.map +1 -0
- package/lib/components/studio/UpdateProjectServiceQuerySetup.d.ts +18 -0
- package/lib/components/studio/UpdateProjectServiceQuerySetup.d.ts.map +1 -0
- package/lib/components/studio/UpdateProjectServiceQuerySetup.js +182 -0
- package/lib/components/studio/UpdateProjectServiceQuerySetup.js.map +1 -0
- package/lib/components/studio/UpdateServiceQuerySetup.d.ts +18 -0
- package/lib/components/studio/UpdateServiceQuerySetup.d.ts.map +1 -0
- package/lib/components/studio/UpdateServiceQuerySetup.js +172 -0
- package/lib/components/studio/UpdateServiceQuerySetup.js.map +1 -0
- package/lib/index.css +17 -0
- package/lib/index.css.map +1 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +17 -0
- package/lib/index.js.map +1 -0
- package/lib/package.json +84 -0
- package/lib/stores/studio/DSL_Service_LegendStudioRouter.d.ts +53 -0
- package/lib/stores/studio/DSL_Service_LegendStudioRouter.d.ts.map +1 -0
- package/lib/stores/studio/DSL_Service_LegendStudioRouter.js +62 -0
- package/lib/stores/studio/DSL_Service_LegendStudioRouter.js.map +1 -0
- package/lib/stores/studio/ServiceQueryEditorStore.d.ts +64 -0
- package/lib/stores/studio/ServiceQueryEditorStore.d.ts.map +1 -0
- package/lib/stores/studio/ServiceQueryEditorStore.js +260 -0
- package/lib/stores/studio/ServiceQueryEditorStore.js.map +1 -0
- package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.d.ts +46 -0
- package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.d.ts.map +1 -0
- package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.js +184 -0
- package/lib/stores/studio/UpdateProjectServiceQuerySetupStore.js.map +1 -0
- package/lib/stores/studio/UpdateServiceQuerySetupStore.d.ts +48 -0
- package/lib/stores/studio/UpdateServiceQuerySetupStore.d.ts.map +1 -0
- package/lib/stores/studio/UpdateServiceQuerySetupStore.js +184 -0
- package/lib/stores/studio/UpdateServiceQuerySetupStore.js.map +1 -0
- package/package.json +84 -0
- package/src/components/studio/DSL_Service_LegendStudioApplicationPlugin.tsx +71 -0
- package/src/components/studio/ServiceQueryEditor.tsx +551 -0
- package/src/components/studio/ServiceQueryEditorReviewAction.tsx +172 -0
- package/src/components/studio/ServiceQueryEditorStoreProvider.tsx +89 -0
- package/src/components/studio/ServiceQueryEditorWorkspaceStatus.tsx +121 -0
- package/src/components/studio/UpdateProjectServiceQuerySetup.tsx +479 -0
- package/src/components/studio/UpdateServiceQuerySetup.tsx +476 -0
- package/src/index.ts +17 -0
- package/src/stores/studio/DSL_Service_LegendStudioRouter.ts +159 -0
- package/src/stores/studio/ServiceQueryEditorStore.ts +487 -0
- package/src/stores/studio/UpdateProjectServiceQuerySetupStore.ts +281 -0
- package/src/stores/studio/UpdateServiceQuerySetupStore.ts +314 -0
- package/tsconfig.json +58 -0
- package/tsconfig.package.json +38 -0
|
@@ -0,0 +1,476 @@
|
|
|
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
|
+
createContext,
|
|
19
|
+
useContext,
|
|
20
|
+
useEffect,
|
|
21
|
+
useMemo,
|
|
22
|
+
useState,
|
|
23
|
+
useRef,
|
|
24
|
+
} from 'react';
|
|
25
|
+
import { observer, useLocalObservable } from 'mobx-react-lite';
|
|
26
|
+
import { debounce, guaranteeNonNullable } from '@finos/legend-shared';
|
|
27
|
+
import { useSDLCServerClient, WorkspaceType } from '@finos/legend-server-sdlc';
|
|
28
|
+
import {
|
|
29
|
+
type WorkspaceOption,
|
|
30
|
+
ActivityBarMenu,
|
|
31
|
+
buildWorkspaceOption,
|
|
32
|
+
LEGEND_STUDIO_TEST_ID,
|
|
33
|
+
useLegendStudioApplicationStore,
|
|
34
|
+
} from '@finos/legend-application-studio';
|
|
35
|
+
import { UpdateServiceQuerySetupStore } from '../../stores/studio/UpdateServiceQuerySetupStore.js';
|
|
36
|
+
import {
|
|
37
|
+
type ProjectData,
|
|
38
|
+
useDepotServerClient,
|
|
39
|
+
} from '@finos/legend-server-depot';
|
|
40
|
+
import { useParams } from 'react-router';
|
|
41
|
+
import {
|
|
42
|
+
type ServiceQueryUpdaterSetupPathParams,
|
|
43
|
+
generateServiceQueryUpdaterRoute,
|
|
44
|
+
} from '../../stores/studio/DSL_Service_LegendStudioRouter.js';
|
|
45
|
+
import { flowResult } from 'mobx';
|
|
46
|
+
import {
|
|
47
|
+
type ServiceInfo,
|
|
48
|
+
type ServiceOption,
|
|
49
|
+
buildServiceOption,
|
|
50
|
+
formatServiceOptionLabel,
|
|
51
|
+
} from '@finos/legend-query-builder';
|
|
52
|
+
import {
|
|
53
|
+
CircleNotchIcon,
|
|
54
|
+
clsx,
|
|
55
|
+
compareLabelFn,
|
|
56
|
+
createFilter,
|
|
57
|
+
CustomSelectorInput,
|
|
58
|
+
Dialog,
|
|
59
|
+
ErrorIcon,
|
|
60
|
+
GitBranchIcon,
|
|
61
|
+
Panel,
|
|
62
|
+
PanelLoadingIndicator,
|
|
63
|
+
PlusIcon,
|
|
64
|
+
PURE_ServiceIcon,
|
|
65
|
+
UserIcon,
|
|
66
|
+
UsersIcon,
|
|
67
|
+
} from '@finos/legend-art';
|
|
68
|
+
|
|
69
|
+
const UpdateServiceQuerySetupStoreContext = createContext<
|
|
70
|
+
UpdateServiceQuerySetupStore | undefined
|
|
71
|
+
>(undefined);
|
|
72
|
+
|
|
73
|
+
const UpdateServiceQuerySetupStoreProvider: React.FC<{
|
|
74
|
+
children: React.ReactNode;
|
|
75
|
+
}> = ({ children }) => {
|
|
76
|
+
const applicationStore = useLegendStudioApplicationStore();
|
|
77
|
+
const sdlcServerClient = useSDLCServerClient();
|
|
78
|
+
const depotServerClient = useDepotServerClient();
|
|
79
|
+
const store = useLocalObservable(
|
|
80
|
+
() =>
|
|
81
|
+
new UpdateServiceQuerySetupStore(
|
|
82
|
+
applicationStore,
|
|
83
|
+
sdlcServerClient,
|
|
84
|
+
depotServerClient,
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
return (
|
|
88
|
+
<UpdateServiceQuerySetupStoreContext.Provider value={store}>
|
|
89
|
+
{children}
|
|
90
|
+
</UpdateServiceQuerySetupStoreContext.Provider>
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const useUpdateServiceQuerySetupStore = (): UpdateServiceQuerySetupStore =>
|
|
95
|
+
guaranteeNonNullable(
|
|
96
|
+
useContext(UpdateServiceQuerySetupStoreContext),
|
|
97
|
+
`Can't find service query updater store in context`,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const withUpdateServiceQuerySetupStore = (
|
|
101
|
+
WrappedComponent: React.FC,
|
|
102
|
+
): React.FC =>
|
|
103
|
+
function WithUpdateServiceQuerySetupStore() {
|
|
104
|
+
return (
|
|
105
|
+
<UpdateServiceQuerySetupStoreProvider>
|
|
106
|
+
<WrappedComponent />
|
|
107
|
+
</UpdateServiceQuerySetupStoreProvider>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const CreateWorkspaceModal = observer(
|
|
112
|
+
(props: {
|
|
113
|
+
selectedProject: ProjectData;
|
|
114
|
+
selectedSnapService: ServiceInfo;
|
|
115
|
+
}) => {
|
|
116
|
+
const { selectedProject, selectedSnapService } = props;
|
|
117
|
+
const setupStore = useUpdateServiceQuerySetupStore();
|
|
118
|
+
const applicationStore = useLegendStudioApplicationStore();
|
|
119
|
+
const workspaceNameInputRef = useRef<HTMLInputElement>(null);
|
|
120
|
+
const [workspaceName, setWorkspaceName] = useState('');
|
|
121
|
+
|
|
122
|
+
const workspaceAlreadyExists = Boolean(
|
|
123
|
+
setupStore.groupWorkspaces.find(
|
|
124
|
+
(workspace) => workspace.workspaceId === workspaceName,
|
|
125
|
+
),
|
|
126
|
+
);
|
|
127
|
+
const createWorkspace = (): void => {
|
|
128
|
+
if (workspaceName && !workspaceAlreadyExists) {
|
|
129
|
+
flowResult(
|
|
130
|
+
setupStore.createWorkspace(
|
|
131
|
+
selectedProject.projectId,
|
|
132
|
+
workspaceName,
|
|
133
|
+
selectedSnapService.path,
|
|
134
|
+
),
|
|
135
|
+
).catch(applicationStore.alertUnhandledError);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const changeWorkspaceName: React.ChangeEventHandler<HTMLInputElement> = (
|
|
139
|
+
event,
|
|
140
|
+
) => setWorkspaceName(event.target.value);
|
|
141
|
+
|
|
142
|
+
const handleEnter = (): void => {
|
|
143
|
+
workspaceNameInputRef.current?.focus();
|
|
144
|
+
};
|
|
145
|
+
const onClose = (): void => {
|
|
146
|
+
setupStore.setShowCreateWorkspaceModal(false);
|
|
147
|
+
};
|
|
148
|
+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
createWorkspace();
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Dialog
|
|
155
|
+
open={setupStore.showCreateWorkspaceModal}
|
|
156
|
+
onClose={onClose}
|
|
157
|
+
TransitionProps={{
|
|
158
|
+
onEnter: handleEnter,
|
|
159
|
+
}}
|
|
160
|
+
classes={{ container: 'search-modal__container' }}
|
|
161
|
+
PaperProps={{ classes: { root: 'search-modal__inner-container' } }}
|
|
162
|
+
>
|
|
163
|
+
<form
|
|
164
|
+
onSubmit={handleSubmit}
|
|
165
|
+
className="modal modal--dark search-modal"
|
|
166
|
+
>
|
|
167
|
+
<div className="modal__title">Create New Workspace</div>
|
|
168
|
+
<Panel>
|
|
169
|
+
<PanelLoadingIndicator
|
|
170
|
+
isLoading={setupStore.createWorkspaceState.isInProgress}
|
|
171
|
+
/>
|
|
172
|
+
<div className="panel__content--full">
|
|
173
|
+
<div className="input-group">
|
|
174
|
+
<input
|
|
175
|
+
className="input input--dark input-group__input"
|
|
176
|
+
ref={workspaceNameInputRef}
|
|
177
|
+
spellCheck={false}
|
|
178
|
+
disabled={setupStore.createWorkspaceState.isInProgress}
|
|
179
|
+
placeholder="MyWorkspace"
|
|
180
|
+
value={workspaceName}
|
|
181
|
+
onChange={changeWorkspaceName}
|
|
182
|
+
/>
|
|
183
|
+
{workspaceAlreadyExists && (
|
|
184
|
+
<div className="input-group__error-message">
|
|
185
|
+
Workspace with same name already exists
|
|
186
|
+
</div>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
</Panel>
|
|
191
|
+
<div className="search-modal__actions">
|
|
192
|
+
<button
|
|
193
|
+
disabled={
|
|
194
|
+
setupStore.createWorkspaceState.isInProgress ||
|
|
195
|
+
!workspaceName ||
|
|
196
|
+
workspaceAlreadyExists
|
|
197
|
+
}
|
|
198
|
+
className="btn btn--dark"
|
|
199
|
+
>
|
|
200
|
+
Create
|
|
201
|
+
</button>
|
|
202
|
+
</div>
|
|
203
|
+
</form>
|
|
204
|
+
</Dialog>
|
|
205
|
+
);
|
|
206
|
+
},
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
export const UpdateServiceQuerySetup = withUpdateServiceQuerySetupStore(
|
|
210
|
+
observer(() => {
|
|
211
|
+
const params = useParams<ServiceQueryUpdaterSetupPathParams>();
|
|
212
|
+
const { serviceCoordinates } = params;
|
|
213
|
+
const setupStore = useUpdateServiceQuerySetupStore();
|
|
214
|
+
const applicationStore = useLegendStudioApplicationStore();
|
|
215
|
+
const [serviceSearchText, setServiceSearchText] = useState('');
|
|
216
|
+
|
|
217
|
+
// action
|
|
218
|
+
const disableProceedButton =
|
|
219
|
+
!setupStore.currentProject ||
|
|
220
|
+
!setupStore.currentGroupWorkspace ||
|
|
221
|
+
!setupStore.currentWorkspaceService;
|
|
222
|
+
const handleProceed = (): void => {
|
|
223
|
+
if (
|
|
224
|
+
setupStore.currentProject &&
|
|
225
|
+
setupStore.currentGroupWorkspace &&
|
|
226
|
+
setupStore.currentWorkspaceService
|
|
227
|
+
) {
|
|
228
|
+
applicationStore.navigator.goTo(
|
|
229
|
+
generateServiceQueryUpdaterRoute(
|
|
230
|
+
setupStore.currentProject.groupId,
|
|
231
|
+
setupStore.currentProject.artifactId,
|
|
232
|
+
setupStore.currentWorkspaceService.path,
|
|
233
|
+
setupStore.currentGroupWorkspace.workspaceId,
|
|
234
|
+
),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// services
|
|
240
|
+
const serviceOptions = setupStore.services.map(buildServiceOption);
|
|
241
|
+
const selectedServiceOption = setupStore.currentSnapshotService
|
|
242
|
+
? buildServiceOption(setupStore.currentSnapshotService)
|
|
243
|
+
: null;
|
|
244
|
+
const onServiceOptionChange = (option: ServiceOption | null): void => {
|
|
245
|
+
if (option) {
|
|
246
|
+
flowResult(
|
|
247
|
+
setupStore.changeService(
|
|
248
|
+
option.value.groupId,
|
|
249
|
+
option.value.artifactId,
|
|
250
|
+
option.value.path,
|
|
251
|
+
),
|
|
252
|
+
).catch(applicationStore.alertUnhandledError);
|
|
253
|
+
} else {
|
|
254
|
+
setupStore.resetCurrentService();
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
const serviceFilterOption = createFilter({
|
|
258
|
+
ignoreCase: true,
|
|
259
|
+
ignoreAccents: false,
|
|
260
|
+
stringify: (option: ServiceOption): string =>
|
|
261
|
+
// NOTE: account for label, path, and URL pattern
|
|
262
|
+
`${option.label} - ${option.value.urlPattern ?? ''} - ${
|
|
263
|
+
option.value.path
|
|
264
|
+
}`,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// service search text
|
|
268
|
+
const debouncedLoadServices = useMemo(
|
|
269
|
+
() =>
|
|
270
|
+
debounce((input: string): void => {
|
|
271
|
+
flowResult(setupStore.loadServices(input)).catch(
|
|
272
|
+
applicationStore.alertUnhandledError,
|
|
273
|
+
);
|
|
274
|
+
}, 500),
|
|
275
|
+
[applicationStore, setupStore],
|
|
276
|
+
);
|
|
277
|
+
const onServiceSearchTextChange = (value: string): void => {
|
|
278
|
+
if (value !== serviceSearchText) {
|
|
279
|
+
setServiceSearchText(value);
|
|
280
|
+
debouncedLoadServices.cancel();
|
|
281
|
+
debouncedLoadServices(value);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// workspaces
|
|
286
|
+
const workspaceOptions = setupStore.groupWorkspaces
|
|
287
|
+
.map(buildWorkspaceOption)
|
|
288
|
+
.sort(compareLabelFn);
|
|
289
|
+
const selectedOption = setupStore.currentGroupWorkspace
|
|
290
|
+
? buildWorkspaceOption(setupStore.currentGroupWorkspace)
|
|
291
|
+
: null;
|
|
292
|
+
const onWorkspaceChange = (option: WorkspaceOption | null): void => {
|
|
293
|
+
if (option) {
|
|
294
|
+
if (setupStore.currentSnapshotService) {
|
|
295
|
+
flowResult(
|
|
296
|
+
setupStore.changeWorkspace(
|
|
297
|
+
option.value,
|
|
298
|
+
setupStore.currentSnapshotService.path,
|
|
299
|
+
),
|
|
300
|
+
).catch(applicationStore.alertUnhandledError);
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
setupStore.resetCurrentGroupWorkspace();
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
const showCreateWorkspaceModal = (): void =>
|
|
307
|
+
setupStore.setShowCreateWorkspaceModal(true);
|
|
308
|
+
const formatWorkspaceOptionLabel = (
|
|
309
|
+
option: WorkspaceOption,
|
|
310
|
+
): React.ReactNode => {
|
|
311
|
+
const isCurrentOptionInvalid =
|
|
312
|
+
// we can only check the current workspace
|
|
313
|
+
setupStore.currentGroupWorkspace === option.value &&
|
|
314
|
+
!setupStore.currentWorkspaceService &&
|
|
315
|
+
!setupStore.checkWorkspaceCompatibilityState.isInProgress;
|
|
316
|
+
return (
|
|
317
|
+
<div
|
|
318
|
+
className="workspace-selector__option"
|
|
319
|
+
title={
|
|
320
|
+
isCurrentOptionInvalid
|
|
321
|
+
? `Selected workspace does not have the specified service${
|
|
322
|
+
setupStore.currentSnapshotService
|
|
323
|
+
? ` '${setupStore.currentSnapshotService.path}'`
|
|
324
|
+
: ''
|
|
325
|
+
}\nPlease select another appropriate workspace or create and use a new workspace`
|
|
326
|
+
: setupStore.checkWorkspaceCompatibilityState.isInProgress
|
|
327
|
+
? `Checking if the specified service is present in the workspace`
|
|
328
|
+
: undefined
|
|
329
|
+
}
|
|
330
|
+
>
|
|
331
|
+
<div className="workspace-selector__option__icon">
|
|
332
|
+
{option.value.workspaceType === WorkspaceType.GROUP ? (
|
|
333
|
+
<UsersIcon />
|
|
334
|
+
) : (
|
|
335
|
+
<UserIcon />
|
|
336
|
+
)}
|
|
337
|
+
</div>
|
|
338
|
+
<div
|
|
339
|
+
className={clsx('workspace-selector__option__name', {
|
|
340
|
+
'service-query-setup__workspace-selector__option__name--invalid':
|
|
341
|
+
isCurrentOptionInvalid,
|
|
342
|
+
})}
|
|
343
|
+
>
|
|
344
|
+
{option.label}
|
|
345
|
+
{isCurrentOptionInvalid && <ErrorIcon />}
|
|
346
|
+
{setupStore.checkWorkspaceCompatibilityState.isInProgress && (
|
|
347
|
+
<CircleNotchIcon className="service-query-setup__workspace-selector__option__loading-indicator" />
|
|
348
|
+
)}
|
|
349
|
+
</div>
|
|
350
|
+
</div>
|
|
351
|
+
);
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
useEffect(() => {
|
|
355
|
+
flowResult(setupStore.loadServices('')).catch(
|
|
356
|
+
applicationStore.alertUnhandledError,
|
|
357
|
+
);
|
|
358
|
+
}, [setupStore, applicationStore]);
|
|
359
|
+
|
|
360
|
+
useEffect(() => {
|
|
361
|
+
setupStore.initialize(serviceCoordinates);
|
|
362
|
+
}, [setupStore, serviceCoordinates]);
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<div className="app__page">
|
|
366
|
+
<div className="service-query-setup">
|
|
367
|
+
<div className="service-query-setup__body">
|
|
368
|
+
<div className="activity-bar">
|
|
369
|
+
<ActivityBarMenu />
|
|
370
|
+
</div>
|
|
371
|
+
<div
|
|
372
|
+
className="service-query-setup__content"
|
|
373
|
+
data-testid={LEGEND_STUDIO_TEST_ID.SETUP__CONTENT}
|
|
374
|
+
>
|
|
375
|
+
<div className="service-query-setup__content__main">
|
|
376
|
+
<div className="service-query-setup__title">
|
|
377
|
+
<div className="service-query-setup__title__header">
|
|
378
|
+
Update Service Query
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
<div className="service-query-setup__selector">
|
|
382
|
+
<div
|
|
383
|
+
className="service-query-setup__selector__icon"
|
|
384
|
+
title="service"
|
|
385
|
+
>
|
|
386
|
+
<PURE_ServiceIcon />
|
|
387
|
+
</div>
|
|
388
|
+
<CustomSelectorInput
|
|
389
|
+
className="service-query-setup__selector__input"
|
|
390
|
+
options={serviceOptions}
|
|
391
|
+
isLoading={setupStore.loadServicesState.isInProgress}
|
|
392
|
+
onInputChange={onServiceSearchTextChange}
|
|
393
|
+
inputValue={serviceSearchText}
|
|
394
|
+
value={selectedServiceOption}
|
|
395
|
+
onChange={onServiceOptionChange}
|
|
396
|
+
placeholder="Search for service..."
|
|
397
|
+
darkMode={true}
|
|
398
|
+
isClearable={true}
|
|
399
|
+
escapeClearsValue={true}
|
|
400
|
+
filterOption={serviceFilterOption}
|
|
401
|
+
formatOptionLabel={formatServiceOptionLabel}
|
|
402
|
+
/>
|
|
403
|
+
</div>
|
|
404
|
+
<div className="service-query-setup__selector">
|
|
405
|
+
<div
|
|
406
|
+
className="service-query-setup__selector__icon"
|
|
407
|
+
title="workspace"
|
|
408
|
+
>
|
|
409
|
+
<GitBranchIcon className="service-query-setup__selector__icon--workspace" />
|
|
410
|
+
</div>
|
|
411
|
+
<CustomSelectorInput
|
|
412
|
+
className="service-query-setup__selector__input"
|
|
413
|
+
options={workspaceOptions}
|
|
414
|
+
disabled={
|
|
415
|
+
!setupStore.currentProject ||
|
|
416
|
+
!setupStore.currentSnapshotService ||
|
|
417
|
+
setupStore.loadWorkspacesState.isInProgress
|
|
418
|
+
}
|
|
419
|
+
isLoading={setupStore.loadWorkspacesState.isInProgress}
|
|
420
|
+
onChange={onWorkspaceChange}
|
|
421
|
+
formatOptionLabel={formatWorkspaceOptionLabel}
|
|
422
|
+
value={selectedOption}
|
|
423
|
+
placeholder={
|
|
424
|
+
setupStore.loadWorkspacesState.isInProgress
|
|
425
|
+
? 'Loading workspaces...'
|
|
426
|
+
: !setupStore.currentProject
|
|
427
|
+
? 'In order to select a workspace, a project must be selected'
|
|
428
|
+
: workspaceOptions.length
|
|
429
|
+
? 'Choose an existing workspace'
|
|
430
|
+
: setupStore.loadWorkspacesState.hasFailed
|
|
431
|
+
? `Can't fetch project workspaces. Please try again or select another service`
|
|
432
|
+
: 'You have no workspaces. Please create one to proceed...'
|
|
433
|
+
}
|
|
434
|
+
isClearable={true}
|
|
435
|
+
escapeClearsValue={true}
|
|
436
|
+
darkMode={true}
|
|
437
|
+
/>
|
|
438
|
+
<button
|
|
439
|
+
className="service-query-setup__selector__action btn--dark"
|
|
440
|
+
onClick={showCreateWorkspaceModal}
|
|
441
|
+
disabled={!setupStore.currentProject}
|
|
442
|
+
tabIndex={-1}
|
|
443
|
+
title="Create a Workspace"
|
|
444
|
+
>
|
|
445
|
+
<PlusIcon />
|
|
446
|
+
</button>
|
|
447
|
+
</div>
|
|
448
|
+
{setupStore.showCreateWorkspaceModal &&
|
|
449
|
+
setupStore.currentProject &&
|
|
450
|
+
setupStore.currentSnapshotService && (
|
|
451
|
+
<CreateWorkspaceModal
|
|
452
|
+
selectedProject={setupStore.currentProject}
|
|
453
|
+
selectedSnapService={setupStore.currentSnapshotService}
|
|
454
|
+
/>
|
|
455
|
+
)}
|
|
456
|
+
<div className="service-query-setup__actions">
|
|
457
|
+
<button
|
|
458
|
+
className="service-query-setup__next-btn btn--dark"
|
|
459
|
+
onClick={handleProceed}
|
|
460
|
+
disabled={disableProceedButton}
|
|
461
|
+
>
|
|
462
|
+
Edit Service Query
|
|
463
|
+
</button>
|
|
464
|
+
</div>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
<div
|
|
469
|
+
data-testid={LEGEND_STUDIO_TEST_ID.STATUS_BAR}
|
|
470
|
+
className="editor__status-bar"
|
|
471
|
+
/>
|
|
472
|
+
</div>
|
|
473
|
+
</div>
|
|
474
|
+
);
|
|
475
|
+
}),
|
|
476
|
+
);
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
export { DSL_Service_LegendStudioApplicationPlugin } from './components/studio/DSL_Service_LegendStudioApplicationPlugin.js';
|
|
@@ -0,0 +1,159 @@
|
|
|
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 { generateExtensionUrlPattern } from '@finos/legend-application';
|
|
18
|
+
import { assertTrue, guaranteeNonEmptyString } from '@finos/legend-shared';
|
|
19
|
+
import {
|
|
20
|
+
generateGAVCoordinates,
|
|
21
|
+
parseGACoordinates,
|
|
22
|
+
} from '@finos/legend-storage';
|
|
23
|
+
import { generatePath } from 'react-router';
|
|
24
|
+
|
|
25
|
+
const SERVICE_COORDINATE_DELIMITER = '@';
|
|
26
|
+
|
|
27
|
+
export const parseServiceCoordinates = (
|
|
28
|
+
val: string,
|
|
29
|
+
): {
|
|
30
|
+
servicePath: string;
|
|
31
|
+
groupId: string;
|
|
32
|
+
artifactId: string;
|
|
33
|
+
} => {
|
|
34
|
+
const parts = val.split(SERVICE_COORDINATE_DELIMITER);
|
|
35
|
+
assertTrue(
|
|
36
|
+
parts.length === 2,
|
|
37
|
+
`Can't parse service coordinates '${val}': expect the coordinates to follow format {servicePath}${SERVICE_COORDINATE_DELIMITER}{GACoordinates}`,
|
|
38
|
+
);
|
|
39
|
+
const { groupId, artifactId } = parseGACoordinates(
|
|
40
|
+
guaranteeNonEmptyString(
|
|
41
|
+
parts[1]?.trim(),
|
|
42
|
+
`Service coordinates GA coordinates are missing or empty`,
|
|
43
|
+
),
|
|
44
|
+
);
|
|
45
|
+
return {
|
|
46
|
+
groupId,
|
|
47
|
+
artifactId,
|
|
48
|
+
servicePath: guaranteeNonEmptyString(
|
|
49
|
+
parts[0]?.trim(),
|
|
50
|
+
`Service coordinates service path is missing or empty`,
|
|
51
|
+
),
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const generateServiceCoordinates = (
|
|
56
|
+
groupId: string,
|
|
57
|
+
artifactId: string,
|
|
58
|
+
servicePath: string,
|
|
59
|
+
): string =>
|
|
60
|
+
`${servicePath}${SERVICE_COORDINATE_DELIMITER}${generateGAVCoordinates(
|
|
61
|
+
groupId,
|
|
62
|
+
artifactId,
|
|
63
|
+
undefined,
|
|
64
|
+
)}`;
|
|
65
|
+
|
|
66
|
+
export enum DSL_SERVICE_PATH_PARAM_TOKEN {
|
|
67
|
+
SERVICE_COORDINATES = 'serviceCoordinates',
|
|
68
|
+
PROJECT_ID = 'projectId',
|
|
69
|
+
GROUP_WORKSPACE_ID = 'groupWorkspaceId',
|
|
70
|
+
SERVICE_PATH = 'servicePath',
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const DSL_SERVICE_LEGEND_STUDIO_ROUTE_PATTERN = Object.freeze({
|
|
74
|
+
UPDATE_SERVICE_QUERY_SETUP: `/update-service-query/:${DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_COORDINATES}?`,
|
|
75
|
+
UPDATE_SERVICE_QUERY: `/update-service-query/:${DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_COORDINATES}/:${DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID}`,
|
|
76
|
+
UPDATE_PROJECT_SERVICE_QUERY_SETUP: `/update-project-service-query/:${DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID}?`,
|
|
77
|
+
UPDATE_PROJECT_SERVICE_QUERY: `/update-project-service-query/:${DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID}/:${DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID}/:${DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_PATH}`,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
export interface ServiceQueryUpdaterSetupPathParams {
|
|
81
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_COORDINATES]?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const generateServiceQueryUpdaterSetupRoute = (
|
|
85
|
+
groupId?: string,
|
|
86
|
+
artifactId?: string,
|
|
87
|
+
servicePath?: string,
|
|
88
|
+
): string =>
|
|
89
|
+
generatePath(
|
|
90
|
+
generateExtensionUrlPattern(
|
|
91
|
+
DSL_SERVICE_LEGEND_STUDIO_ROUTE_PATTERN.UPDATE_SERVICE_QUERY_SETUP,
|
|
92
|
+
),
|
|
93
|
+
{
|
|
94
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_COORDINATES]:
|
|
95
|
+
groupId && artifactId && servicePath
|
|
96
|
+
? generateServiceCoordinates(groupId, artifactId, servicePath)
|
|
97
|
+
: undefined,
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
export interface ServiceQueryUpdaterPathParams {
|
|
102
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_COORDINATES]: string;
|
|
103
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID]: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const generateServiceQueryUpdaterRoute = (
|
|
107
|
+
groupId: string,
|
|
108
|
+
artifactId: string,
|
|
109
|
+
servicePath: string,
|
|
110
|
+
groupWorkspaceId: string,
|
|
111
|
+
): string =>
|
|
112
|
+
generatePath(
|
|
113
|
+
generateExtensionUrlPattern(
|
|
114
|
+
DSL_SERVICE_LEGEND_STUDIO_ROUTE_PATTERN.UPDATE_SERVICE_QUERY,
|
|
115
|
+
),
|
|
116
|
+
{
|
|
117
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_COORDINATES]:
|
|
118
|
+
generateServiceCoordinates(groupId, artifactId, servicePath),
|
|
119
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID]: groupWorkspaceId,
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
export interface ProjectServiceQueryUpdaterSetupPathParams {
|
|
124
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID]?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export const generateProjectServiceQueryUpdaterSetupRoute = (
|
|
128
|
+
projectId?: string,
|
|
129
|
+
): string =>
|
|
130
|
+
generatePath(
|
|
131
|
+
generateExtensionUrlPattern(
|
|
132
|
+
DSL_SERVICE_LEGEND_STUDIO_ROUTE_PATTERN.UPDATE_PROJECT_SERVICE_QUERY_SETUP,
|
|
133
|
+
),
|
|
134
|
+
{
|
|
135
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID]: projectId,
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
export interface ProjectServiceQueryUpdaterPathParams {
|
|
140
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID]: string;
|
|
141
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID]: string;
|
|
142
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_PATH]: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export const generateProjectServiceQueryUpdaterRoute = (
|
|
146
|
+
projectId: string,
|
|
147
|
+
groupWorkspaceId: string,
|
|
148
|
+
servicePath: string,
|
|
149
|
+
): string =>
|
|
150
|
+
generatePath(
|
|
151
|
+
generateExtensionUrlPattern(
|
|
152
|
+
DSL_SERVICE_LEGEND_STUDIO_ROUTE_PATTERN.UPDATE_PROJECT_SERVICE_QUERY,
|
|
153
|
+
),
|
|
154
|
+
{
|
|
155
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID]: projectId,
|
|
156
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID]: groupWorkspaceId,
|
|
157
|
+
[DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_PATH]: servicePath,
|
|
158
|
+
},
|
|
159
|
+
);
|