@finos/legend-application-studio 28.21.23 → 28.21.24
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__/LegendStudioDocumentation.d.ts +2 -2
- package/lib/__lib__/LegendStudioDocumentation.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioDocumentation.js +1 -1
- package/lib/__lib__/LegendStudioDocumentation.js.map +1 -1
- package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js +2 -5
- package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.js +13 -239
- package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.js.map +1 -1
- package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js +17 -3
- package/lib/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.js.map +1 -1
- package/lib/components/editor/editor-group/ingest-editor/testable/IngestTestableEditor.d.ts +22 -0
- package/lib/components/editor/editor-group/ingest-editor/testable/IngestTestableEditor.d.ts.map +1 -0
- package/lib/components/editor/editor-group/ingest-editor/testable/IngestTestableEditor.js +134 -0
- package/lib/components/editor/editor-group/ingest-editor/testable/IngestTestableEditor.js.map +1 -0
- package/lib/components/editor/editor-group/testable/LakehouseTestableEditor.d.ts +89 -0
- package/lib/components/editor/editor-group/testable/LakehouseTestableEditor.d.ts.map +1 -0
- package/lib/components/editor/editor-group/testable/LakehouseTestableEditor.js +144 -0
- package/lib/components/editor/editor-group/testable/LakehouseTestableEditor.js.map +1 -0
- package/lib/components/editor/editor-group/testable/TestableSharedComponents.d.ts.map +1 -1
- package/lib/components/editor/editor-group/testable/TestableSharedComponents.js +14 -8
- package/lib/components/editor/editor-group/testable/TestableSharedComponents.js.map +1 -1
- package/lib/components/editor/ingest-definition-editor.css +1 -1
- package/lib/components/editor/ingest-definition-editor.css.map +1 -1
- package/lib/components/project-reviewer/ProjectReviewer.d.ts.map +1 -1
- package/lib/components/project-reviewer/ProjectReviewer.js +2 -1
- package/lib/components/project-reviewer/ProjectReviewer.js.map +1 -1
- package/lib/components/project-view/ProjectViewer.d.ts.map +1 -1
- package/lib/components/project-view/ProjectViewer.js +2 -2
- package/lib/components/project-view/ProjectViewer.js.map +1 -1
- package/lib/components/showcase/ShowcaseViewer.d.ts.map +1 -1
- package/lib/components/showcase/ShowcaseViewer.js +2 -2
- package/lib/components/showcase/ShowcaseViewer.js.map +1 -1
- package/lib/components/workspace-setup/WorkspaceSetup.d.ts +1 -1
- package/lib/components/workspace-setup/WorkspaceSetup.d.ts.map +1 -1
- package/lib/components/workspace-setup/WorkspaceSetup.js +98 -43
- package/lib/components/workspace-setup/WorkspaceSetup.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/data/EmbeddedDataState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.js +1 -2
- package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts +8 -30
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js +7 -147
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +32 -28
- package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.d.ts +8 -0
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js +15 -0
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.d.ts +86 -0
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.d.ts.map +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.js +420 -0
- package/lib/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.js.map +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/testable/LakehouseTestableUtils.d.ts +62 -0
- package/lib/stores/editor/editor-state/element-editor-state/testable/LakehouseTestableUtils.d.ts.map +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/testable/LakehouseTestableUtils.js +138 -0
- package/lib/stores/editor/editor-state/element-editor-state/testable/LakehouseTestableUtils.js.map +1 -0
- package/lib/stores/workspace-setup/WorkspaceSetupStore.d.ts +10 -1
- package/lib/stores/workspace-setup/WorkspaceSetupStore.d.ts.map +1 -1
- package/lib/stores/workspace-setup/WorkspaceSetupStore.js +105 -12
- package/lib/stores/workspace-setup/WorkspaceSetupStore.js.map +1 -1
- package/package.json +11 -11
- package/src/__lib__/LegendStudioDocumentation.ts +1 -1
- package/src/components/editor/editor-group/data-editor/RelationElementsDataEditor.tsx +2 -5
- package/src/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.tsx +19 -869
- package/src/components/editor/editor-group/ingest-editor/IngestDefinitionEditor.tsx +90 -34
- package/src/components/editor/editor-group/ingest-editor/testable/IngestTestableEditor.tsx +418 -0
- package/src/components/editor/editor-group/testable/LakehouseTestableEditor.tsx +564 -0
- package/src/components/editor/editor-group/testable/TestableSharedComponents.tsx +17 -9
- package/src/components/project-reviewer/ProjectReviewer.tsx +2 -0
- package/src/components/project-view/ProjectViewer.tsx +2 -1
- package/src/components/showcase/ShowcaseViewer.tsx +2 -1
- package/src/components/workspace-setup/WorkspaceSetup.tsx +169 -75
- package/src/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.ts +1 -2
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +1 -0
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.ts +18 -204
- package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +41 -36
- package/src/stores/editor/editor-state/element-editor-state/ingest/IngestDefinitionEditorState.ts +16 -0
- package/src/stores/editor/editor-state/element-editor-state/ingest/IngestTestableState.ts +654 -0
- package/src/stores/editor/editor-state/element-editor-state/testable/LakehouseTestableUtils.ts +224 -0
- package/src/stores/workspace-setup/WorkspaceSetupStore.ts +125 -8
- package/tsconfig.json +4 -0
package/src/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.tsx
CHANGED
|
@@ -18,13 +18,10 @@ import { observer } from 'mobx-react-lite';
|
|
|
18
18
|
import { flowResult } from 'mobx';
|
|
19
19
|
import {
|
|
20
20
|
BlankPanelPlaceholder,
|
|
21
|
-
BlankPanelContent,
|
|
22
21
|
clsx,
|
|
23
22
|
ContextMenu,
|
|
24
23
|
CustomSelectorInput,
|
|
25
24
|
Dialog,
|
|
26
|
-
ErrorWarnIcon,
|
|
27
|
-
FilledWindowMaximizeIcon,
|
|
28
25
|
MenuContent,
|
|
29
26
|
MenuContentItem,
|
|
30
27
|
Modal,
|
|
@@ -39,64 +36,23 @@ import {
|
|
|
39
36
|
PanelHeaderActionItem,
|
|
40
37
|
PanelHeaderActions,
|
|
41
38
|
PanelLoadingIndicator,
|
|
42
|
-
PlayIcon,
|
|
43
39
|
PlusIcon,
|
|
44
|
-
RefreshIcon,
|
|
45
|
-
ResizablePanel,
|
|
46
|
-
ResizablePanelGroup,
|
|
47
|
-
ResizablePanelSplitter,
|
|
48
|
-
ResizablePanelSplitterLine,
|
|
49
|
-
RunAllIcon,
|
|
50
|
-
TimesIcon,
|
|
51
40
|
} from '@finos/legend-art';
|
|
52
|
-
import {
|
|
53
|
-
FunctionAccessPoint,
|
|
54
|
-
LakehouseAccessPoint,
|
|
55
|
-
PrimitiveInstanceValue,
|
|
56
|
-
PrimitiveType,
|
|
57
|
-
type RawLambda,
|
|
58
|
-
type DataProductTestSuite,
|
|
59
|
-
type ValueSpecification,
|
|
60
|
-
} from '@finos/legend-graph';
|
|
41
|
+
import type { DataProductTestSuite } from '@finos/legend-graph';
|
|
61
42
|
import type { DataProductEditorState } from '../../../../../stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js';
|
|
62
43
|
import {
|
|
63
|
-
DataProductValueSpecificationTestParameterState,
|
|
64
|
-
type DataProductTestParameterState,
|
|
65
44
|
type DataProductTestableState,
|
|
66
45
|
type DataProductTestSuiteState,
|
|
67
|
-
type DataProductTestState,
|
|
68
|
-
type DataProductTestDataState,
|
|
69
|
-
type DataProductElementTestDataState,
|
|
70
46
|
} from '../../../../../stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js';
|
|
71
|
-
import { forwardRef,
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
TESTABLE_RESULT,
|
|
75
|
-
getTestableResultFromTestResult,
|
|
76
|
-
} from '../../../../../stores/editor/sidebar-state/testable/GlobalTestRunnerState.js';
|
|
77
|
-
import { RelationElementsDataEditor } from '../../data-editor/RelationElementsDataEditor.js';
|
|
78
|
-
import {
|
|
79
|
-
getContentTypeWithParamFromQuery,
|
|
80
|
-
type TestParamContentType,
|
|
81
|
-
validateTestableId,
|
|
82
|
-
} from '../../../../../stores/editor/utils/TestableUtils.js';
|
|
47
|
+
import { forwardRef, useRef, useState } from 'react';
|
|
48
|
+
import { validateTestableId } from '../../../../../stores/editor/utils/TestableUtils.js';
|
|
83
49
|
import { useEditorStore } from '../../../EditorStoreProvider.js';
|
|
84
50
|
import { guaranteeNonNullable } from '@finos/legend-shared';
|
|
85
|
-
import {
|
|
86
|
-
ExternalFormatParameterEditorModal,
|
|
87
|
-
RenameModal,
|
|
88
|
-
TestAssertionEditor,
|
|
89
|
-
} from '../../testable/TestableSharedComponents.js';
|
|
51
|
+
import { RenameModal } from '../../testable/TestableSharedComponents.js';
|
|
90
52
|
import { testSuite_setId } from '../../../../../stores/graph-modifier/Testable_GraphModifierHelper.js';
|
|
91
|
-
import {
|
|
92
|
-
import {
|
|
93
|
-
BasicValueSpecificationEditor,
|
|
94
|
-
instanceValue_setValue,
|
|
95
|
-
} from '@finos/legend-query-builder';
|
|
53
|
+
import { LakehouseTestSuiteEditor } from '../../testable/LakehouseTestableEditor.js';
|
|
96
54
|
|
|
97
|
-
//
|
|
98
|
-
// Create Suite Modal — test name + access point (datasets are auto-inferred)
|
|
99
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
55
|
+
// ─── Create Suite Modal ───────────────────────────────────────────────────────
|
|
100
56
|
|
|
101
57
|
interface ItemOption {
|
|
102
58
|
value: string;
|
|
@@ -115,7 +71,6 @@ const CreateSuiteModal = observer(
|
|
|
115
71
|
string | undefined
|
|
116
72
|
>(undefined);
|
|
117
73
|
|
|
118
|
-
// Auto-generate suite name
|
|
119
74
|
const existingIds = testableState.dataProduct.tests.map((s) => s.id);
|
|
120
75
|
const generateSuiteName = (): string => {
|
|
121
76
|
let idx = 1;
|
|
@@ -127,7 +82,6 @@ const CreateSuiteModal = observer(
|
|
|
127
82
|
|
|
128
83
|
const testError = validateTestableId(testName, undefined);
|
|
129
84
|
|
|
130
|
-
// Access points on the current DataProduct (for the test target)
|
|
131
85
|
const accessPointOptions: ItemOption[] = testableState.ownAccessPoints.map(
|
|
132
86
|
(ap) => ({
|
|
133
87
|
value: ap.id,
|
|
@@ -228,9 +182,7 @@ const CreateSuiteModal = observer(
|
|
|
228
182
|
},
|
|
229
183
|
);
|
|
230
184
|
|
|
231
|
-
//
|
|
232
|
-
// Create Test Modal — asks for test name + access point to test
|
|
233
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
185
|
+
// ─── Create Test Modal ────────────────────────────────────────────────────────
|
|
234
186
|
|
|
235
187
|
const CreateTestModal = observer(
|
|
236
188
|
(props: { suiteState: DataProductTestSuiteState; onClose: () => void }) => {
|
|
@@ -339,807 +291,7 @@ const CreateTestModal = observer(
|
|
|
339
291
|
},
|
|
340
292
|
);
|
|
341
293
|
|
|
342
|
-
//
|
|
343
|
-
// Element Test Data Item (sidebar list row in test data panel)
|
|
344
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
345
|
-
|
|
346
|
-
const ElementTestDataItem = observer(
|
|
347
|
-
(props: {
|
|
348
|
-
elementState: DataProductElementTestDataState;
|
|
349
|
-
testDataState: DataProductTestDataState;
|
|
350
|
-
isReadOnly: boolean;
|
|
351
|
-
}) => {
|
|
352
|
-
const { elementState, testDataState, isReadOnly } = props;
|
|
353
|
-
const isActive =
|
|
354
|
-
testDataState.selectedElementTestDataState === elementState;
|
|
355
|
-
|
|
356
|
-
const select = (): void =>
|
|
357
|
-
testDataState.setSelectedElementTestDataState(elementState);
|
|
358
|
-
|
|
359
|
-
return (
|
|
360
|
-
<div
|
|
361
|
-
className={clsx('testable-test-explorer__item', {
|
|
362
|
-
'testable-test-explorer__item--active': isActive,
|
|
363
|
-
})}
|
|
364
|
-
>
|
|
365
|
-
<div
|
|
366
|
-
className="testable-test-explorer__item__label"
|
|
367
|
-
onClick={select}
|
|
368
|
-
tabIndex={-1}
|
|
369
|
-
>
|
|
370
|
-
<div className="testable-test-explorer__item__label__text">
|
|
371
|
-
<span title={elementState.element.path}>
|
|
372
|
-
{elementState.element.name}
|
|
373
|
-
</span>
|
|
374
|
-
</div>
|
|
375
|
-
{!isReadOnly && (
|
|
376
|
-
<div className="mapping-test-explorer__item__actions">
|
|
377
|
-
<button
|
|
378
|
-
className="mapping-test-explorer__item__action"
|
|
379
|
-
onClick={(e): void => {
|
|
380
|
-
e.stopPropagation();
|
|
381
|
-
testDataState.deleteElement(elementState);
|
|
382
|
-
}}
|
|
383
|
-
tabIndex={-1}
|
|
384
|
-
title="Delete"
|
|
385
|
-
>
|
|
386
|
-
<TimesIcon />
|
|
387
|
-
</button>
|
|
388
|
-
</div>
|
|
389
|
-
)}
|
|
390
|
-
</div>
|
|
391
|
-
</div>
|
|
392
|
-
);
|
|
393
|
-
},
|
|
394
|
-
);
|
|
395
|
-
|
|
396
|
-
const ElementTestDataEditor = observer(
|
|
397
|
-
(props: {
|
|
398
|
-
elementState: DataProductElementTestDataState;
|
|
399
|
-
isReadOnly: boolean;
|
|
400
|
-
}) => {
|
|
401
|
-
const { elementState, isReadOnly } = props;
|
|
402
|
-
const dataState = elementState.relationElementsDataState;
|
|
403
|
-
|
|
404
|
-
if (!dataState) {
|
|
405
|
-
return (
|
|
406
|
-
<BlankPanelContent>No relation data for this element</BlankPanelContent>
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return (
|
|
411
|
-
<RelationElementsDataEditor
|
|
412
|
-
dataState={dataState}
|
|
413
|
-
isReadOnly={isReadOnly}
|
|
414
|
-
hideColumnDefinitions={true}
|
|
415
|
-
/>
|
|
416
|
-
);
|
|
417
|
-
},
|
|
418
|
-
);
|
|
419
|
-
|
|
420
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
421
|
-
// Test Data Editor (top panel) — always-visible elements sidebar + per-element editor
|
|
422
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
423
|
-
|
|
424
|
-
const AddElementModal = observer(
|
|
425
|
-
(props: { testDataState: DataProductTestDataState }) => {
|
|
426
|
-
const { testDataState } = props;
|
|
427
|
-
const applicationStore = testDataState.editorStore.applicationStore;
|
|
428
|
-
const options = testDataState.availableElementsToAdd.map((e) => ({
|
|
429
|
-
value: e.path,
|
|
430
|
-
label: e.path,
|
|
431
|
-
}));
|
|
432
|
-
const [selectedPath, setSelectedPath] = useState<string | undefined>(
|
|
433
|
-
options[0]?.value,
|
|
434
|
-
);
|
|
435
|
-
const close = (): void => testDataState.setShowAddElementModal(false);
|
|
436
|
-
const add = (): void => {
|
|
437
|
-
if (selectedPath) {
|
|
438
|
-
testDataState.addElement(selectedPath);
|
|
439
|
-
close();
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
const onChange = (val: { label: string; value: string } | null): void => {
|
|
443
|
-
setSelectedPath(val?.value);
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
return (
|
|
447
|
-
<Dialog
|
|
448
|
-
open={testDataState.showAddElementModal}
|
|
449
|
-
onClose={close}
|
|
450
|
-
classes={{ container: 'search-modal__container' }}
|
|
451
|
-
slotProps={{
|
|
452
|
-
paper: {
|
|
453
|
-
classes: { root: 'search-modal__inner-container' },
|
|
454
|
-
},
|
|
455
|
-
}}
|
|
456
|
-
>
|
|
457
|
-
<Modal
|
|
458
|
-
darkMode={
|
|
459
|
-
!applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
|
|
460
|
-
}
|
|
461
|
-
>
|
|
462
|
-
<ModalHeader>
|
|
463
|
-
<ModalTitle title="Add Element" />
|
|
464
|
-
</ModalHeader>
|
|
465
|
-
<ModalBody>
|
|
466
|
-
<CustomSelectorInput
|
|
467
|
-
className="panel__content__form__section__dropdown"
|
|
468
|
-
options={options}
|
|
469
|
-
onChange={onChange}
|
|
470
|
-
value={
|
|
471
|
-
selectedPath
|
|
472
|
-
? { value: selectedPath, label: selectedPath }
|
|
473
|
-
: null
|
|
474
|
-
}
|
|
475
|
-
placeholder="Select element..."
|
|
476
|
-
darkMode={
|
|
477
|
-
!applicationStore.layoutService
|
|
478
|
-
.TEMPORARY__isLightColorThemeEnabled
|
|
479
|
-
}
|
|
480
|
-
/>
|
|
481
|
-
</ModalBody>
|
|
482
|
-
<ModalFooter>
|
|
483
|
-
<ModalFooterButton
|
|
484
|
-
disabled={!selectedPath}
|
|
485
|
-
onClick={add}
|
|
486
|
-
text="Add"
|
|
487
|
-
/>
|
|
488
|
-
<ModalFooterButton onClick={close} text="Close" type="secondary" />
|
|
489
|
-
</ModalFooter>
|
|
490
|
-
</Modal>
|
|
491
|
-
</Dialog>
|
|
492
|
-
);
|
|
493
|
-
},
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
const DataProductTestDataEditor = observer(
|
|
497
|
-
(props: { testDataState: DataProductTestDataState; isReadOnly: boolean }) => {
|
|
498
|
-
const { testDataState, isReadOnly } = props;
|
|
499
|
-
|
|
500
|
-
const addElement = (): void => {
|
|
501
|
-
if (testDataState.availableElementsToAdd.length === 0) {
|
|
502
|
-
testDataState.editorStore.applicationStore.notificationService.notifyWarning(
|
|
503
|
-
'No elements available to add',
|
|
504
|
-
);
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
testDataState.setShowAddElementModal(true);
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
const hasTestData = testDataState.elementTestDataStates.length > 0;
|
|
511
|
-
|
|
512
|
-
return (
|
|
513
|
-
<div
|
|
514
|
-
className={clsx('data-product-test-data-editor panel', {
|
|
515
|
-
'data-product-test-data-editor--no-data': !hasTestData,
|
|
516
|
-
})}
|
|
517
|
-
>
|
|
518
|
-
<div className="data-product-test-data-editor__data">
|
|
519
|
-
<ResizablePanelGroup orientation="vertical">
|
|
520
|
-
{/* Left: elements list — always visible */}
|
|
521
|
-
<ResizablePanel minSize={100} size={180}>
|
|
522
|
-
<div className="binding-editor__header">
|
|
523
|
-
<div className="binding-editor__header__title">
|
|
524
|
-
<div className="panel__header__title__content">Test Data</div>
|
|
525
|
-
</div>
|
|
526
|
-
{!isReadOnly && (
|
|
527
|
-
<div className="panel__header__actions">
|
|
528
|
-
<button
|
|
529
|
-
className="panel__header__action"
|
|
530
|
-
tabIndex={-1}
|
|
531
|
-
onClick={addElement}
|
|
532
|
-
title="Add Element"
|
|
533
|
-
>
|
|
534
|
-
<PlusIcon />
|
|
535
|
-
</button>
|
|
536
|
-
</div>
|
|
537
|
-
)}
|
|
538
|
-
</div>
|
|
539
|
-
{!hasTestData ? (
|
|
540
|
-
<div className="data-product-test-data-editor__warning">
|
|
541
|
-
<ErrorWarnIcon />
|
|
542
|
-
<span>Add an element to configure test data</span>
|
|
543
|
-
</div>
|
|
544
|
-
) : (
|
|
545
|
-
<div>
|
|
546
|
-
{testDataState.elementTestDataStates.map((elementState) => (
|
|
547
|
-
<ElementTestDataItem
|
|
548
|
-
key={elementState.element.path}
|
|
549
|
-
elementState={elementState}
|
|
550
|
-
testDataState={testDataState}
|
|
551
|
-
isReadOnly={isReadOnly}
|
|
552
|
-
/>
|
|
553
|
-
))}
|
|
554
|
-
</div>
|
|
555
|
-
)}
|
|
556
|
-
</ResizablePanel>
|
|
557
|
-
<ResizablePanelSplitter>
|
|
558
|
-
<ResizablePanelSplitterLine color="var(--color-dark-grey-200)" />
|
|
559
|
-
</ResizablePanelSplitter>
|
|
560
|
-
{/* Right: per-element dataset tabs + CSV editor */}
|
|
561
|
-
<ResizablePanel minSize={200}>
|
|
562
|
-
{testDataState.selectedElementTestDataState ? (
|
|
563
|
-
<ElementTestDataEditor
|
|
564
|
-
elementState={testDataState.selectedElementTestDataState}
|
|
565
|
-
isReadOnly={isReadOnly}
|
|
566
|
-
/>
|
|
567
|
-
) : (
|
|
568
|
-
<BlankPanelContent>
|
|
569
|
-
Select an element to configure its test data
|
|
570
|
-
</BlankPanelContent>
|
|
571
|
-
)}
|
|
572
|
-
</ResizablePanel>
|
|
573
|
-
</ResizablePanelGroup>
|
|
574
|
-
</div>
|
|
575
|
-
{testDataState.showAddElementModal && (
|
|
576
|
-
<AddElementModal testDataState={testDataState} />
|
|
577
|
-
)}
|
|
578
|
-
</div>
|
|
579
|
-
);
|
|
580
|
-
},
|
|
581
|
-
);
|
|
582
|
-
|
|
583
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
584
|
-
// Test Item (inside tests panel)
|
|
585
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
586
|
-
|
|
587
|
-
const TestItem = observer(
|
|
588
|
-
(props: {
|
|
589
|
-
testState: DataProductTestState;
|
|
590
|
-
suiteState: DataProductTestSuiteState;
|
|
591
|
-
isReadOnly: boolean;
|
|
592
|
-
}) => {
|
|
593
|
-
const { testState, suiteState, isReadOnly } = props;
|
|
594
|
-
const isActive = suiteState.selectTestState === testState;
|
|
595
|
-
const isRunning = testState.runningTestAction.isInProgress;
|
|
596
|
-
const _testableResult = getTestableResultFromTestResult(
|
|
597
|
-
testState.testResultState.result,
|
|
598
|
-
);
|
|
599
|
-
const testResult = isRunning
|
|
600
|
-
? TESTABLE_RESULT.IN_PROGRESS
|
|
601
|
-
: _testableResult;
|
|
602
|
-
|
|
603
|
-
const select = (): void => suiteState.changeTest(testState.test);
|
|
604
|
-
const runTest = (): void => {
|
|
605
|
-
flowResult(testState.runTest()).catch(
|
|
606
|
-
testState.editorStore.applicationStore.alertUnhandledError,
|
|
607
|
-
);
|
|
608
|
-
};
|
|
609
|
-
const deleteTest = (): void => {
|
|
610
|
-
if (!isReadOnly) {
|
|
611
|
-
suiteState.deleteTest(testState.test);
|
|
612
|
-
}
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
return (
|
|
616
|
-
<div
|
|
617
|
-
className={clsx('testable-test-explorer__item', {
|
|
618
|
-
'testable-test-explorer__item--active': isActive,
|
|
619
|
-
})}
|
|
620
|
-
>
|
|
621
|
-
<div
|
|
622
|
-
className="testable-test-explorer__item__label"
|
|
623
|
-
onClick={select}
|
|
624
|
-
tabIndex={-1}
|
|
625
|
-
>
|
|
626
|
-
<div className="testable-test-explorer__item__label__icon">
|
|
627
|
-
{getTestableResultIcon(testResult)}
|
|
628
|
-
</div>
|
|
629
|
-
<div className="testable-test-explorer__item__label__text">
|
|
630
|
-
{testState.test.id}
|
|
631
|
-
</div>
|
|
632
|
-
</div>
|
|
633
|
-
<div className="mapping-test-explorer__item__actions">
|
|
634
|
-
<button
|
|
635
|
-
className="mapping-test-explorer__item__action mapping-test-explorer__run-test-btn"
|
|
636
|
-
onClick={runTest}
|
|
637
|
-
disabled={isRunning}
|
|
638
|
-
tabIndex={-1}
|
|
639
|
-
title={`Run test ${testState.test.id}`}
|
|
640
|
-
>
|
|
641
|
-
<PlayIcon />
|
|
642
|
-
</button>
|
|
643
|
-
{!isReadOnly && (
|
|
644
|
-
<button
|
|
645
|
-
className="mapping-test-explorer__item__action mapping-test-explorer__run-test-btn"
|
|
646
|
-
onClick={deleteTest}
|
|
647
|
-
tabIndex={-1}
|
|
648
|
-
title={`Delete test ${testState.test.id}`}
|
|
649
|
-
>
|
|
650
|
-
<TimesIcon />
|
|
651
|
-
</button>
|
|
652
|
-
)}
|
|
653
|
-
</div>
|
|
654
|
-
</div>
|
|
655
|
-
);
|
|
656
|
-
},
|
|
657
|
-
);
|
|
658
|
-
|
|
659
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
660
|
-
// Test Editor — shows SETUP (input data) and ASSERTION (expected + result) tabs
|
|
661
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
662
|
-
|
|
663
|
-
const DataProductTestParameterEditor = observer(
|
|
664
|
-
(props: {
|
|
665
|
-
isReadOnly: boolean;
|
|
666
|
-
paramState: DataProductTestParameterState;
|
|
667
|
-
testState: DataProductTestState;
|
|
668
|
-
contentTypeParamPair: TestParamContentType | undefined;
|
|
669
|
-
}) => {
|
|
670
|
-
const { testState, paramState, isReadOnly, contentTypeParamPair } = props;
|
|
671
|
-
const [showPopUp, setShowPopUp] = useState(false);
|
|
672
|
-
const valueSpecificationParamState =
|
|
673
|
-
paramState instanceof DataProductValueSpecificationTestParameterState
|
|
674
|
-
? paramState
|
|
675
|
-
: undefined;
|
|
676
|
-
const paramExpression = valueSpecificationParamState?.varExpression;
|
|
677
|
-
const paramIsRequired = (paramExpression?.multiplicity.lowerBound ?? 0) > 0;
|
|
678
|
-
const type = contentTypeParamPair
|
|
679
|
-
? contentTypeParamPair.contentType
|
|
680
|
-
: (paramExpression?.genericType?.value.rawType.name ?? 'unknown');
|
|
681
|
-
const primitiveValueSpecification =
|
|
682
|
-
valueSpecificationParamState?.valueSpec instanceof PrimitiveInstanceValue
|
|
683
|
-
? valueSpecificationParamState.valueSpec
|
|
684
|
-
: undefined;
|
|
685
|
-
const primitiveValue = primitiveValueSpecification?.values[0] as
|
|
686
|
-
| string
|
|
687
|
-
| undefined;
|
|
688
|
-
const paramValue =
|
|
689
|
-
paramExpression?.genericType?.value.rawType === PrimitiveType.BYTE &&
|
|
690
|
-
primitiveValue !== undefined
|
|
691
|
-
? atob(primitiveValue)
|
|
692
|
-
: (primitiveValue ?? '');
|
|
693
|
-
|
|
694
|
-
const openInPopUp = (): void => setShowPopUp(!showPopUp);
|
|
695
|
-
const closePopUp = (): void => setShowPopUp(false);
|
|
696
|
-
const updateParamValue = (val: string): void => {
|
|
697
|
-
if (
|
|
698
|
-
primitiveValueSpecification &&
|
|
699
|
-
valueSpecificationParamState &&
|
|
700
|
-
paramExpression
|
|
701
|
-
) {
|
|
702
|
-
instanceValue_setValue(
|
|
703
|
-
primitiveValueSpecification,
|
|
704
|
-
paramExpression.genericType?.value.rawType === PrimitiveType.BYTE
|
|
705
|
-
? btoa(val)
|
|
706
|
-
: val,
|
|
707
|
-
0,
|
|
708
|
-
testState.editorStore.changeDetectionState.observerContext,
|
|
709
|
-
);
|
|
710
|
-
valueSpecificationParamState.updateValueSpecification(
|
|
711
|
-
primitiveValueSpecification,
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
|
|
716
|
-
return (
|
|
717
|
-
<div
|
|
718
|
-
key={paramState.parameterValue.name}
|
|
719
|
-
className="panel__content__form__section"
|
|
720
|
-
>
|
|
721
|
-
<div className="panel__content__form__section__header__label">
|
|
722
|
-
{paramState.parameterValue.name}
|
|
723
|
-
<button
|
|
724
|
-
className={clsx('type-tree__node__type__label', {})}
|
|
725
|
-
tabIndex={-1}
|
|
726
|
-
title={type}
|
|
727
|
-
>
|
|
728
|
-
{type}
|
|
729
|
-
</button>
|
|
730
|
-
</div>
|
|
731
|
-
{!valueSpecificationParamState || !paramExpression ? (
|
|
732
|
-
<BlankPanelPlaceholder
|
|
733
|
-
text="Unsupported parameter value"
|
|
734
|
-
tooltipText="This parameter was preserved but cannot currently be edited in form mode"
|
|
735
|
-
/>
|
|
736
|
-
) : contentTypeParamPair && primitiveValueSpecification ? (
|
|
737
|
-
<div className="data-product-test-editor__parameter__code-editor">
|
|
738
|
-
<textarea
|
|
739
|
-
className="panel__content__form__section__textarea value-spec-editor__input"
|
|
740
|
-
spellCheck={false}
|
|
741
|
-
value={paramValue}
|
|
742
|
-
placeholder={primitiveValue === '' ? '(empty)' : undefined}
|
|
743
|
-
onChange={(event) => {
|
|
744
|
-
updateParamValue(event.target.value);
|
|
745
|
-
}}
|
|
746
|
-
/>
|
|
747
|
-
{showPopUp && (
|
|
748
|
-
<ExternalFormatParameterEditorModal
|
|
749
|
-
valueSpec={valueSpecificationParamState.valueSpec}
|
|
750
|
-
varExpression={paramExpression}
|
|
751
|
-
isReadOnly={isReadOnly}
|
|
752
|
-
onClose={closePopUp}
|
|
753
|
-
updateParamValue={updateParamValue}
|
|
754
|
-
contentTypeParamPair={contentTypeParamPair}
|
|
755
|
-
/>
|
|
756
|
-
)}
|
|
757
|
-
<div className="data-product-test-editor__parameter__value__actions">
|
|
758
|
-
<button
|
|
759
|
-
className="data-product-test-editor__parameter__code-editor__expand-btn"
|
|
760
|
-
onClick={openInPopUp}
|
|
761
|
-
tabIndex={-1}
|
|
762
|
-
title="Open in a popup..."
|
|
763
|
-
>
|
|
764
|
-
<FilledWindowMaximizeIcon />
|
|
765
|
-
</button>
|
|
766
|
-
<button
|
|
767
|
-
className="btn--icon btn--dark btn--sm data-product-test-editor__parameter__code-editor__expand-btn"
|
|
768
|
-
disabled={isReadOnly || paramIsRequired}
|
|
769
|
-
onClick={(): void =>
|
|
770
|
-
testState.removeParamValueState(paramState)
|
|
771
|
-
}
|
|
772
|
-
tabIndex={-1}
|
|
773
|
-
title={
|
|
774
|
-
paramIsRequired ? 'Parameter Required' : 'Remove Parameter'
|
|
775
|
-
}
|
|
776
|
-
>
|
|
777
|
-
<TimesIcon />
|
|
778
|
-
</button>
|
|
779
|
-
</div>
|
|
780
|
-
</div>
|
|
781
|
-
) : (
|
|
782
|
-
<div className="data-product-test-editor__parameter__value">
|
|
783
|
-
<BasicValueSpecificationEditor
|
|
784
|
-
valueSpecification={valueSpecificationParamState.valueSpec}
|
|
785
|
-
setValueSpecification={(val: ValueSpecification): void => {
|
|
786
|
-
valueSpecificationParamState.updateValueSpecification(val);
|
|
787
|
-
}}
|
|
788
|
-
graph={testState.editorStore.graphManagerState.graph}
|
|
789
|
-
observerContext={
|
|
790
|
-
testState.editorStore.changeDetectionState.observerContext
|
|
791
|
-
}
|
|
792
|
-
typeCheckOption={{
|
|
793
|
-
expectedType:
|
|
794
|
-
paramExpression.genericType?.value.rawType ??
|
|
795
|
-
PrimitiveType.STRING,
|
|
796
|
-
}}
|
|
797
|
-
className="query-builder__parameters__value__editor"
|
|
798
|
-
resetValue={(): void => {
|
|
799
|
-
valueSpecificationParamState.resetValueSpec();
|
|
800
|
-
}}
|
|
801
|
-
/>
|
|
802
|
-
<div className="data-product-test-editor__parameter__value__actions">
|
|
803
|
-
<button
|
|
804
|
-
className="btn--icon btn--dark btn--sm"
|
|
805
|
-
disabled={isReadOnly || paramIsRequired}
|
|
806
|
-
onClick={(): void =>
|
|
807
|
-
testState.removeParamValueState(paramState)
|
|
808
|
-
}
|
|
809
|
-
tabIndex={-1}
|
|
810
|
-
title={
|
|
811
|
-
paramIsRequired ? 'Parameter Required' : 'Remove Parameter'
|
|
812
|
-
}
|
|
813
|
-
>
|
|
814
|
-
<TimesIcon />
|
|
815
|
-
</button>
|
|
816
|
-
</div>
|
|
817
|
-
</div>
|
|
818
|
-
)}
|
|
819
|
-
</div>
|
|
820
|
-
);
|
|
821
|
-
},
|
|
822
|
-
);
|
|
823
|
-
|
|
824
|
-
const NewDataProductParameterModal = observer(
|
|
825
|
-
(props: { testState: DataProductTestState; isReadOnly: boolean }) => {
|
|
826
|
-
const { testState, isReadOnly } = props;
|
|
827
|
-
const applicationStore = testState.editorStore.applicationStore;
|
|
828
|
-
const currentOption = {
|
|
829
|
-
value: testState.newParameterValueName,
|
|
830
|
-
label: testState.newParameterValueName,
|
|
831
|
-
};
|
|
832
|
-
const options = testState.newParamOptions;
|
|
833
|
-
const closeModal = (): void => testState.setShowNewParameterModal(false);
|
|
834
|
-
const onChange = (val: { label: string; value: string } | null): void => {
|
|
835
|
-
if (val === null) {
|
|
836
|
-
testState.setNewParameterValueName('');
|
|
837
|
-
} else if (val.value !== testState.newParameterValueName) {
|
|
838
|
-
testState.setNewParameterValueName(val.value);
|
|
839
|
-
}
|
|
840
|
-
};
|
|
841
|
-
return (
|
|
842
|
-
<Dialog
|
|
843
|
-
open={testState.showNewParameterModal}
|
|
844
|
-
onClose={closeModal}
|
|
845
|
-
classes={{ container: 'search-modal__container' }}
|
|
846
|
-
slotProps={{
|
|
847
|
-
paper: {
|
|
848
|
-
classes: { root: 'search-modal__inner-container' },
|
|
849
|
-
},
|
|
850
|
-
}}
|
|
851
|
-
>
|
|
852
|
-
<form
|
|
853
|
-
onSubmit={(event) => {
|
|
854
|
-
event.preventDefault();
|
|
855
|
-
testState.addParameterValue();
|
|
856
|
-
}}
|
|
857
|
-
className="modal modal--dark search-modal"
|
|
858
|
-
>
|
|
859
|
-
<div className="modal__title">New Test Parameter Value</div>
|
|
860
|
-
<CustomSelectorInput
|
|
861
|
-
className="panel__content__form__section__dropdown"
|
|
862
|
-
options={options}
|
|
863
|
-
onChange={onChange}
|
|
864
|
-
value={currentOption}
|
|
865
|
-
escapeClearsValue={true}
|
|
866
|
-
darkMode={
|
|
867
|
-
!applicationStore.layoutService
|
|
868
|
-
.TEMPORARY__isLightColorThemeEnabled
|
|
869
|
-
}
|
|
870
|
-
disabled={isReadOnly}
|
|
871
|
-
/>
|
|
872
|
-
<div className="search-modal__actions">
|
|
873
|
-
<button className="btn btn--dark" disabled={isReadOnly}>
|
|
874
|
-
Add
|
|
875
|
-
</button>
|
|
876
|
-
</div>
|
|
877
|
-
</form>
|
|
878
|
-
</Dialog>
|
|
879
|
-
);
|
|
880
|
-
},
|
|
881
|
-
);
|
|
882
|
-
|
|
883
|
-
const DataProductTestEditor = observer(
|
|
884
|
-
(props: { testState: DataProductTestState; isReadOnly: boolean }) => {
|
|
885
|
-
const { testState, isReadOnly } = props;
|
|
886
|
-
const selectedTab = testState.selectedTab;
|
|
887
|
-
const selectedAssertion = testState.selectedAsertionState;
|
|
888
|
-
|
|
889
|
-
useEffect(() => {
|
|
890
|
-
testState.syncWithQuery();
|
|
891
|
-
}, [testState]);
|
|
892
|
-
|
|
893
|
-
const addParameter = (): void => {
|
|
894
|
-
testState.openNewParamModal();
|
|
895
|
-
};
|
|
896
|
-
|
|
897
|
-
const generateParameterValues = (): void => {
|
|
898
|
-
testState.generateTestParameterValues();
|
|
899
|
-
};
|
|
900
|
-
|
|
901
|
-
const accessPoint = testState.suiteState.testableState.ownAccessPoints.find(
|
|
902
|
-
(ap) => ap.id === testState.test.accessPointId,
|
|
903
|
-
);
|
|
904
|
-
let accessPointQuery: RawLambda | undefined;
|
|
905
|
-
if (accessPoint instanceof LakehouseAccessPoint) {
|
|
906
|
-
accessPointQuery = accessPoint.func;
|
|
907
|
-
} else if (accessPoint instanceof FunctionAccessPoint) {
|
|
908
|
-
accessPointQuery = accessPoint.query;
|
|
909
|
-
}
|
|
910
|
-
const hasQueryParameters = Boolean(
|
|
911
|
-
testState.queryVariableExpressions.length,
|
|
912
|
-
);
|
|
913
|
-
|
|
914
|
-
return (
|
|
915
|
-
<div className="function-test-editor panel">
|
|
916
|
-
<div className="panel__header">
|
|
917
|
-
<div className="panel__header data-product-test-editor__header--with-tabs">
|
|
918
|
-
<div className="panel__header__title__content">Assertion</div>
|
|
919
|
-
</div>
|
|
920
|
-
</div>
|
|
921
|
-
<div className="panel">
|
|
922
|
-
{selectedTab === TESTABLE_TEST_TAB.ASSERTION && (
|
|
923
|
-
<>
|
|
924
|
-
{selectedAssertion ? (
|
|
925
|
-
<div className="data-product-test-editor__assertion">
|
|
926
|
-
{hasQueryParameters && (
|
|
927
|
-
<div className="data-product-test-editor__parameters-panel-container">
|
|
928
|
-
<div className="panel data-product-test-editor__parameters-panel">
|
|
929
|
-
<div className="data-product-test-editor__parameters-header">
|
|
930
|
-
<div className="data-product-test-editor__parameters-header__title">
|
|
931
|
-
<div className="data-product-test-editor__parameters-header__title__label">
|
|
932
|
-
Parameters
|
|
933
|
-
</div>
|
|
934
|
-
</div>
|
|
935
|
-
<div className="panel__header__actions data-product-test-editor__parameters-header__actions">
|
|
936
|
-
<button
|
|
937
|
-
className="panel__header__action data-product-test-editor__generate-btn"
|
|
938
|
-
onClick={generateParameterValues}
|
|
939
|
-
disabled={!testState.newParamOptions.length}
|
|
940
|
-
title="Generate test parameter values"
|
|
941
|
-
tabIndex={-1}
|
|
942
|
-
>
|
|
943
|
-
<div className="data-product-test-editor__generate-btn__label">
|
|
944
|
-
<RefreshIcon className="data-product-test-editor__generate-btn__label__icon" />
|
|
945
|
-
<div className="data-product-test-editor__generate-btn__label__title">
|
|
946
|
-
Generate
|
|
947
|
-
</div>
|
|
948
|
-
</div>
|
|
949
|
-
</button>
|
|
950
|
-
<button
|
|
951
|
-
className="panel__header__action data-product-test-editor__parameters-header__action"
|
|
952
|
-
tabIndex={-1}
|
|
953
|
-
disabled={!testState.newParamOptions.length}
|
|
954
|
-
onClick={addParameter}
|
|
955
|
-
title="Add Parameter Value"
|
|
956
|
-
>
|
|
957
|
-
<PlusIcon />
|
|
958
|
-
</button>
|
|
959
|
-
</div>
|
|
960
|
-
</div>
|
|
961
|
-
<div className="data-product-test-editor__parameters">
|
|
962
|
-
{testState.parameterValueStates.map((paramState) => (
|
|
963
|
-
<DataProductTestParameterEditor
|
|
964
|
-
key={paramState.uuid}
|
|
965
|
-
isReadOnly={isReadOnly}
|
|
966
|
-
paramState={paramState}
|
|
967
|
-
testState={testState}
|
|
968
|
-
contentTypeParamPair={getContentTypeWithParamFromQuery(
|
|
969
|
-
accessPointQuery,
|
|
970
|
-
testState.editorStore,
|
|
971
|
-
).find(
|
|
972
|
-
(pair) =>
|
|
973
|
-
pair.param === paramState.parameterValue.name,
|
|
974
|
-
)}
|
|
975
|
-
/>
|
|
976
|
-
))}
|
|
977
|
-
</div>
|
|
978
|
-
</div>
|
|
979
|
-
</div>
|
|
980
|
-
)}
|
|
981
|
-
<div
|
|
982
|
-
className={clsx(
|
|
983
|
-
'data-product-test-editor__assertion-result',
|
|
984
|
-
{
|
|
985
|
-
'data-product-test-editor__assertion-result--full':
|
|
986
|
-
!hasQueryParameters,
|
|
987
|
-
},
|
|
988
|
-
)}
|
|
989
|
-
>
|
|
990
|
-
<TestAssertionEditor
|
|
991
|
-
testAssertionState={selectedAssertion}
|
|
992
|
-
/>
|
|
993
|
-
</div>
|
|
994
|
-
</div>
|
|
995
|
-
) : null}
|
|
996
|
-
</>
|
|
997
|
-
)}
|
|
998
|
-
{selectedTab === TESTABLE_TEST_TAB.ASSERTION &&
|
|
999
|
-
!selectedAssertion && (
|
|
1000
|
-
<BlankPanelPlaceholder
|
|
1001
|
-
text="No assertion"
|
|
1002
|
-
tooltipText="No assertion configured for this test"
|
|
1003
|
-
/>
|
|
1004
|
-
)}
|
|
1005
|
-
{testState.showNewParameterModal && (
|
|
1006
|
-
<NewDataProductParameterModal
|
|
1007
|
-
testState={testState}
|
|
1008
|
-
isReadOnly={isReadOnly}
|
|
1009
|
-
/>
|
|
1010
|
-
)}
|
|
1011
|
-
</div>
|
|
1012
|
-
</div>
|
|
1013
|
-
);
|
|
1014
|
-
},
|
|
1015
|
-
);
|
|
1016
|
-
|
|
1017
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
1018
|
-
// Tests Editor (bottom panel) — tests list + test detail
|
|
1019
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
1020
|
-
|
|
1021
|
-
const DataProductTestsEditor = observer(
|
|
1022
|
-
(props: {
|
|
1023
|
-
suiteState: DataProductTestSuiteState;
|
|
1024
|
-
testableState: DataProductTestableState;
|
|
1025
|
-
isReadOnly: boolean;
|
|
1026
|
-
}) => {
|
|
1027
|
-
const { suiteState, testableState, isReadOnly } = props;
|
|
1028
|
-
const selectedTest = suiteState.selectTestState;
|
|
1029
|
-
|
|
1030
|
-
return (
|
|
1031
|
-
<div className="panel data-product-test-editor__tests">
|
|
1032
|
-
<div className="data-product-test-editor__tests__content">
|
|
1033
|
-
<ResizablePanelGroup orientation="vertical">
|
|
1034
|
-
<ResizablePanel minSize={100} size={200}>
|
|
1035
|
-
<div className="binding-editor__header">
|
|
1036
|
-
<div className="binding-editor__header__title">
|
|
1037
|
-
<div className="panel__header__title__content">Tests</div>
|
|
1038
|
-
</div>
|
|
1039
|
-
<div className="panel__header__actions">
|
|
1040
|
-
<button
|
|
1041
|
-
className="panel__header__action testable-test-explorer__play__all__icon"
|
|
1042
|
-
tabIndex={-1}
|
|
1043
|
-
onClick={(): void => {
|
|
1044
|
-
flowResult(suiteState.runSuite()).catch(
|
|
1045
|
-
testableState.editorStore.applicationStore
|
|
1046
|
-
.alertUnhandledError,
|
|
1047
|
-
);
|
|
1048
|
-
}}
|
|
1049
|
-
disabled={
|
|
1050
|
-
suiteState.runningSuiteState.isInProgress ||
|
|
1051
|
-
suiteState.suite.tests.length === 0
|
|
1052
|
-
}
|
|
1053
|
-
title="Run all tests in this suite"
|
|
1054
|
-
>
|
|
1055
|
-
<RunAllIcon />
|
|
1056
|
-
</button>
|
|
1057
|
-
{!isReadOnly && (
|
|
1058
|
-
<button
|
|
1059
|
-
className="panel__header__action"
|
|
1060
|
-
tabIndex={-1}
|
|
1061
|
-
onClick={(): void =>
|
|
1062
|
-
testableState.setShowCreateTestModal(true)
|
|
1063
|
-
}
|
|
1064
|
-
title="Add test to this suite"
|
|
1065
|
-
>
|
|
1066
|
-
<PlusIcon />
|
|
1067
|
-
</button>
|
|
1068
|
-
)}
|
|
1069
|
-
</div>
|
|
1070
|
-
</div>
|
|
1071
|
-
<div>
|
|
1072
|
-
{suiteState.testStates.map((ts) => (
|
|
1073
|
-
<TestItem
|
|
1074
|
-
key={ts.test.id}
|
|
1075
|
-
testState={ts}
|
|
1076
|
-
suiteState={suiteState}
|
|
1077
|
-
isReadOnly={isReadOnly}
|
|
1078
|
-
/>
|
|
1079
|
-
))}
|
|
1080
|
-
</div>
|
|
1081
|
-
</ResizablePanel>
|
|
1082
|
-
<ResizablePanelSplitter>
|
|
1083
|
-
<ResizablePanelSplitterLine color="var(--color-dark-grey-200)" />
|
|
1084
|
-
</ResizablePanelSplitter>
|
|
1085
|
-
<ResizablePanel minSize={56}>
|
|
1086
|
-
{selectedTest ? (
|
|
1087
|
-
<DataProductTestEditor
|
|
1088
|
-
testState={selectedTest}
|
|
1089
|
-
isReadOnly={isReadOnly}
|
|
1090
|
-
/>
|
|
1091
|
-
) : (
|
|
1092
|
-
<BlankPanelPlaceholder
|
|
1093
|
-
text="Select a test"
|
|
1094
|
-
tooltipText="Select a test from the list above"
|
|
1095
|
-
/>
|
|
1096
|
-
)}
|
|
1097
|
-
</ResizablePanel>
|
|
1098
|
-
</ResizablePanelGroup>
|
|
1099
|
-
</div>
|
|
1100
|
-
</div>
|
|
1101
|
-
);
|
|
1102
|
-
},
|
|
1103
|
-
);
|
|
1104
|
-
|
|
1105
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
1106
|
-
// Suite Editor — horizontal split: test data (top) + tests (bottom)
|
|
1107
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
1108
|
-
|
|
1109
|
-
const DataProductTestSuiteEditor = observer(
|
|
1110
|
-
(props: { suiteState: DataProductTestSuiteState }) => {
|
|
1111
|
-
const { suiteState } = props;
|
|
1112
|
-
const testableState = suiteState.testableState;
|
|
1113
|
-
const isReadOnly = testableState.dataProductEditorState.isReadOnly;
|
|
1114
|
-
|
|
1115
|
-
return (
|
|
1116
|
-
<div className="data-product-test-suite-editor">
|
|
1117
|
-
<ResizablePanelGroup orientation="horizontal">
|
|
1118
|
-
<ResizablePanel size={580} minSize={28}>
|
|
1119
|
-
<DataProductTestDataEditor
|
|
1120
|
-
testDataState={suiteState.testDataState}
|
|
1121
|
-
isReadOnly={isReadOnly}
|
|
1122
|
-
/>
|
|
1123
|
-
</ResizablePanel>
|
|
1124
|
-
<ResizablePanelSplitter>
|
|
1125
|
-
<ResizablePanelSplitterLine color="var(--color-dark-grey-200)" />
|
|
1126
|
-
</ResizablePanelSplitter>
|
|
1127
|
-
<ResizablePanel minSize={56}>
|
|
1128
|
-
<DataProductTestsEditor
|
|
1129
|
-
suiteState={suiteState}
|
|
1130
|
-
testableState={testableState}
|
|
1131
|
-
isReadOnly={isReadOnly}
|
|
1132
|
-
/>
|
|
1133
|
-
</ResizablePanel>
|
|
1134
|
-
</ResizablePanelGroup>
|
|
1135
|
-
</div>
|
|
1136
|
-
);
|
|
1137
|
-
},
|
|
1138
|
-
);
|
|
1139
|
-
|
|
1140
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
1141
|
-
// Suite Tab Context Menu (rename/delete)
|
|
1142
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
294
|
+
// ─── Suite Tab Context Menu ───────────────────────────────────────────────────
|
|
1143
295
|
|
|
1144
296
|
const SuiteHeaderTabContextMenu = observer(
|
|
1145
297
|
forwardRef<
|
|
@@ -1169,9 +321,7 @@ const SuiteHeaderTabContextMenu = observer(
|
|
|
1169
321
|
}),
|
|
1170
322
|
);
|
|
1171
323
|
|
|
1172
|
-
//
|
|
1173
|
-
// Main Testing Tab — suite tabs at top, suite editor below
|
|
1174
|
-
// ──────────────────────────────────────────────────────────────────────────────
|
|
324
|
+
// ─── Main Testing Tab ─────────────────────────────────────────────────────────
|
|
1175
325
|
|
|
1176
326
|
export const DataProductTestableEditor = observer(
|
|
1177
327
|
(props: {
|
|
@@ -1183,10 +333,6 @@ export const DataProductTestableEditor = observer(
|
|
|
1183
333
|
const selectedSuiteState = testableState.selectedSuiteState;
|
|
1184
334
|
const dp = testableState.dataProduct;
|
|
1185
335
|
|
|
1186
|
-
useEffect(() => {
|
|
1187
|
-
testableState.init();
|
|
1188
|
-
}, [testableState]);
|
|
1189
|
-
|
|
1190
336
|
const addSuite = (): void => {
|
|
1191
337
|
testableState.setShowCreateSuiteModal(true);
|
|
1192
338
|
};
|
|
@@ -1199,7 +345,7 @@ export const DataProductTestableEditor = observer(
|
|
|
1199
345
|
testSuite_setId(guaranteeNonNullable(testableState.suiteToRename), val);
|
|
1200
346
|
|
|
1201
347
|
return (
|
|
1202
|
-
<Panel className="
|
|
348
|
+
<Panel className="service-test-suite-editor">
|
|
1203
349
|
<PanelLoadingIndicator
|
|
1204
350
|
isLoading={testableState.runningAllTestsState.isInProgress}
|
|
1205
351
|
/>
|
|
@@ -1220,14 +366,14 @@ export const DataProductTestableEditor = observer(
|
|
|
1220
366
|
|
|
1221
367
|
<PanelHeader>
|
|
1222
368
|
{dp.tests.length ? (
|
|
1223
|
-
<PanelHeader className="
|
|
369
|
+
<PanelHeader className="service-test-suite-editor__header service-test-suite-editor__header--with-tabs">
|
|
1224
370
|
<div className="uml-element-editor__tabs">
|
|
1225
371
|
{dp.tests.map((suite) => (
|
|
1226
372
|
<div
|
|
1227
373
|
key={suite.id}
|
|
1228
374
|
onClick={(): void => changeSuite(suite)}
|
|
1229
|
-
className={clsx('
|
|
1230
|
-
'
|
|
375
|
+
className={clsx('service-test-suite-editor__tab', {
|
|
376
|
+
'service-test-suite-editor__tab--active':
|
|
1231
377
|
selectedSuiteState?.suite === suite,
|
|
1232
378
|
})}
|
|
1233
379
|
>
|
|
@@ -1255,9 +401,13 @@ export const DataProductTestableEditor = observer(
|
|
|
1255
401
|
</PanelHeaderActionItem>
|
|
1256
402
|
</PanelHeaderActions>
|
|
1257
403
|
</PanelHeader>
|
|
1258
|
-
<Panel className="
|
|
404
|
+
<Panel className="service-test-suite-editor">
|
|
1259
405
|
{selectedSuiteState && (
|
|
1260
|
-
<
|
|
406
|
+
<LakehouseTestSuiteEditor
|
|
407
|
+
suiteState={selectedSuiteState}
|
|
408
|
+
testableState={testableState}
|
|
409
|
+
isReadOnly={isReadOnly}
|
|
410
|
+
/>
|
|
1261
411
|
)}
|
|
1262
412
|
{!dp.tests.length && (
|
|
1263
413
|
<BlankPanelPlaceholder
|