@finos/legend-application-studio 26.1.4 → 26.1.6
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/lib/__lib__/LegendStudioEvent.d.ts +1 -0
- package/lib/__lib__/LegendStudioEvent.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioEvent.js +1 -0
- package/lib/__lib__/LegendStudioEvent.js.map +1 -1
- package/lib/components/editor/ActivityBar.d.ts.map +1 -1
- package/lib/components/editor/ActivityBar.js +5 -1
- package/lib/components/editor/ActivityBar.js.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.d.ts +14 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.js +44 -16
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts +9 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js +60 -3
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js.map +1 -1
- package/package.json +5 -5
- package/src/__lib__/LegendStudioEvent.ts +1 -0
- package/src/components/editor/ActivityBar.tsx +12 -1
- package/src/components/editor/editor-group/service-editor/testable/ServiceTestsEditor.tsx +212 -41
- package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestEditorState.ts +116 -2
@@ -34,14 +34,26 @@ import {
|
|
34
34
|
Dialog,
|
35
35
|
RefreshIcon,
|
36
36
|
TimesIcon,
|
37
|
+
FilledWindowMaximizeIcon,
|
38
|
+
Modal,
|
39
|
+
ModalHeader,
|
40
|
+
ModalFooter,
|
41
|
+
ModalBody,
|
42
|
+
ModalTitle,
|
37
43
|
} from '@finos/legend-art';
|
38
44
|
import {
|
45
|
+
type Binding,
|
39
46
|
type ValueSpecification,
|
47
|
+
PrimitiveInstanceValue,
|
40
48
|
PrimitiveType,
|
41
49
|
PureMultiExecution,
|
42
50
|
} from '@finos/legend-graph';
|
43
|
-
import { BasicValueSpecificationEditor } from '@finos/legend-query-builder';
|
44
51
|
import {
|
52
|
+
BasicValueSpecificationEditor,
|
53
|
+
instanceValue_setValue,
|
54
|
+
} from '@finos/legend-query-builder';
|
55
|
+
import {
|
56
|
+
ContentType,
|
45
57
|
filterByType,
|
46
58
|
guaranteeNonNullable,
|
47
59
|
prettyCONSTName,
|
@@ -71,6 +83,10 @@ import {
|
|
71
83
|
TestAssertionEditor,
|
72
84
|
TestAssertionItem,
|
73
85
|
} from '../../testable/TestableSharedComponents.js';
|
86
|
+
import {
|
87
|
+
CODE_EDITOR_LANGUAGE,
|
88
|
+
CodeEditor,
|
89
|
+
} from '@finos/legend-lego/code-editor';
|
74
90
|
|
75
91
|
export const NewParameterModal = observer(
|
76
92
|
(props: { setupState: ServiceTestSetupState; isReadOnly: boolean }) => {
|
@@ -123,16 +139,106 @@ export const NewParameterModal = observer(
|
|
123
139
|
},
|
124
140
|
);
|
125
141
|
|
142
|
+
export const ExternalFormatParameterEditorModal = observer(
|
143
|
+
(props: {
|
144
|
+
paramState: ServiceValueSpecificationTestParameterState;
|
145
|
+
isReadOnly: boolean;
|
146
|
+
onClose: () => void;
|
147
|
+
updateParamValue: (val: string) => void;
|
148
|
+
bindingParamPair: {
|
149
|
+
binding: Binding;
|
150
|
+
param: string;
|
151
|
+
};
|
152
|
+
}) => {
|
153
|
+
const {
|
154
|
+
paramState,
|
155
|
+
isReadOnly,
|
156
|
+
onClose,
|
157
|
+
updateParamValue,
|
158
|
+
bindingParamPair,
|
159
|
+
} = props;
|
160
|
+
return (
|
161
|
+
<Dialog
|
162
|
+
open={true}
|
163
|
+
onClose={onClose}
|
164
|
+
classes={{ container: 'search-modal__container' }}
|
165
|
+
PaperProps={{ classes: { root: 'search-modal__inner-container' } }}
|
166
|
+
>
|
167
|
+
<Modal
|
168
|
+
darkMode={true}
|
169
|
+
className={clsx('editor-modal lambda-editor__popup__modal')}
|
170
|
+
>
|
171
|
+
<ModalHeader>
|
172
|
+
<ModalTitle title="Edit Parameter Value" />
|
173
|
+
</ModalHeader>
|
174
|
+
<ModalBody>
|
175
|
+
<div className="service-test-editor__setup__parameter__code-editor__container">
|
176
|
+
<div className="service-test-editor__setup__parameter__code-editor__container__content">
|
177
|
+
<CodeEditor
|
178
|
+
key={paramState.uuid}
|
179
|
+
inputValue={
|
180
|
+
(paramState.valueSpec as PrimitiveInstanceValue)
|
181
|
+
.values[0] as string
|
182
|
+
}
|
183
|
+
updateInput={updateParamValue}
|
184
|
+
isReadOnly={isReadOnly}
|
185
|
+
language={
|
186
|
+
bindingParamPair.binding.contentType ===
|
187
|
+
ContentType.APPLICATION_JSON.toString()
|
188
|
+
? CODE_EDITOR_LANGUAGE.JSON
|
189
|
+
: CODE_EDITOR_LANGUAGE.TEXT
|
190
|
+
}
|
191
|
+
/>
|
192
|
+
</div>
|
193
|
+
</div>
|
194
|
+
</ModalBody>
|
195
|
+
<ModalFooter>
|
196
|
+
<button className="btn btn--dark" onClick={onClose}>
|
197
|
+
Close
|
198
|
+
</button>
|
199
|
+
</ModalFooter>
|
200
|
+
</Modal>
|
201
|
+
</Dialog>
|
202
|
+
);
|
203
|
+
},
|
204
|
+
);
|
205
|
+
|
126
206
|
const ServiceTestParameterEditor = observer(
|
127
207
|
(props: {
|
128
208
|
isReadOnly: boolean;
|
129
209
|
paramState: ServiceValueSpecificationTestParameterState;
|
130
210
|
serviceTestState: ServiceTestState;
|
211
|
+
bindingParamPair:
|
212
|
+
| {
|
213
|
+
binding: Binding;
|
214
|
+
param: string;
|
215
|
+
}
|
216
|
+
| undefined;
|
131
217
|
}) => {
|
132
|
-
const { serviceTestState, paramState, isReadOnly } =
|
218
|
+
const { serviceTestState, paramState, isReadOnly, bindingParamPair } =
|
219
|
+
props;
|
220
|
+
const [showPopUp, setShowPopUp] = useState(false);
|
133
221
|
const setupState = serviceTestState.setupState;
|
134
222
|
const paramIsRequired =
|
135
223
|
paramState.varExpression.multiplicity.lowerBound > 0;
|
224
|
+
const type = bindingParamPair
|
225
|
+
? bindingParamPair.binding.contentType
|
226
|
+
: paramState.varExpression.genericType?.value.rawType.name ?? 'unknown';
|
227
|
+
|
228
|
+
const openInPopUp = (): void => setShowPopUp(!showPopUp);
|
229
|
+
const closePopUp = (): void => setShowPopUp(false);
|
230
|
+
const updateParamValue = (val: string): void => {
|
231
|
+
if (paramState.valueSpec instanceof PrimitiveInstanceValue) {
|
232
|
+
instanceValue_setValue(
|
233
|
+
paramState.valueSpec,
|
234
|
+
val,
|
235
|
+
0,
|
236
|
+
setupState.editorStore.changeDetectionState.observerContext,
|
237
|
+
);
|
238
|
+
paramState.updateValueSpecification(paramState.valueSpec);
|
239
|
+
}
|
240
|
+
};
|
241
|
+
|
136
242
|
return (
|
137
243
|
<div
|
138
244
|
key={paramState.parameterValue.name}
|
@@ -143,48 +249,107 @@ const ServiceTestParameterEditor = observer(
|
|
143
249
|
<button
|
144
250
|
className={clsx('type-tree__node__type__label', {})}
|
145
251
|
tabIndex={-1}
|
146
|
-
title={
|
147
|
-
paramState.varExpression.genericType?.value.rawType.name ?? ''
|
148
|
-
}
|
252
|
+
title={type}
|
149
253
|
>
|
150
|
-
{
|
151
|
-
'unknown'}
|
254
|
+
{type}
|
152
255
|
</button>
|
153
256
|
</div>
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
}
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
257
|
+
<>
|
258
|
+
{bindingParamPair ? (
|
259
|
+
<div className="service-test-editor__setup__parameter__code-editor">
|
260
|
+
<textarea
|
261
|
+
className="panel__content__form__section__textarea value-spec-editor__input"
|
262
|
+
spellCheck={false}
|
263
|
+
value={
|
264
|
+
(paramState.valueSpec as PrimitiveInstanceValue)
|
265
|
+
.values[0] as string
|
266
|
+
}
|
267
|
+
placeholder={
|
268
|
+
((paramState.valueSpec as PrimitiveInstanceValue)
|
269
|
+
.values[0] as string) === ''
|
270
|
+
? '(empty)'
|
271
|
+
: undefined
|
272
|
+
}
|
273
|
+
onChange={(event) => {
|
274
|
+
updateParamValue(event.target.value);
|
275
|
+
}}
|
276
|
+
/>
|
277
|
+
{showPopUp && (
|
278
|
+
<ExternalFormatParameterEditorModal
|
279
|
+
paramState={paramState}
|
280
|
+
isReadOnly={isReadOnly}
|
281
|
+
onClose={closePopUp}
|
282
|
+
updateParamValue={updateParamValue}
|
283
|
+
bindingParamPair={bindingParamPair}
|
284
|
+
/>
|
285
|
+
)}
|
286
|
+
<div className="service-test-editor__setup__parameter__value__actions">
|
287
|
+
<button
|
288
|
+
className={clsx(
|
289
|
+
'service-test-editor__setup__parameter__code-editor__expand-btn',
|
290
|
+
)}
|
291
|
+
onClick={openInPopUp}
|
292
|
+
tabIndex={-1}
|
293
|
+
title="Open in a popup..."
|
294
|
+
>
|
295
|
+
<FilledWindowMaximizeIcon />
|
296
|
+
</button>
|
297
|
+
<button
|
298
|
+
className={clsx(
|
299
|
+
'btn--icon btn--dark btn--sm service-test-editor__setup__parameter__code-editor__expand-btn',
|
300
|
+
)}
|
301
|
+
disabled={isReadOnly || paramIsRequired}
|
302
|
+
onClick={(): void =>
|
303
|
+
setupState.removeParamValueState(paramState)
|
304
|
+
}
|
305
|
+
tabIndex={-1}
|
306
|
+
title={
|
307
|
+
paramIsRequired ? 'Parameter Required' : 'Remove Parameter'
|
308
|
+
}
|
309
|
+
>
|
310
|
+
<TimesIcon />
|
311
|
+
</button>
|
312
|
+
</div>
|
313
|
+
</div>
|
314
|
+
) : (
|
315
|
+
<div className="service-test-editor__setup__parameter__value">
|
316
|
+
<BasicValueSpecificationEditor
|
317
|
+
valueSpecification={paramState.valueSpec}
|
318
|
+
setValueSpecification={(val: ValueSpecification): void => {
|
319
|
+
paramState.updateValueSpecification(val);
|
320
|
+
}}
|
321
|
+
graph={setupState.editorStore.graphManagerState.graph}
|
322
|
+
obseverContext={
|
323
|
+
setupState.editorStore.changeDetectionState.observerContext
|
324
|
+
}
|
325
|
+
typeCheckOption={{
|
326
|
+
expectedType:
|
327
|
+
paramState.varExpression.genericType?.value.rawType ??
|
328
|
+
PrimitiveType.STRING,
|
329
|
+
}}
|
330
|
+
className="query-builder__parameters__value__editor"
|
331
|
+
resetValue={(): void => {
|
332
|
+
paramState.resetValueSpec();
|
333
|
+
}}
|
334
|
+
/>
|
335
|
+
<div className="service-test-editor__setup__parameter__value__actions">
|
336
|
+
<button
|
337
|
+
className="btn--icon btn--dark btn--sm"
|
338
|
+
disabled={isReadOnly || paramIsRequired}
|
339
|
+
onClick={(): void =>
|
340
|
+
setupState.removeParamValueState(paramState)
|
341
|
+
}
|
342
|
+
tabIndex={-1}
|
343
|
+
title={
|
344
|
+
paramIsRequired ? 'Parameter Required' : 'Remove Parameter'
|
345
|
+
}
|
346
|
+
>
|
347
|
+
<TimesIcon />
|
348
|
+
</button>
|
349
|
+
</div>
|
350
|
+
</div>
|
351
|
+
)}
|
352
|
+
</>
|
188
353
|
</div>
|
189
354
|
);
|
190
355
|
},
|
@@ -338,6 +503,12 @@ const ServiceTestSetupEditor = observer(
|
|
338
503
|
isReadOnly={isReadOnly}
|
339
504
|
paramState={paramState}
|
340
505
|
serviceTestState={serviceTestState}
|
506
|
+
bindingParamPair={setupState
|
507
|
+
.getBindingWithParamFromQuery()
|
508
|
+
.find(
|
509
|
+
(pair) =>
|
510
|
+
pair.param === paramState.parameterValue.name,
|
511
|
+
)}
|
341
512
|
/>
|
342
513
|
))}
|
343
514
|
</div>
|
@@ -15,6 +15,7 @@
|
|
15
15
|
*/
|
16
16
|
|
17
17
|
import {
|
18
|
+
type Binding,
|
18
19
|
type ServiceTest,
|
19
20
|
type Service,
|
20
21
|
type ValueSpecification,
|
@@ -23,6 +24,13 @@ import {
|
|
23
24
|
buildLambdaVariableExpressions,
|
24
25
|
VariableExpression,
|
25
26
|
PureMultiExecution,
|
27
|
+
PackageableElementImplicitReference,
|
28
|
+
matchFunctionName,
|
29
|
+
isStubbed_RawLambda,
|
30
|
+
InstanceValue,
|
31
|
+
LambdaFunctionInstanceValue,
|
32
|
+
SimpleFunctionExpression,
|
33
|
+
CollectionInstanceValue,
|
26
34
|
} from '@finos/legend-graph';
|
27
35
|
import { action, flow, makeObservable, observable } from 'mobx';
|
28
36
|
import { TestableTestEditorState } from '../../testable/TestableEditorState.js';
|
@@ -37,6 +45,7 @@ import {
|
|
37
45
|
service_setSerializationFormat,
|
38
46
|
} from '../../../../../graph-modifier/DSL_Service_GraphModifierHelper.js';
|
39
47
|
import {
|
48
|
+
type PlainObject,
|
40
49
|
assertErrorThrown,
|
41
50
|
deleteEntry,
|
42
51
|
filterByType,
|
@@ -44,10 +53,15 @@ import {
|
|
44
53
|
isNonNullable,
|
45
54
|
returnUndefOnError,
|
46
55
|
uuid,
|
47
|
-
|
56
|
+
getNullableFirstEntry,
|
57
|
+
LogEvent,
|
48
58
|
} from '@finos/legend-shared';
|
49
59
|
import type { EditorStore } from '../../../../EditorStore.js';
|
50
|
-
import {
|
60
|
+
import {
|
61
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS,
|
62
|
+
generateVariableExpressionMockValue,
|
63
|
+
} from '@finos/legend-query-builder';
|
64
|
+
import { LEGEND_STUDIO_APP_EVENT } from '../../../../../../__lib__/LegendStudioEvent.js';
|
51
65
|
|
52
66
|
export enum SERIALIZATION_FORMAT {
|
53
67
|
PURE = 'PURE',
|
@@ -180,6 +194,7 @@ export class ServiceTestSetupState {
|
|
180
194
|
addServiceTestAssertKeys: action,
|
181
195
|
syncWithQuery: action,
|
182
196
|
removeParamValueState: action,
|
197
|
+
getBindingWithParamFromQuery: action,
|
183
198
|
});
|
184
199
|
this.parameterValueStates = this.buildParameterStates();
|
185
200
|
}
|
@@ -221,6 +236,105 @@ export class ServiceTestSetupState {
|
|
221
236
|
}));
|
222
237
|
}
|
223
238
|
|
239
|
+
getBindingWithParamFromQuery(): {
|
240
|
+
binding: Binding;
|
241
|
+
param: string;
|
242
|
+
}[] {
|
243
|
+
const query =
|
244
|
+
this.testState.suiteState.testableState.serviceEditorState.serviceQuery;
|
245
|
+
if (query && !isStubbed_RawLambda(query)) {
|
246
|
+
// safely pass unsupported funtions when building ValueSpecification from Rawlambda
|
247
|
+
try {
|
248
|
+
const valueSpec =
|
249
|
+
this.editorStore.graphManagerState.graphManager.buildValueSpecification(
|
250
|
+
this.editorStore.graphManagerState.graphManager.serializeRawValueSpecification(
|
251
|
+
query,
|
252
|
+
),
|
253
|
+
this.editorStore.graphManagerState.graph,
|
254
|
+
);
|
255
|
+
|
256
|
+
if (valueSpec instanceof LambdaFunctionInstanceValue) {
|
257
|
+
return this.getBindingWithParamRecursively(
|
258
|
+
valueSpec.values[0]?.expressionSequence[0],
|
259
|
+
);
|
260
|
+
}
|
261
|
+
} catch (error) {
|
262
|
+
this.editorStore.applicationStore.logService.error(
|
263
|
+
LogEvent.create(
|
264
|
+
LEGEND_STUDIO_APP_EVENT.TEST_DATA_GENERATION__SETUP__FAILURE,
|
265
|
+
),
|
266
|
+
error,
|
267
|
+
);
|
268
|
+
}
|
269
|
+
}
|
270
|
+
return [];
|
271
|
+
}
|
272
|
+
|
273
|
+
getBindingWithParamRecursively(expression: ValueSpecification | undefined): {
|
274
|
+
binding: Binding;
|
275
|
+
param: string;
|
276
|
+
}[] {
|
277
|
+
let currentExpression = expression;
|
278
|
+
const res: {
|
279
|
+
binding: Binding;
|
280
|
+
param: string;
|
281
|
+
}[] = [];
|
282
|
+
// use if statement to safely scan service query without breaking the app
|
283
|
+
while (currentExpression instanceof SimpleFunctionExpression) {
|
284
|
+
if (
|
285
|
+
matchFunctionName(
|
286
|
+
currentExpression.functionName,
|
287
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.INTERNALIZE,
|
288
|
+
) ||
|
289
|
+
matchFunctionName(
|
290
|
+
currentExpression.functionName,
|
291
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.GET_RUNTIME_WITH_MODEL_QUERY_CONNECTION,
|
292
|
+
)
|
293
|
+
) {
|
294
|
+
if (currentExpression.parametersValues[1] instanceof InstanceValue) {
|
295
|
+
if (
|
296
|
+
currentExpression.parametersValues[1].values[0] instanceof
|
297
|
+
PackageableElementImplicitReference<Binding> &&
|
298
|
+
currentExpression.parametersValues[2] instanceof VariableExpression
|
299
|
+
) {
|
300
|
+
res.push({
|
301
|
+
binding: currentExpression.parametersValues[1].values[0]
|
302
|
+
.value as Binding,
|
303
|
+
param: currentExpression.parametersValues[2].name,
|
304
|
+
});
|
305
|
+
}
|
306
|
+
}
|
307
|
+
currentExpression = currentExpression.parametersValues[1];
|
308
|
+
} else if (
|
309
|
+
matchFunctionName(
|
310
|
+
currentExpression.functionName,
|
311
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.FROM,
|
312
|
+
)
|
313
|
+
) {
|
314
|
+
currentExpression = currentExpression.parametersValues[2];
|
315
|
+
} else if (
|
316
|
+
matchFunctionName(
|
317
|
+
currentExpression.functionName,
|
318
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.MERGERUNTIMES,
|
319
|
+
)
|
320
|
+
) {
|
321
|
+
const collection = currentExpression.parametersValues[0];
|
322
|
+
if (collection instanceof CollectionInstanceValue) {
|
323
|
+
collection.values
|
324
|
+
.map((v) => this.getBindingWithParamRecursively(v))
|
325
|
+
.flat()
|
326
|
+
.map((p) => res.push(p));
|
327
|
+
}
|
328
|
+
currentExpression = collection;
|
329
|
+
} else {
|
330
|
+
currentExpression = getNullableFirstEntry(
|
331
|
+
currentExpression.parametersValues,
|
332
|
+
);
|
333
|
+
}
|
334
|
+
}
|
335
|
+
return res;
|
336
|
+
}
|
337
|
+
|
224
338
|
addServiceTestAssertKeys(val: string[]): void {
|
225
339
|
service_addAssertKeyForTest(this.testState.test, val);
|
226
340
|
}
|