From df3a7f14e56cac6cef4c2eeacb008badcbe74985 Mon Sep 17 00:00:00 2001 From: Peter Hicks Date: Tue, 7 May 2024 15:27:41 -0700 Subject: [PATCH] Web: Data Quality (#2810) * Quality and node display * Fixing display on column lineage title. * Fixing bad status icon and adding divider to tooltip. * Fixing minor theme details. * Minor code review updates. * UX tweaks * Adding updated at --------- Co-authored-by: phix --- web/src/components/core/copy/MqCopy.tsx | 7 +- .../core/date-picker/MqDatePicker.tsx | 7 ++ web/src/components/core/tooltip/MQTooltip.tsx | 6 +- web/src/components/datasets/Assertions.tsx | 65 ++++++++++++++++ .../components/datasets/DatasetDetailPage.tsx | 65 +++++++++++++--- web/src/components/jobs/Runs.tsx | 6 +- .../namespace-select/NamespaceSelect.tsx | 9 +++ web/src/helpers/nodes.ts | 8 +- web/src/i18n/config.ts | 2 +- .../routes/column-level/ColumnLevelDrawer.tsx | 54 ++++++++++--- web/src/routes/datasets/Datasets.tsx | 33 +++++--- .../table-level/TableLineageDatasetNode.tsx | 77 ++++++++++++++++--- .../table-level/TableLineageJobNode.tsx | 33 +++++++- web/src/types/api.ts | 12 +-- 14 files changed, 329 insertions(+), 55 deletions(-) create mode 100644 web/src/components/datasets/Assertions.tsx diff --git a/web/src/components/core/copy/MqCopy.tsx b/web/src/components/core/copy/MqCopy.tsx index 829aaaab14..ce62eecf31 100644 --- a/web/src/components/core/copy/MqCopy.tsx +++ b/web/src/components/core/copy/MqCopy.tsx @@ -1,9 +1,10 @@ // Copyright 2018-2023 contributors to the Marquez project // SPDX-License-Identifier: Apache-2.0 -import { Snackbar, Tooltip } from '@mui/material' +import { Snackbar } from '@mui/material' import ContentCopyIcon from '@mui/icons-material/ContentCopy' import IconButton from '@mui/material/IconButton' +import MQTooltip from '../tooltip/MQTooltip' import React from 'react' interface MqCopyProps { @@ -21,7 +22,7 @@ const MqEmpty: React.FC = ({ string }) => { } return ( <> - + { event.stopPropagation() @@ -34,7 +35,7 @@ const MqEmpty: React.FC = ({ string }) => { > - + = ({ return ( void + onClose?: (event: React.SyntheticEvent) => void placement?: | 'left' | 'right' @@ -25,10 +27,12 @@ interface MqToolTipProps { | 'right-start' } -const MQTooltip: React.FC = ({ title, children, placement }) => { +const MQTooltip: React.FC = ({ title, onOpen, onClose, children, placement }) => { const theme = createTheme(useTheme()) return ( = ({ assertions, hasHeader }) => { + if (assertions.length === 0) { + return null + } + return ( + + {hasHeader && ( + + + + COLUMN + + + ASSERTION + + + STATUS + + + + )} + + {assertions.map((assertion) => { + const sx = { borderBottom: 'none' } + return ( + + + {assertion.column} + + + {assertion.assertion} + + + { + + } + + + ) + })} + +
+ ) +} + +export default Assertions diff --git a/web/src/components/datasets/DatasetDetailPage.tsx b/web/src/components/datasets/DatasetDetailPage.tsx index 796f2d57fb..9962d6eeef 100644 --- a/web/src/components/datasets/DatasetDetailPage.tsx +++ b/web/src/components/datasets/DatasetDetailPage.tsx @@ -23,7 +23,7 @@ import { MqInfo } from '../core/info/MqInfo' import { alpha } from '@mui/material/styles' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import { datasetFacetsStatus } from '../../helpers/nodes' +import { datasetFacetsQualityAssertions, datasetFacetsStatus } from '../../helpers/nodes' import { deleteDataset, dialogToggle, @@ -38,6 +38,7 @@ import { formatUpdatedAt } from '../../helpers' import { truncateText } from '../../helpers/text' import { useNavigate, useSearchParams } from 'react-router-dom' import { useTheme } from '@emotion/react' +import Assertions from './Assertions' import CloseIcon from '@mui/icons-material/Close' import DatasetInfo from './DatasetInfo' import DatasetTags from './DatasetTags' @@ -45,9 +46,11 @@ import DatasetVersions from './DatasetVersions' import Dialog from '../Dialog' import IconButton from '@mui/material/IconButton' import ListIcon from '@mui/icons-material/List' +import MQTooltip from '../core/tooltip/MQTooltip' import MqStatus from '../core/status/MqStatus' import MqText from '../core/text/MqText' import React, { ChangeEvent, FunctionComponent, useEffect, useState } from 'react' +import RuleIcon from '@mui/icons-material/Rule' import StorageIcon from '@mui/icons-material/Storage' interface StateProps { @@ -143,6 +146,8 @@ const DatasetDetailPage: FunctionComponent = (props) => { const { name, tags, description } = firstVersion const facetsStatus = datasetFacetsStatus(firstVersion.facets) + const assertions = datasetFacetsQualityAssertions(firstVersion.facets) + return ( = (props) => { mb={2} > - {facetsStatus && ( - - - - )} @@ -224,27 +224,74 @@ const DatasetDetailPage: FunctionComponent = (props) => { - + } label={'Updated at'.toUpperCase()} value={formatUpdatedAt(firstVersion.createdAt)} /> - + } label={'Dataset Type'.toUpperCase()} value={{firstVersion.type}} /> - + } label={'Fields'.toUpperCase()} value={`${firstVersion.fields.length} columns`} /> + + } + label={'Quality'.toUpperCase()} + value={ + facetsStatus ? ( + + assertion.success)} + /> + } + > + + assertion.success).length + } Passing`.toUpperCase()} + color={theme.palette.primary.main} + /> + + + + !assertion.success)} + /> + } + > + + !assertion.success).length + } Failing`.toUpperCase()} + color={theme.palette.error.main} + /> + + + + ) : ( + + ) + } + /> + diff --git a/web/src/components/jobs/Runs.tsx b/web/src/components/jobs/Runs.tsx index 401c04ebe1..f69ebe7b80 100644 --- a/web/src/components/jobs/Runs.tsx +++ b/web/src/components/jobs/Runs.tsx @@ -25,7 +25,6 @@ import MqStatus from '../core/status/MqStatus' import MqText from '../core/text/MqText' import React, { FunctionComponent, SetStateAction } from 'react' import RunInfo from './RunInfo' -import RunStatus from './RunStatus' interface RunsProps { runs: Run[] @@ -139,10 +138,7 @@ const Runs: FunctionComponent = (props) => { > {run.id} - - - {run.state} - + {formatUpdatedAt(run.createdAt)} {formatUpdatedAt(run.startedAt)} diff --git a/web/src/components/namespace-select/NamespaceSelect.tsx b/web/src/components/namespace-select/NamespaceSelect.tsx index 4494fa3361..8c73a6414a 100644 --- a/web/src/components/namespace-select/NamespaceSelect.tsx +++ b/web/src/components/namespace-select/NamespaceSelect.tsx @@ -59,6 +59,15 @@ const NamespaceSelect: React.FC = ({