@finos/legend-extension-dsl-data-quality 2.0.16 → 2.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/lib/components/DataQualityRelationTrialRuns.d.ts.map +1 -1
  2. package/lib/components/DataQualityRelationTrialRuns.js +33 -6
  3. package/lib/components/DataQualityRelationTrialRuns.js.map +1 -1
  4. package/lib/components/DataQualityRelationValidationConfigurationEditor.d.ts.map +1 -1
  5. package/lib/components/DataQualityRelationValidationConfigurationEditor.js +49 -4
  6. package/lib/components/DataQualityRelationValidationConfigurationEditor.js.map +1 -1
  7. package/lib/components/constants/DataQualityConstants.d.ts +1 -0
  8. package/lib/components/constants/DataQualityConstants.d.ts.map +1 -1
  9. package/lib/components/constants/DataQualityConstants.js +1 -0
  10. package/lib/components/constants/DataQualityConstants.js.map +1 -1
  11. package/lib/components/states/DataQualityRelationResultState.d.ts +7 -2
  12. package/lib/components/states/DataQualityRelationResultState.d.ts.map +1 -1
  13. package/lib/components/states/DataQualityRelationResultState.js +80 -3
  14. package/lib/components/states/DataQualityRelationResultState.js.map +1 -1
  15. package/lib/components/states/DataQualityRelationValidationConfigurationState.d.ts +8 -1
  16. package/lib/components/states/DataQualityRelationValidationConfigurationState.d.ts.map +1 -1
  17. package/lib/components/states/DataQualityRelationValidationConfigurationState.js +74 -2
  18. package/lib/components/states/DataQualityRelationValidationConfigurationState.js.map +1 -1
  19. package/lib/graph/metamodel/pure/packageableElements/data-quality/DataQualityValidationConfiguration.d.ts +2 -1
  20. package/lib/graph/metamodel/pure/packageableElements/data-quality/DataQualityValidationConfiguration.d.ts.map +1 -1
  21. package/lib/graph/metamodel/pure/packageableElements/data-quality/DataQualityValidationConfiguration.js.map +1 -1
  22. package/lib/graph-manager/protocol/pure/DSL_DataQuality_PureGraphManagerExtension.d.ts +1 -0
  23. package/lib/graph-manager/protocol/pure/DSL_DataQuality_PureGraphManagerExtension.d.ts.map +1 -1
  24. package/lib/graph-manager/protocol/pure/DSL_DataQuality_PureGraphManagerExtension.js.map +1 -1
  25. package/lib/graph-manager/protocol/pure/v1/V1_DSL_Data_Quality_PureGraphManagerExtension.d.ts +3 -1
  26. package/lib/graph-manager/protocol/pure/v1/V1_DSL_Data_Quality_PureGraphManagerExtension.d.ts.map +1 -1
  27. package/lib/graph-manager/protocol/pure/v1/V1_DSL_Data_Quality_PureGraphManagerExtension.js +26 -3
  28. package/lib/graph-manager/protocol/pure/v1/V1_DSL_Data_Quality_PureGraphManagerExtension.js.map +1 -1
  29. package/lib/index.css +2 -2
  30. package/lib/index.css.map +1 -1
  31. package/lib/package.json +1 -1
  32. package/package.json +12 -12
  33. package/src/components/DataQualityRelationTrialRuns.tsx +77 -8
  34. package/src/components/DataQualityRelationValidationConfigurationEditor.tsx +135 -3
  35. package/src/components/constants/DataQualityConstants.ts +3 -0
  36. package/src/components/states/DataQualityRelationResultState.ts +115 -0
  37. package/src/components/states/DataQualityRelationValidationConfigurationState.ts +96 -0
  38. package/src/graph/metamodel/pure/packageableElements/data-quality/DataQualityValidationConfiguration.ts +2 -0
  39. package/src/graph-manager/protocol/pure/DSL_DataQuality_PureGraphManagerExtension.ts +6 -0
  40. package/src/graph-manager/protocol/pure/v1/V1_DSL_Data_Quality_PureGraphManagerExtension.ts +55 -5
  41. package/style/_data-quality-relation-validation-builder.scss +13 -0
  42. package/style/_data-quality-validation-builder.scss +6 -0
