Skip to content

Commit

Permalink
MR | export feature in data quality relation validation (finos#3772)
Browse files Browse the repository at this point in the history
  • Loading branch information
viju4076 authored Dec 30, 2024
1 parent 5f31e37 commit de26c72
Show file tree
Hide file tree
Showing 15 changed files with 521 additions and 18 deletions.
4 changes: 4 additions & 0 deletions .changeset/chilly-chairs-hunt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
'@finos/legend-graph': patch
'@finos/legend-query-builder': patch
---
5 changes: 5 additions & 0 deletions .changeset/good-rings-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@finos/legend-extension-dsl-data-quality': patch
---

export feature in data quality relation validation
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
*/

import { observer } from 'mobx-react-lite';
import { useApplicationStore } from '@finos/legend-application';
import {
ActionAlertActionType,
ActionAlertType,
useApplicationStore,
} from '@finos/legend-application';
import { flowResult } from 'mobx';
import {
ExecutionPlanViewer,
Expand All @@ -24,7 +28,10 @@ import {
import { type ExecutionResult } from '@finos/legend-graph';
import { prettyDuration } from '@finos/legend-shared';
import React, { useRef, useState } from 'react';
import { DATA_QUALITY_VALIDATION_TEST_ID } from './constants/DataQualityConstants.js';
import {
DATA_QUALITY_VALIDATION_TEST_ID,
USER_ATTESTATION_MESSAGE,
} from './constants/DataQualityConstants.js';
import {
type SelectOption,
BlankPanelContent,
Expand All @@ -43,6 +50,7 @@ import {
PauseCircleIcon,
PlayIcon,
ReportIcon,
CsvIcon,
} from '@finos/legend-art';
import { DataQualityResultValues } from './DataQualityResultValues.js';
import type { DataQualityRelationValidationConfigurationState } from './states/DataQualityRelationValidationConfigurationState.js';
Expand All @@ -57,6 +65,31 @@ export const DataQualityRelationTrialRuns = observer(
dataQualityRelationValidationConfigurationState.resultState;
const executionResult = resultState.executionResult;

const exportValidationResults = async (format: string): Promise<void> => {
resultState.handleExport(format);
};

const confirmExport = (format: string): void => {
applicationStore.alertService.setActionAlertInfo({
message: USER_ATTESTATION_MESSAGE,
type: ActionAlertType.CAUTION,
actions: [
{
label: 'Accept',
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
handler: applicationStore.guardUnhandledError(() =>
exportValidationResults(format),
),
},
{
label: 'Decline',
type: ActionAlertActionType.PROCEED,
default: true,
},
],
});
};

const runQuery = (): void => {
if (!resultState.isRunningValidation) {
resultState.handleRunValidation();
Expand All @@ -74,8 +107,10 @@ export const DataQualityRelationTrialRuns = observer(
flowResult(resultState.generatePlan(true)),
);

const isRunQueryDisabled =
resultState.isGeneratingPlan || resultState.isRunningValidation;
const isRunValidationDisabled =
!resultState.validationToRun ||
resultState.isGeneratingPlan ||
resultState.isRunningValidation;

const getResultSetDescription = (
_executionResult: ExecutionResult,
Expand Down Expand Up @@ -238,20 +273,20 @@ export const DataQualityRelationTrialRuns = observer(
className="btn__dropdown-combo__label data-quality-validation__result__execute-btn__validation data-quality-validation__result__execute-btn__btn data-quality-validation__result__execute-btn__btn--green"
onClick={runQuery}
tabIndex={-1}
disabled={isRunQueryDisabled}
disabled={isRunValidationDisabled}
>
<PlayIcon />
Run Validation
</button>
<ControlledDropdownMenu
className="btn__dropdown-combo__dropdown-btn data-quality-validation__result__execute-btn__btn data-quality-validation__result__execute-btn__btn--green"
disabled={isRunQueryDisabled}
disabled={isRunValidationDisabled}
content={
<MenuContent>
<MenuContentItem
className="btn__dropdown-combo__option"
onClick={generatePlan}
disabled={isRunQueryDisabled}
disabled={isRunValidationDisabled}
>
<MenuContentItemIcon>
<ReportIcon />
Expand All @@ -263,7 +298,7 @@ export const DataQualityRelationTrialRuns = observer(
<MenuContentItem
className="btn__dropdown-combo__option"
onClick={debugPlanGeneration}
disabled={isRunQueryDisabled}
disabled={isRunValidationDisabled}
>
<MenuContentItemIcon>
<DebugIcon />
Expand All @@ -282,6 +317,40 @@ export const DataQualityRelationTrialRuns = observer(
</>
)}
</div>
<ControlledDropdownMenu
className="data-quality-validation__result__export__dropdown"
title="Export"
disabled={isRunValidationDisabled}
content={
<MenuContent>
{Object.values(resultState.exportDataFormatOptions).map(
(format) => (
<MenuContentItem
key={format}
onClick={(): void => confirmExport(format)}
>
<MenuContentItemIcon>
<CsvIcon />
</MenuContentItemIcon>
<MenuContentItemLabel>{format}</MenuContentItemLabel>
</MenuContentItem>
),
)}
</MenuContent>
}
menuProps={{
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
transformOrigin: { vertical: 'top', horizontal: 'right' },
elevation: 7,
}}
>
<div className="data-quality-validation__result__export__dropdown__label">
Export
</div>
<div className="data-quality-validation__result__export__dropdown__trigger">
<CaretDownIcon />
</div>
</ControlledDropdownMenu>
</div>
</div>
<PanelContent className="data-quality-validation__result__content">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,33 @@ import {
CaretDownIcon,
clsx,
ControlledDropdownMenu,
CsvIcon,
DragPreviewLayer,
ExclamationTriangleIcon,
MenuContent,
MenuContentItem,
MenuContentItemIcon,
MenuContentItemLabel,
Panel,
PanelContent,
PanelLoadingIndicator,
PauseCircleIcon,
PlayIcon,
PlusIcon,
} from '@finos/legend-art';
import { prettyCONSTName, returnUndefOnError } from '@finos/legend-shared';
import {
prettyCONSTName,
prettyDuration,
returnUndefOnError,
} from '@finos/legend-shared';
import {
ExecutionPlanViewer,
LambdaEditor,
LambdaParameterValuesEditor,
} from '@finos/legend-query-builder';
import {
type RawVariableExpression,
type ExecutionResult,
PrimitiveType,
stub_RawVariableExpression,
Type,
Expand All @@ -57,6 +66,8 @@ import {
TDSExecutionResult,
} from '@finos/legend-graph';
import {
ActionAlertActionType,
ActionAlertType,
DEFAULT_TAB_SIZE,
useApplicationNavigationContext,
useApplicationStore,
Expand All @@ -77,6 +88,10 @@ import { DataQualityRelationValidationsEditor } from './DataQualityRelationValid
import { CodeEditor } from '@finos/legend-lego/code-editor';
import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
import { DataQualityRelationGridResult } from './DataQualityRelationGridResult.js';
import {
DATA_QUALITY_VALIDATION_TEST_ID,
USER_ATTESTATION_MESSAGE,
} from './constants/DataQualityConstants.js';

const RelationDefinitionEditor = observer(
(props: {
Expand All @@ -85,6 +100,9 @@ const RelationDefinitionEditor = observer(
const { dataQualityRelationValidationConfigurationState } = props;
const { relationFunctionDefinitionEditorState, resultState } =
dataQualityRelationValidationConfigurationState;
const {
editorStore: { applicationStore },
} = dataQualityRelationValidationConfigurationState;
const validationElement =
dataQualityRelationValidationConfigurationState.validationElement;
const lambdaExecutionResult =
Expand All @@ -93,6 +111,58 @@ const RelationDefinitionEditor = observer(
const isReadOnly =
dataQualityRelationValidationConfigurationState.isReadOnly;

const isExportDisabled =
dataQualityRelationValidationConfigurationState.isRunningValidation ||
dataQualityRelationValidationConfigurationState.isGeneratingPlan;

const exportValidationResults = async (format: string): Promise<void> => {
dataQualityRelationValidationConfigurationState.handleExport(format);
};

const getResultSetDescription = (
_executionResult: ExecutionResult,
): string | undefined => {
const queryDuration =
dataQualityRelationValidationConfigurationState.executionDuration
? prettyDuration(
dataQualityRelationValidationConfigurationState.executionDuration,
{
ms: true,
},
)
: undefined;
if (!queryDuration) {
return undefined;
}
return `lambda ran in ${queryDuration}`;
};
const resultDescription =
!dataQualityRelationValidationConfigurationState.isRunningValidation &&
lambdaExecutionResult
? getResultSetDescription(lambdaExecutionResult)
: undefined;

const confirmExport = (format: string): void => {
applicationStore.alertService.setActionAlertInfo({
message: USER_ATTESTATION_MESSAGE,
type: ActionAlertType.CAUTION,
actions: [
{
label: 'Accept',
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
handler: applicationStore.guardUnhandledError(() =>
exportValidationResults(format),
),
},
{
label: 'Decline',
type: ActionAlertActionType.PROCEED,
default: true,
},
],
});
};

const addParameter = (): void => {
dataQualityRelationValidation_addParameter(
validationElement.query.parameters,
Expand Down Expand Up @@ -269,9 +339,71 @@ const RelationDefinitionEditor = observer(
</div>
<div className="relation-validation-config-editor__item">
<div className="relation-validation-config-editor__definition__item__header">
<div className="relation-validation-config-editor__definition__item__header__title">
RESULT
<div className="relation-validation-config-editor__definition__item__header-group">
<div className="relation-validation-config-editor__definition__item__header__title">
RESULT
</div>
{dataQualityRelationValidationConfigurationState.isRunningValidation && (
<div className="panel__header__title__label__status">
Running Validation...
</div>
)}
<div
data-testid={
DATA_QUALITY_VALIDATION_TEST_ID.DATA_QUALITY_VALIDATION_RESULT_ANALYTICS
}
className="data-quality-validation__result__analytics"
>
{resultDescription ?? ''}
</div>
{lambdaExecutionResult &&
dataQualityRelationValidationConfigurationState.checkForStaleResults && (
<div className="data-quality-validation__result__stale-status">
<div className="data-quality-validation__result__stale-status__icon">
<ExclamationTriangleIcon />
</div>
<div className="data-quality-validation__result__stale-status__label">
Preview data might be stale
</div>
</div>
)}
</div>
<ControlledDropdownMenu
className="data-quality-validation__result__export__dropdown"
title="Export"
disabled={isExportDisabled}
content={
<MenuContent>
{Object.values(resultState.exportDataFormatOptions).map(
(format) => (
<MenuContentItem
key={format}
onClick={(): void => confirmExport(format)}
>
<MenuContentItemIcon>
<CsvIcon />
</MenuContentItemIcon>
<MenuContentItemLabel>{format}</MenuContentItemLabel>
</MenuContentItem>
),
)}
</MenuContent>
}
menuProps={{
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
transformOrigin: { vertical: 'top', horizontal: 'right' },
elevation: 7,
}}
>
<div className="relation-validation-config-editor__definition__item__header__action">
<div className="data-quality-validation__result__export__dropdown__label">
Export
</div>
<div className="data-quality-validation__result__export__dropdown__trigger">
<CaretDownIcon />
</div>
</div>
</ControlledDropdownMenu>
</div>
<div className="relation-validation-config-editor__definition__item__content">
<div className="relation-validation-config-editor__definition__result-viewer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ export enum DATA_QUALITY_VALIDATION_TEST_ID {
DATA_QUALITY_VALIDATION_RESULT_PANEL = 'data-quality-result-panel',
DATA_QUALITY_VALIDATION_RESULT_ANALYTICS = 'data-quality-result-analytics',
}

export const USER_ATTESTATION_MESSAGE =
'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.';
Loading

0 comments on commit de26c72

Please sign in to comment.