@finos/legend-application-studio 28.3.3 → 28.3.5
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/components/editor/editor-group/data-editor/RelationalCSVDataEditor.d.ts +5 -0
- package/lib/components/editor/editor-group/data-editor/RelationalCSVDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.d.ts +4 -1
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.js +51 -3
- package/lib/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.js.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.d.ts +23 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js +101 -8
- package/lib/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.js.map +1 -1
- package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
- package/lib/components/editor/side-bar/Explorer.js +8 -2
- package/lib/components/editor/side-bar/Explorer.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts +38 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js +195 -6
- package/lib/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/ProjectOverviewState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/ProjectOverviewState.js +13 -4
- package/lib/stores/editor/sidebar-state/ProjectOverviewState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkspaceReviewState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js +8 -1
- package/lib/stores/editor/sidebar-state/WorkspaceReviewState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkspaceUpdaterState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/WorkspaceUpdaterState.js +11 -4
- package/lib/stores/editor/sidebar-state/WorkspaceUpdaterState.js.map +1 -1
- package/package.json +6 -6
- package/src/components/editor/editor-group/data-editor/RelationalCSVDataEditor.tsx +1 -1
- package/src/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.tsx +101 -7
- package/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx +296 -5
- package/src/components/editor/side-bar/Explorer.tsx +17 -0
- package/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts +337 -11
- package/src/stores/editor/sidebar-state/ProjectOverviewState.ts +14 -16
- package/src/stores/editor/sidebar-state/WorkspaceReviewState.ts +9 -5
- package/src/stores/editor/sidebar-state/WorkspaceUpdaterState.ts +11 -12
package/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx
CHANGED
@@ -39,20 +39,26 @@ import {
|
|
39
39
|
ResizablePanelGroup,
|
40
40
|
ResizablePanelSplitter,
|
41
41
|
ResizablePanelSplitterLine,
|
42
|
+
TimesIcon,
|
42
43
|
} from '@finos/legend-art';
|
43
44
|
import {
|
44
45
|
type IdentifiedConnection,
|
45
46
|
type ConnectionTestData,
|
46
47
|
type DataElement,
|
48
|
+
type ValueSpecification,
|
47
49
|
getAllIdentifiedServiceConnections,
|
48
50
|
DataElementReference,
|
49
51
|
PackageableElementExplicitReference,
|
52
|
+
Column,
|
50
53
|
} from '@finos/legend-graph';
|
51
54
|
import { observer } from 'mobx-react-lite';
|
52
55
|
import { forwardRef, useState } from 'react';
|
53
|
-
import
|
54
|
-
|
55
|
-
|
56
|
+
import {
|
57
|
+
createMockPrimitiveValueSpecificationFromRelationalDataType,
|
58
|
+
type ConnectionTestDataState,
|
59
|
+
type RowIdentifierState,
|
60
|
+
type ServiceTestDataState,
|
61
|
+
type TableRowIdentifierState,
|
56
62
|
} from '../../../../../stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.js';
|
57
63
|
import type { EmbeddedDataTypeOption } from '../../../../../stores/editor/editor-state/element-editor-state/data/DataEditorState.js';
|
58
64
|
import { EmbeddedDataEditor } from '../../data-editor/EmbeddedDataEditor.js';
|
@@ -64,11 +70,266 @@ import {
|
|
64
70
|
useApplicationStore,
|
65
71
|
} from '@finos/legend-application';
|
66
72
|
import { buildElementOption } from '@finos/legend-lego/graph-editor';
|
67
|
-
import {
|
73
|
+
import {
|
74
|
+
filterByType,
|
75
|
+
getNullableFirstEntry,
|
76
|
+
guaranteeNonNullable,
|
77
|
+
prettyCONSTName,
|
78
|
+
} from '@finos/legend-shared';
|
68
79
|
import type { DSL_Data_LegendStudioApplicationPlugin_Extension } from '../../../../../stores/extensions/DSL_Data_LegendStudioApplicationPlugin_Extension.js';
|
69
80
|
import { useEditorStore } from '../../../EditorStoreProvider.js';
|
70
|
-
import {
|
81
|
+
import {
|
82
|
+
BasicValueSpecificationEditor,
|
83
|
+
LambdaParameterValuesEditor,
|
84
|
+
} from '@finos/legend-query-builder';
|
71
85
|
import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../../__lib__/LegendStudioDocumentation.js';
|
86
|
+
import type { TableOption } from '../../data-editor/RelationalCSVDataEditor.js';
|
87
|
+
import { getPrimitiveTypeFromRelationalType } from '../../../../../stores/editor/utils/MockDataUtils.js';
|
88
|
+
|
89
|
+
export interface ColumnOption {
|
90
|
+
value: Column;
|
91
|
+
label: string;
|
92
|
+
}
|
93
|
+
|
94
|
+
export const RowIdentifierEditor = observer(
|
95
|
+
(props: {
|
96
|
+
tableRowIdentifierState: TableRowIdentifierState;
|
97
|
+
rowIdentifierState: RowIdentifierState;
|
98
|
+
}) => {
|
99
|
+
const { tableRowIdentifierState, rowIdentifierState } = props;
|
100
|
+
const columnOptions = tableRowIdentifierState.table.columns
|
101
|
+
.filter(filterByType(Column))
|
102
|
+
.map((_c) => ({
|
103
|
+
label: _c.name,
|
104
|
+
value: _c,
|
105
|
+
}));
|
106
|
+
const changeColumn = (val: ColumnOption): void => {
|
107
|
+
if (rowIdentifierState.column.name !== val.value.name) {
|
108
|
+
const valueSpec =
|
109
|
+
createMockPrimitiveValueSpecificationFromRelationalDataType(
|
110
|
+
guaranteeNonNullable(rowIdentifierState.column.type),
|
111
|
+
tableRowIdentifierState.connectionTestDataState.editorStore
|
112
|
+
.graphManagerState.graph,
|
113
|
+
tableRowIdentifierState.connectionTestDataState.editorStore
|
114
|
+
.changeDetectionState.observerContext,
|
115
|
+
);
|
116
|
+
if (valueSpec) {
|
117
|
+
rowIdentifierState.updateRowIdentifierValue(valueSpec);
|
118
|
+
rowIdentifierState.updateRowIdentifierColumn(val.value);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
};
|
122
|
+
|
123
|
+
const resetNode = (): void => {
|
124
|
+
const valueSpec =
|
125
|
+
createMockPrimitiveValueSpecificationFromRelationalDataType(
|
126
|
+
guaranteeNonNullable(rowIdentifierState.column.type),
|
127
|
+
tableRowIdentifierState.connectionTestDataState.editorStore
|
128
|
+
.graphManagerState.graph,
|
129
|
+
tableRowIdentifierState.connectionTestDataState.editorStore
|
130
|
+
.changeDetectionState.observerContext,
|
131
|
+
);
|
132
|
+
if (valueSpec) {
|
133
|
+
rowIdentifierState.updateRowIdentifierValue(valueSpec);
|
134
|
+
}
|
135
|
+
};
|
136
|
+
|
137
|
+
return (
|
138
|
+
<div className="panel__content__form__section__list">
|
139
|
+
<div className="panel__content__form__section__list__new-item">
|
140
|
+
<CustomSelectorInput
|
141
|
+
className="service-editor__owner__selector"
|
142
|
+
placeholder="Choose a column..."
|
143
|
+
options={columnOptions}
|
144
|
+
onChange={changeColumn}
|
145
|
+
value={{
|
146
|
+
label: rowIdentifierState.column.name,
|
147
|
+
|
148
|
+
value: rowIdentifierState.column,
|
149
|
+
}}
|
150
|
+
darkMode={true}
|
151
|
+
/>
|
152
|
+
<BasicValueSpecificationEditor
|
153
|
+
valueSpecification={rowIdentifierState.value}
|
154
|
+
setValueSpecification={(val: ValueSpecification): void => {
|
155
|
+
rowIdentifierState.updateRowIdentifierValue(val);
|
156
|
+
}}
|
157
|
+
graph={
|
158
|
+
tableRowIdentifierState.connectionTestDataState.editorStore
|
159
|
+
.graphManagerState.graph
|
160
|
+
}
|
161
|
+
obseverContext={
|
162
|
+
tableRowIdentifierState.connectionTestDataState.editorStore
|
163
|
+
.changeDetectionState.observerContext
|
164
|
+
}
|
165
|
+
typeCheckOption={{
|
166
|
+
expectedType: guaranteeNonNullable(
|
167
|
+
getPrimitiveTypeFromRelationalType(
|
168
|
+
guaranteeNonNullable(rowIdentifierState.column.type),
|
169
|
+
),
|
170
|
+
),
|
171
|
+
}}
|
172
|
+
resetValue={resetNode}
|
173
|
+
/>
|
174
|
+
<button
|
175
|
+
className="btn--icon btn--dark btn--sm"
|
176
|
+
onClick={(): void =>
|
177
|
+
tableRowIdentifierState.removeRowIdentifierState(
|
178
|
+
rowIdentifierState,
|
179
|
+
)
|
180
|
+
}
|
181
|
+
tabIndex={-1}
|
182
|
+
title={'Remove Row'}
|
183
|
+
>
|
184
|
+
<TimesIcon />
|
185
|
+
</button>
|
186
|
+
</div>
|
187
|
+
</div>
|
188
|
+
);
|
189
|
+
},
|
190
|
+
);
|
191
|
+
|
192
|
+
export const TableRowIdentifierEditor = observer(
|
193
|
+
(props: {
|
194
|
+
connectionTestDataState: ConnectionTestDataState;
|
195
|
+
tableRowIdentifierState: TableRowIdentifierState;
|
196
|
+
}) => {
|
197
|
+
const { connectionTestDataState, tableRowIdentifierState } = props;
|
198
|
+
const tables = connectionTestDataState.getAvailableTables();
|
199
|
+
const tableOptions = tables.map((_t) => ({
|
200
|
+
label: `${_t.schema.name}.${_t.name}`,
|
201
|
+
value: _t,
|
202
|
+
}));
|
203
|
+
|
204
|
+
const changeTable = (val: TableOption): void => {
|
205
|
+
if (tableRowIdentifierState.table !== val.value) {
|
206
|
+
tableRowIdentifierState.updateTable(val.value);
|
207
|
+
tableRowIdentifierState.setNewRowIdentifierState([]);
|
208
|
+
}
|
209
|
+
};
|
210
|
+
const addNewRow = (): void => {
|
211
|
+
tableRowIdentifierState.addNewRowIdentifierState(
|
212
|
+
guaranteeNonNullable(
|
213
|
+
tableRowIdentifierState.table.columns.filter(filterByType(Column))[0],
|
214
|
+
),
|
215
|
+
);
|
216
|
+
};
|
217
|
+
return (
|
218
|
+
<ModalBody className="lambda-parameter-values__modal__body">
|
219
|
+
<div className="panel__content__form__section">
|
220
|
+
<div className="panel__content__form__section__header__label">
|
221
|
+
Table
|
222
|
+
</div>
|
223
|
+
<div className="panel__content__form__section__header__prompt">
|
224
|
+
create seed data below based on root tables
|
225
|
+
</div>
|
226
|
+
<CustomSelectorInput
|
227
|
+
placeholder="Choose a root table..."
|
228
|
+
options={tableOptions}
|
229
|
+
onChange={changeTable}
|
230
|
+
value={{
|
231
|
+
label: `${tableRowIdentifierState.table.schema.name}.${tableRowIdentifierState.table.name}`,
|
232
|
+
|
233
|
+
value: tableRowIdentifierState.table,
|
234
|
+
}}
|
235
|
+
darkMode={true}
|
236
|
+
/>
|
237
|
+
</div>
|
238
|
+
<div className="panel__content__form__section">
|
239
|
+
<div className="panel__content__form__section__header__label">
|
240
|
+
Seed Data
|
241
|
+
</div>
|
242
|
+
<div className="panel__content__form__section__header__prompt">
|
243
|
+
create value for primary key column
|
244
|
+
</div>
|
245
|
+
{tableRowIdentifierState.rowIdentifierStates.map(
|
246
|
+
(rowIdentifierState) => (
|
247
|
+
<RowIdentifierEditor
|
248
|
+
key={rowIdentifierState._UUID}
|
249
|
+
tableRowIdentifierState={tableRowIdentifierState}
|
250
|
+
rowIdentifierState={rowIdentifierState}
|
251
|
+
/>
|
252
|
+
),
|
253
|
+
)}
|
254
|
+
<div className="panel__content__form__section__list__new-item__add">
|
255
|
+
<button
|
256
|
+
className="panel__content__form__section__list__new-item__add-btn btn btn--dark"
|
257
|
+
onClick={addNewRow}
|
258
|
+
tabIndex={-1}
|
259
|
+
title="Add Seed Data for column"
|
260
|
+
>
|
261
|
+
Add Row
|
262
|
+
</button>
|
263
|
+
</div>
|
264
|
+
</div>
|
265
|
+
</ModalBody>
|
266
|
+
);
|
267
|
+
},
|
268
|
+
);
|
269
|
+
|
270
|
+
export const SeedDataInputModal = observer(
|
271
|
+
(props: { connectionTestDataState: ConnectionTestDataState }) => {
|
272
|
+
const { connectionTestDataState } = props;
|
273
|
+
const applicationStore = useApplicationStore();
|
274
|
+
const useSeedDataInputModal = connectionTestDataState.useSeedDataInputModal;
|
275
|
+
const closeModal = (): void =>
|
276
|
+
connectionTestDataState.setUseSeedDataInputModal(false);
|
277
|
+
const generateWithSeedData = (): void => {
|
278
|
+
closeModal();
|
279
|
+
flowResult(connectionTestDataState.generateTestDataWithSeedData()).catch(
|
280
|
+
applicationStore.alertUnhandledError,
|
281
|
+
);
|
282
|
+
};
|
283
|
+
const addNewTable = (): void => {
|
284
|
+
const tables = connectionTestDataState.getAvailableTables();
|
285
|
+
if (tables[0]) {
|
286
|
+
connectionTestDataState.addNewTableIdentifierState(tables[0]);
|
287
|
+
}
|
288
|
+
};
|
289
|
+
|
290
|
+
return (
|
291
|
+
<Dialog
|
292
|
+
open={useSeedDataInputModal}
|
293
|
+
onClose={closeModal}
|
294
|
+
classes={{
|
295
|
+
root: 'editor-modal__root-container',
|
296
|
+
container: 'editor-modal__container',
|
297
|
+
paper: 'editor-modal__content',
|
298
|
+
}}
|
299
|
+
>
|
300
|
+
<Modal
|
301
|
+
darkMode={true}
|
302
|
+
className="editor-modal lambda-parameter-values__modal"
|
303
|
+
>
|
304
|
+
<ModalHeader title="Create Seed Data Input (BETA)" />
|
305
|
+
<ModalBody className="lambda-parameter-values__modal__body">
|
306
|
+
{connectionTestDataState.tableRowIdentifierStates.map(
|
307
|
+
(tableRowIdentifierState) => (
|
308
|
+
<TableRowIdentifierEditor
|
309
|
+
key={tableRowIdentifierState._UUID}
|
310
|
+
connectionTestDataState={connectionTestDataState}
|
311
|
+
tableRowIdentifierState={tableRowIdentifierState}
|
312
|
+
/>
|
313
|
+
),
|
314
|
+
)}
|
315
|
+
<button
|
316
|
+
className="panel__content__form__section__list__new-item__add-btn btn btn--dark"
|
317
|
+
onClick={addNewTable}
|
318
|
+
tabIndex={-1}
|
319
|
+
title="Add Seed Data for table"
|
320
|
+
>
|
321
|
+
Add a Different Table
|
322
|
+
</button>
|
323
|
+
</ModalBody>
|
324
|
+
<ModalFooter>
|
325
|
+
<ModalFooterButton onClick={closeModal} text="Close" />
|
326
|
+
<ModalFooterButton onClick={generateWithSeedData} text="Generate" />
|
327
|
+
</ModalFooter>
|
328
|
+
</Modal>
|
329
|
+
</Dialog>
|
330
|
+
);
|
331
|
+
},
|
332
|
+
);
|
72
333
|
|
73
334
|
export const UseDataElementModal = observer(
|
74
335
|
(props: { connectionTestDataState: ConnectionTestDataState }) => {
|
@@ -201,6 +462,17 @@ export const ConnectionTestDataEditor = observer(
|
|
201
462
|
}
|
202
463
|
};
|
203
464
|
|
465
|
+
const generateTestDataWithSeedData = (): void => {
|
466
|
+
connectionTestDataState.setUseSeedDataInputModal(true);
|
467
|
+
connectionTestDataState.setNewTableIdentifierState([]);
|
468
|
+
const table = getNullableFirstEntry(
|
469
|
+
connectionTestDataState.getAvailableTables(),
|
470
|
+
);
|
471
|
+
if (table) {
|
472
|
+
connectionTestDataState.addNewTableIdentifierState(table);
|
473
|
+
}
|
474
|
+
};
|
475
|
+
|
204
476
|
const generateQuerySchemas = (): void => {
|
205
477
|
flowResult(connectionTestDataState.generateQuerySchemas()).catch(
|
206
478
|
applicationStore.alertUnhandledError,
|
@@ -268,6 +540,16 @@ export const ConnectionTestDataEditor = observer(
|
|
268
540
|
>
|
269
541
|
Generate Query Schemas
|
270
542
|
</MenuContentItem>
|
543
|
+
<MenuContentItem
|
544
|
+
className="btn__dropdown-combo__option"
|
545
|
+
onClick={generateTestDataWithSeedData}
|
546
|
+
disabled={
|
547
|
+
connectionTestDataState
|
548
|
+
.generatingTestDataWithSeedDataState.isInProgress
|
549
|
+
}
|
550
|
+
>
|
551
|
+
Generate with Seed Data (Beta)
|
552
|
+
</MenuContentItem>
|
271
553
|
</MenuContent>
|
272
554
|
}
|
273
555
|
menuProps={{
|
@@ -316,6 +598,11 @@ export const ConnectionTestDataEditor = observer(
|
|
316
598
|
connectionTestDataState={connectionTestDataState}
|
317
599
|
/>
|
318
600
|
)}
|
601
|
+
{connectionTestDataState.useSeedDataInputModal && (
|
602
|
+
<SeedDataInputModal
|
603
|
+
connectionTestDataState={connectionTestDataState}
|
604
|
+
/>
|
605
|
+
)}
|
319
606
|
</div>
|
320
607
|
);
|
321
608
|
},
|
@@ -624,6 +911,10 @@ export const ServiceTestDataEditor = observer(
|
|
624
911
|
Boolean(
|
625
912
|
testDataState.selectedDataState?.generateSchemaQueryState
|
626
913
|
.isInProgress,
|
914
|
+
) ||
|
915
|
+
Boolean(
|
916
|
+
testDataState.selectedDataState
|
917
|
+
?.generatingTestDataWithSeedDataState.isInProgress,
|
627
918
|
)
|
628
919
|
}
|
629
920
|
/>
|
@@ -113,6 +113,7 @@ import {
|
|
113
113
|
type FunctionActivatorConfiguration,
|
114
114
|
Database,
|
115
115
|
DEPENDENCY_ROOT_PACKAGE_PREFIX,
|
116
|
+
Service,
|
116
117
|
} from '@finos/legend-graph';
|
117
118
|
import {
|
118
119
|
ActionAlertActionType,
|
@@ -145,6 +146,7 @@ import {
|
|
145
146
|
import { DatabaseBuilderWizard } from '../editor-group/connection-editor/DatabaseBuilderWizard.js';
|
146
147
|
import { FunctionEditorState } from '../../../stores/editor/editor-state/element-editor-state/FunctionEditorState.js';
|
147
148
|
import { DatabaseModelBuilder } from '../editor-group/connection-editor/DatabaseModelBuilder.js';
|
149
|
+
import { queryService } from '../editor-group/service-editor/ServiceExecutionQueryEditor.js';
|
148
150
|
|
149
151
|
const ElementRenamer = observer(() => {
|
150
152
|
const editorStore = useEditorStore();
|
@@ -520,6 +522,13 @@ const ExplorerContextMenu = observer(
|
|
520
522
|
}
|
521
523
|
},
|
522
524
|
);
|
525
|
+
const buildServiceQuery = editorStore.applicationStore.guardUnhandledError(
|
526
|
+
async () => {
|
527
|
+
if (node?.packageableElement instanceof Service) {
|
528
|
+
await queryService(node.packageableElement, editorStore);
|
529
|
+
}
|
530
|
+
},
|
531
|
+
);
|
523
532
|
const generateSampleData = editorStore.applicationStore.guardUnhandledError(
|
524
533
|
async () => {
|
525
534
|
if (node?.packageableElement instanceof Class) {
|
@@ -852,6 +861,14 @@ const ExplorerContextMenu = observer(
|
|
852
861
|
<MenuContentDivider />
|
853
862
|
</>
|
854
863
|
)}
|
864
|
+
{node.packageableElement instanceof Service && (
|
865
|
+
<>
|
866
|
+
<MenuContentItem onClick={buildServiceQuery}>
|
867
|
+
Query...
|
868
|
+
</MenuContentItem>
|
869
|
+
<MenuContentDivider />
|
870
|
+
</>
|
871
|
+
)}
|
855
872
|
{node.packageableElement instanceof ConcreteFunctionDefinition && (
|
856
873
|
<>
|
857
874
|
{editorStore.applicationStore.config.options
|