@@ -31,9 +31,13 @@ import {
31
31
  CaretDownIcon,
32
32
  clsx,
33
33
  ControlledDropdownMenu,
34
+ CsvIcon,
34
35
  DragPreviewLayer,
36
+ ExclamationTriangleIcon,
35
37
  MenuContent,
36
38
  MenuContentItem,
39
+ MenuContentItemIcon,
40
+ MenuContentItemLabel,
37
41
  Panel,
38
42
  PanelContent,
39
43
  PanelLoadingIndicator,
@@ -41,7 +45,11 @@ import {
41
45
  PlayIcon,
42
46
  PlusIcon,
43
47
  } from '@finos/legend-art';
44
- import { prettyCONSTName, returnUndefOnError } from '@finos/legend-shared';
48
+ import {
49
+ prettyCONSTName,
50
+ prettyDuration,
51
+ returnUndefOnError,
52
+ } from '@finos/legend-shared';
45
53
  import {
46
54
  ExecutionPlanViewer,
47
55
  LambdaEditor,
@@ -49,6 +57,7 @@ import {
49
57
  } from '@finos/legend-query-builder';
50
58
  import {
51
59
  type RawVariableExpression,
60
+ type ExecutionResult,
52
61
  PrimitiveType,
53
62
  stub_RawVariableExpression,
54
63
  Type,
@@ -57,6 +66,8 @@ import {
57
66
  TDSExecutionResult,
58
67
  } from '@finos/legend-graph';
59
68
  import {
69
+ ActionAlertActionType,
70
+ ActionAlertType,
60
71
  DEFAULT_TAB_SIZE,
61
72
  useApplicationNavigationContext,
62
73
  useApplicationStore,
@@ -77,6 +88,10 @@ import { DataQualityRelationValidationsEditor } from './DataQualityRelationValid
77
88
  import { CodeEditor } from '@finos/legend-lego/code-editor';
78
89
  import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
79
90
  import { DataQualityRelationGridResult } from './DataQualityRelationGridResult.js';
91
+ import {
92
+ DATA_QUALITY_VALIDATION_TEST_ID,
93
+ USER_ATTESTATION_MESSAGE,
94
+ } from './constants/DataQualityConstants.js';
80
95
 
81
96
  const RelationDefinitionEditor = observer(
82
97
  (props: {
@@ -85,6 +100,9 @@ const RelationDefinitionEditor = observer(
85
100
  const { dataQualityRelationValidationConfigurationState } = props;
86
101
  const { relationFunctionDefinitionEditorState, resultState } =
87
102
  dataQualityRelationValidationConfigurationState;
103
+ const {
104
+ editorStore: { applicationStore },
105
+ } = dataQualityRelationValidationConfigurationState;
88
106
  const validationElement =
89
107
  dataQualityRelationValidationConfigurationState.validationElement;
90
108
  const lambdaExecutionResult =
@@ -93,6 +111,58 @@ const RelationDefinitionEditor = observer(
93
111
  const isReadOnly =
94
112
  dataQualityRelationValidationConfigurationState.isReadOnly;
95
113
 
114
+ const isExportDisabled =
115
+ dataQualityRelationValidationConfigurationState.isRunningValidation ||
116
+ dataQualityRelationValidationConfigurationState.isGeneratingPlan;
117
+
118
+ const exportValidationResults = async (format: string): Promise<void> => {
119
+ dataQualityRelationValidationConfigurationState.handleExport(format);
120
+ };
121
+
122
+ const getResultSetDescription = (
123
+ _executionResult: ExecutionResult,
124
+ ): string | undefined => {
125
+ const queryDuration =
126
+ dataQualityRelationValidationConfigurationState.executionDuration
127
+ ? prettyDuration(
128
+ dataQualityRelationValidationConfigurationState.executionDuration,
129
+ {
130
+ ms: true,
131
+ },
132
+ )
133
+ : undefined;
134
+ if (!queryDuration) {
135
+ return undefined;
136
+ }
137
+ return `lambda ran in ${queryDuration}`;
138
+ };
139
+ const resultDescription =
140
+ !dataQualityRelationValidationConfigurationState.isRunningValidation &&
141
+ lambdaExecutionResult
142
+ ? getResultSetDescription(lambdaExecutionResult)
143
+ : undefined;
144
+
145
+ const confirmExport = (format: string): void => {
146
+ applicationStore.alertService.setActionAlertInfo({
147
+ message: USER_ATTESTATION_MESSAGE,
148
+ type: ActionAlertType.CAUTION,
149
+ actions: [
150
+ {
151
+ label: 'Accept',
152
+ type: ActionAlertActionType.PROCEED_WITH_CAUTION,
153
+ handler: applicationStore.guardUnhandledError(() =>
154
+ exportValidationResults(format),
155
+ ),
156
+ },
157
+ {
158
+ label: 'Decline',
159
+ type: ActionAlertActionType.PROCEED,
160
+ default: true,
161
+ },
162
+ ],
163
+ });
164
+ };
165
+
96
166
  const addParameter = (): void => {
97
167
  dataQualityRelationValidation_addParameter(
98
168
  validationElement.query.parameters,
@@ -269,9 +339,71 @@ const RelationDefinitionEditor = observer(
269
339
  </div>
270
340
  <div className="relation-validation-config-editor__item">
271
341
  <div className="relation-validation-config-editor__definition__item__header">
272
- <div className="relation-validation-config-editor__definition__item__header__title">
273
- RESULT
342
+ <div className="relation-validation-config-editor__definition__item__header-group">
343
+ <div className="relation-validation-config-editor__definition__item__header__title">
344
+ RESULT
345
+ </div>
346
+ {dataQualityRelationValidationConfigurationState.isRunningValidation && (
347
+ <div className="panel__header__title__label__status">
348
+ Running Validation...
349
+ </div>
350
+ )}
351
+ <div
352
+ data-testid={
353
+ DATA_QUALITY_VALIDATION_TEST_ID.DATA_QUALITY_VALIDATION_RESULT_ANALYTICS
354
+ }
355
+ className="data-quality-validation__result__analytics"
356
+ >
357
+ {resultDescription ?? ''}
358
+ </div>
359
+ {lambdaExecutionResult &&
360
+ dataQualityRelationValidationConfigurationState.checkForStaleResults && (
361
+ <div className="data-quality-validation__result__stale-status">
362
+ <div className="data-quality-validation__result__stale-status__icon">
363
+ <ExclamationTriangleIcon />
364
+ </div>
365
+ <div className="data-quality-validation__result__stale-status__label">
366
+ Preview data might be stale
367
+ </div>
368
+ </div>
369
+ )}
274
370
  </div>
371
+ <ControlledDropdownMenu
372
+ className="data-quality-validation__result__export__dropdown"
373
+ title="Export"
374
+ disabled={isExportDisabled}
375
+ content={
376
+ <MenuContent>
377
+ {Object.values(resultState.exportDataFormatOptions).map(
378
+ (format) => (
379
+ <MenuContentItem
380
+ key={format}
381
+ onClick={(): void => confirmExport(format)}
382
+ >
383
+ <MenuContentItemIcon>
384
+ <CsvIcon />
385
+ </MenuContentItemIcon>
386
+ <MenuContentItemLabel>{format}</MenuContentItemLabel>
387
+ </MenuContentItem>
388
+ ),
389
+ )}
390
+ </MenuContent>
391
+ }
392
+ menuProps={{
393
+ anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
394
+ transformOrigin: { vertical: 'top', horizontal: 'right' },
395
+ elevation: 7,
396
+ }}
397
+ >
398
+ <div className="relation-validation-config-editor__definition__item__header__action">
399
+ <div className="data-quality-validation__result__export__dropdown__label">
400
+ Export
401
+ </div>
402
+ <div className="data-quality-validation__result__export__dropdown__trigger">
403
+ <CaretDownIcon />
404
+ </div>
405
+ </div>
406
+ </ControlledDropdownMenu>
275
407
  </div>
276
408
  <div className="relation-validation-config-editor__definition__item__content">
277
409
  <div className="relation-validation-config-editor__definition__result-viewer">
@@ -22,3 +22,6 @@ export enum DATA_QUALITY_VALIDATION_TEST_ID {
22
22
  DATA_QUALITY_VALIDATION_RESULT_PANEL = 'data-quality-result-panel',
23
23
  DATA_QUALITY_VALIDATION_RESULT_ANALYTICS = 'data-quality-result-analytics',
24
24
  }
25
+
26
+ export const USER_ATTESTATION_MESSAGE =
27
+ 'I attest that I am aware of the sensitive data leakage risk when exporting queried data. The data I export will only be used by me.';
@@ -15,10 +15,12 @@
15
15
  */
16
16
 
17
17
  import {
18
+ type ExportDataInfo,
18
19
  buildExecutionParameterValues,
19
20
  ExecutionPlanState,
20
21
  QUERY_BUILDER_EVENT,
21
22
  QueryBuilderTelemetryHelper,
23
+ PARAMETER_SUBMIT_ACTION,
22
24
  } from '@finos/legend-query-builder';
23
25
  import { action, flow, flowResult, makeObservable, observable } from 'mobx';
24
26
  import {
@@ -26,15 +28,22 @@ import {
26
28
  assertErrorThrown,
27
29
  LogEvent,
28
30
  StopWatch,
31
+ getContentTypeFileExtension,
32
+ ActionState,
33
+ ContentType,
34
+ UnsupportedOperationError,
29
35
  } from '@finos/legend-shared';
30
36
  import {
31
37
  type ExecutionResult,
32
38
  type RawExecutionPlan,
33
39
  GRAPH_MANAGER_EVENT,
40
+ V1_DELEGATED_EXPORT_HEADER,
41
+ EXECUTION_SERIALIZATION_FORMAT,
34
42
  } from '@finos/legend-graph';
35
43
  import { getDataQualityPureGraphManagerExtension } from '../../graph-manager/protocol/pure/DSL_DataQuality_PureGraphManagerExtension.js';
36
44
  import type { DataQualityRelationValidationConfigurationState } from './DataQualityRelationValidationConfigurationState.js';
37
45
  import type { DataQualityRelationValidation } from '../../graph/metamodel/pure/packageableElements/data-quality/DataQualityValidationConfiguration.js';
46
+ import { downloadStream } from '@finos/legend-application';
38
47
 
39
48
  export type DataQualityRelationResultCellDataType =
40
49
  | string
@@ -56,6 +65,7 @@ export const DEFAULT_LIMIT = 1000;
56
65
  export class DataQualityRelationResultState {
57
66
  readonly dataQualityRelationValidationConfigurationState: DataQualityRelationValidationConfigurationState;
58
67
  readonly executionPlanState: ExecutionPlanState;
68
+ readonly exportState = ActionState.create();
59
69
 
60
70
  previewLimit = DEFAULT_LIMIT;
61
71
  isRunningValidation = false;
@@ -85,9 +95,11 @@ export class DataQualityRelationResultState {
85
95
  setValidationRunPromise: action,
86
96
  setValidationToRun: action,
87
97
  handleRunValidation: action,
98
+ handleExport: action,
88
99
  runValidation: flow,
89
100
  cancelValidation: flow,
90
101
  generatePlan: flow,
102
+ exportData: flow,
91
103
  });
92
104
 
93
105
  this.dataQualityRelationValidationConfigurationState =
@@ -150,6 +162,32 @@ export class DataQualityRelationResultState {
150
162
  }
151
163
  }
152
164
 
165
+ handleExport(format: string) {
166
+ const queryLambda =
167
+ this.dataQualityRelationValidationConfigurationState
168
+ .bodyExpressionSequence;
169
+ const parameters = (queryLambda.parameters ?? []) as object[];
170
+ if (parameters.length) {
171
+ this.dataQualityRelationValidationConfigurationState.parametersState.parameterStates =
172
+ this.dataQualityRelationValidationConfigurationState.parametersState.build(
173
+ queryLambda,
174
+ );
175
+ this.dataQualityRelationValidationConfigurationState.parametersState.parameterValuesEditorState.open(
176
+ (): Promise<void> =>
177
+ flowResult(this.exportData(format)).catch(
178
+ this.dataQualityRelationValidationConfigurationState.editorStore
179
+ .applicationStore.alertUnhandledError,
180
+ ),
181
+ PARAMETER_SUBMIT_ACTION.EXPORT,
182
+ );
183
+ } else {
184
+ flowResult(this.exportData(format)).catch(
185
+ this.dataQualityRelationValidationConfigurationState.editorStore
186
+ .applicationStore.alertUnhandledError,
187
+ );
188
+ }
189
+ }
190
+
153
191
  *runValidation(): GeneratorFn<void> {
154
192
  let promise;
155
193
  try {
@@ -287,4 +325,81 @@ export class DataQualityRelationResultState {
287
325
  this.isGeneratingPlan = false;
288
326
  }
289
327
  }
328
+
329
+ getExportDataInfo(format: string): ExportDataInfo {
330
+ switch (format) {
331
+ case EXECUTION_SERIALIZATION_FORMAT.CSV:
332
+ return {
333
+ contentType: ContentType.TEXT_CSV,
334
+ serializationFormat: EXECUTION_SERIALIZATION_FORMAT.CSV,
335
+ };
336
+
337
+ default:
338
+ throw new UnsupportedOperationError(
339
+ `Unsupported TDS export type ${format}`,
340
+ );
341
+ }
342
+ }
343
+
344
+ get exportDataFormatOptions(): string[] {
345
+ return [EXECUTION_SERIALIZATION_FORMAT.CSV];
346
+ }
347
+
348
+ *exportData(format: string): GeneratorFn<void> {
349
+ try {
350
+ this.exportState.inProgress();
351
+ const packagePath =
352
+ this.dataQualityRelationValidationConfigurationState.validationElement
353
+ .path;
354
+ const model =
355
+ this.dataQualityRelationValidationConfigurationState.editorStore
356
+ .graphManagerState.graph;
357
+ this.dataQualityRelationValidationConfigurationState.editorStore.applicationStore.notificationService.notifySuccess(
358
+ `Export ${format} will run in background`,
359
+ );
360
+ const exportData = this.getExportDataInfo(format);
361
+ const contentType = exportData.contentType;
362
+ const serializationFormat = exportData.serializationFormat;
363
+ const result = (yield getDataQualityPureGraphManagerExtension(
364
+ this.dataQualityRelationValidationConfigurationState.editorStore
365
+ .graphManagerState.graphManager,
366
+ ).exportData(model, packagePath, {
367
+ serializationFormat,
368
+ previewLimit: this.previewLimit,
369
+ validationName: this.validationToRun?.name,
370
+ lambdaParameterValues: buildExecutionParameterValues(
371
+ this.dataQualityRelationValidationConfigurationState.parametersState
372
+ .parameterStates,
373
+ this.dataQualityRelationValidationConfigurationState.editorStore
374
+ .graphManagerState,
375
+ ),
376
+ })) as Response;
377
+ if (result.headers.get(V1_DELEGATED_EXPORT_HEADER) === 'true') {
378
+ if (result.status === 200) {
379
+ this.exportState.pass();
380
+ } else {
381
+ this.exportState.fail();
382
+ }
383
+ return;
384
+ }
385
+ downloadStream(
386
+ result,
387
+ `result.${getContentTypeFileExtension(contentType)}`,
388
+ exportData.contentType,
389
+ )
390
+ .then(() => {
391
+ this.exportState.pass();
392
+ })
393
+ .catch((error) => {
394
+ assertErrorThrown(error);
395
+ });
396
+ } catch (error) {
397
+ this.exportState.fail();
398
+ assertErrorThrown(error);
399
+ this.dataQualityRelationValidationConfigurationState.editorStore.applicationStore.notificationService.notifyError(
400
+ error,
401
+ );
402
+ this.exportState.complete();
403
+ }
404
+ }
290
405
  }
@@ -32,6 +32,9 @@ import {
32
32
  hashArray,
33
33
  LogEvent,
34
34
  filterByType,
35
+ getContentTypeFileExtension,
36
+ ActionState,
37
+ StopWatch,
35
38
  } from '@finos/legend-shared';
36
39
  import {
37
40
  type ExecutionResult,
@@ -45,6 +48,7 @@ import {
45
48
  buildLambdaVariableExpressions,
46
49
  observe_ValueSpecification,
47
50
  VariableExpression,
51
+ V1_DELEGATED_EXPORT_HEADER,
48
52
  } from '@finos/legend-graph';
49
53
  import {
50
54
  action,
@@ -67,6 +71,7 @@ import { DataQualityRelationResultState } from './DataQualityRelationResultState
67
71
  import { DATA_QUALITY_HASH_STRUCTURE } from '../../graph/metamodel/DSL_DataQuality_HashUtils.js';
68
72
  import type { SelectOption } from '@finos/legend-art';
69
73
  import { getDataQualityPureGraphManagerExtension } from '../../graph-manager/protocol/pure/DSL_DataQuality_PureGraphManagerExtension.js';
74
+ import { downloadStream } from '@finos/legend-application';
70
75
 
71
76
  export enum DATA_QUALITY_RELATION_VALIDATION_EDITOR_TAB {
72
77
  DEFINITION = 'Definition',
@@ -250,6 +255,7 @@ export class RelationDefinitionParameterState extends LambdaParametersState {
250
255
 
251
256
  export class DataQualityRelationValidationConfigurationState extends ElementEditorState {
252
257
  readonly relationFunctionDefinitionEditorState: RelationFunctionDefinitionEditorState;
258
+ readonly exportState = ActionState.create();
253
259
  selectedTab: DATA_QUALITY_RELATION_VALIDATION_EDITOR_TAB;
254
260
 
255
261
  isRunningValidation = false;
@@ -261,6 +267,8 @@ export class DataQualityRelationValidationConfigurationState extends ElementEdit
261
267
  parametersState: RelationDefinitionParameterState;
262
268
  isConvertingValidationLambdaObjects = false;
263
269
  resultState: DataQualityRelationResultState;
270
+ executionDuration?: number | undefined;
271
+ latestRunHashCode?: string | undefined;
264
272
 
265
273
  constructor(
266
274
  editorStore: EditorStore,
@@ -274,18 +282,23 @@ export class DataQualityRelationValidationConfigurationState extends ElementEdit
274
282
  validationRunPromise: observable,
275
283
  executionResult: observable,
276
284
  resultState: observable,
285
+ executionDuration: observable,
286
+ latestRunHashCode: observable,
277
287
  setSelectedTab: action,
278
288
  setValidationRunPromise: action,
279
289
  setExecutionResult: action,
280
290
  addValidationState: action,
281
291
  resetResultState: action,
292
+ setExecutionDuration: action,
282
293
  validationElement: computed,
283
294
  relationValidationOptions: computed,
295
+ checkForStaleResults: computed,
284
296
  runValidation: flow,
285
297
  handleRunValidation: flow,
286
298
  convertValidationLambdaObjects: flow,
287
299
  cancelValidationRun: flow,
288
300
  generatePlan: flow,
301
+ exportData: flow,
289
302
  });
290
303
  assertType(
291
304
  element,
@@ -358,6 +371,17 @@ export class DataQualityRelationValidationConfigurationState extends ElementEdit
358
371
  }));
359
372
  }
360
373
 
374
+ get checkForStaleResults(): boolean {
375
+ if (this.latestRunHashCode !== this.hashCode) {
376
+ return true;
377
+ }
378
+ return false;
379
+ }
380
+
381
+ setExecutionDuration(val: number | undefined): void {
382
+ this.executionDuration = val;
383
+ }
384
+
361
385
  resetResultState(): void {
362
386
  this.resultState = new DataQualityRelationResultState(this);
363
387
  }
@@ -468,8 +492,10 @@ export class DataQualityRelationValidationConfigurationState extends ElementEdit
468
492
  let promise;
469
493
  try {
470
494
  this.setIsRunningValidation(true);
495
+ const currentHashCode = this.hashCode;
471
496
  const packagePath = this.validationElement.path;
472
497
  const model = this.editorStore.graphManagerState.graph;
498
+ const stopWatch = new StopWatch();
473
499
 
474
500
  promise = getDataQualityPureGraphManagerExtension(
475
501
  this.editorStore.graphManagerState.graphManager,
@@ -486,6 +512,8 @@ export class DataQualityRelationValidationConfigurationState extends ElementEdit
486
512
 
487
513
  if (this.validationRunPromise === promise) {
488
514
  this.setExecutionResult(result);
515
+ this.latestRunHashCode = currentHashCode;
516
+ this.setExecutionDuration(stopWatch.elapsed);
489
517
  }
490
518
  } catch (error) {
491
519
  if (this.validationRunPromise === promise) {
@@ -569,6 +597,74 @@ export class DataQualityRelationValidationConfigurationState extends ElementEdit
569
597
  }
570
598
  }
571
599
 
600
+ *exportData(format: string): GeneratorFn<void> {
601
+ try {
602
+ this.exportState.inProgress();
603
+ const packagePath = this.validationElement.path;
604
+ const model = this.editorStore.graphManagerState.graph;
605
+ this.editorStore.applicationStore.notificationService.notifySuccess(
606
+ `Export ${format} will run in background`,
607
+ );
608
+ const exportData = this.resultState.getExportDataInfo(format);
609
+ const contentType = exportData.contentType;
610
+ const serializationFormat = exportData.serializationFormat;
611
+ const result = (yield getDataQualityPureGraphManagerExtension(
612
+ this.editorStore.graphManagerState.graphManager,
613
+ ).exportData(model, packagePath, {
614
+ serializationFormat,
615
+ runQuery: true,
616
+ lambdaParameterValues: buildExecutionParameterValues(
617
+ this.parametersState.parameterStates,
618
+ this.editorStore.graphManagerState,
619
+ ),
620
+ })) as Response;
621
+ if (result.headers.get(V1_DELEGATED_EXPORT_HEADER) === 'true') {
622
+ if (result.status === 200) {
623
+ this.exportState.pass();
624
+ } else {
625
+ this.exportState.fail();
626
+ }
627
+ return;
628
+ }
629
+ downloadStream(
630
+ result,
631
+ `result.${getContentTypeFileExtension(contentType)}`,
632
+ exportData.contentType,
633
+ )
634
+ .then(() => {
635
+ this.exportState.pass();
636
+ })
637
+ .catch((error) => {
638
+ assertErrorThrown(error);
639
+ });
640
+ } catch (error) {
641
+ this.exportState.fail();
642
+ assertErrorThrown(error);
643
+ this.editorStore.applicationStore.notificationService.notifyError(error);
644
+ this.exportState.complete();
645
+ }
646
+ }
647
+
648
+ handleExport(format: string) {
649
+ const queryLambda = this.bodyExpressionSequence;
650
+ const parameters = (queryLambda.parameters ?? []) as object[];
651
+ if (parameters.length) {
652
+ this.parametersState.parameterStates =
653
+ this.parametersState.build(queryLambda);
654
+ this.parametersState.parameterValuesEditorState.open(
655
+ (): Promise<void> =>
656
+ flowResult(this.exportData(format)).catch(
657
+ this.editorStore.applicationStore.alertUnhandledError,
658
+ ),
659
+ PARAMETER_SUBMIT_ACTION.EXPORT,
660
+ );
661
+ } else {
662
+ flowResult(this.exportData(format)).catch(
663
+ this.editorStore.applicationStore.alertUnhandledError,
664
+ );
665
+ }
666
+ }
667
+
572
668
  get hashCode(): string {
573
669
  return hashArray([
574
670
  DATA_QUALITY_HASH_STRUCTURE.DATA_QUALITY_RELATION_VALIDATION,
@@ -23,6 +23,7 @@ import {
23
23
  type RawLambda,
24
24
  type ParameterValue,
25
25
  type RawVariableExpression,
26
+ type EXECUTION_SERIALIZATION_FORMAT,
26
27
  PackageableElement,
27
28
  hashRawLambda,
28
29
  } from '@finos/legend-graph';
@@ -41,6 +42,7 @@ export interface DQExecuteInputOptions {
41
42
  validationName?: string | undefined;
42
43
  previewLimit?: number | undefined;
43
44
  runQuery?: boolean | undefined;
45
+ serializationFormat?: EXECUTION_SERIALIZATION_FORMAT | undefined;
44
46
  }
45
47
 
46
48
  export abstract class DataQualityExecutionContext implements Hashable {
@@ -38,6 +38,12 @@ export abstract class DSL_DataQuality_PureGraphManagerExtension extends Abstract
38
38
  options: DQExecuteInputOptions,
39
39
  ): Promise<ExecutionResult>;
40
40
 
41
+ abstract exportData(
42
+ graph: PureModel,
43
+ packagePath: string,
44
+ options: DQExecuteInputOptions,
45
+ ): Promise<Response>;
46
+
41
47
  abstract debugExecutionPlanGeneration(
42
48
  graph: PureModel,
43
49
  packagePath: string,