Skip to content

Commit

Permalink
Web: Data Quality (#2810)
Browse files Browse the repository at this point in the history
* 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 <peter.hicks@astronomer.io>
  • Loading branch information
phixMe and phix authored May 7, 2024
1 parent 00b6d35 commit df3a7f1
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 55 deletions.
7 changes: 4 additions & 3 deletions web/src/components/core/copy/MqCopy.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -21,7 +22,7 @@ const MqEmpty: React.FC<MqCopyProps> = ({ string }) => {
}
return (
<>
<Tooltip title='Copy'>
<MQTooltip title='Copy'>
<IconButton
onClick={(event) => {
event.stopPropagation()
Expand All @@ -34,7 +35,7 @@ const MqEmpty: React.FC<MqCopyProps> = ({ string }) => {
>
<ContentCopyIcon fontSize={'small'} />
</IconButton>
</Tooltip>
</MQTooltip>
<Snackbar
open={open}
autoHideDuration={2000}
Expand Down
7 changes: 7 additions & 0 deletions web/src/components/core/date-picker/MqDatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ const MqDatePicker: React.FC<DatePickerProps> = ({
return (
<DateTimePicker
label={label}
slotProps={{
desktopPaper: {
sx: {
backgroundImage: 'none',
},
},
}}
sx={{
label: {
left: theme.spacing(2),
Expand Down
6 changes: 5 additions & 1 deletion web/src/components/core/tooltip/MQTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import Tooltip from '@mui/material/Tooltip'
interface MqToolTipProps {
title: string | ReactElement
children: ReactElement
onOpen?: (event: React.SyntheticEvent) => void
onClose?: (event: React.SyntheticEvent) => void
placement?:
| 'left'
| 'right'
Expand All @@ -25,10 +27,12 @@ interface MqToolTipProps {
| 'right-start'
}

const MQTooltip: React.FC<MqToolTipProps> = ({ title, children, placement }) => {
const MQTooltip: React.FC<MqToolTipProps> = ({ title, onOpen, onClose, children, placement }) => {
const theme = createTheme(useTheme())
return (
<Tooltip
onOpen={onOpen}
onClose={onClose}
title={title}
placement={placement || 'bottom'}
componentsProps={{
Expand Down
65 changes: 65 additions & 0 deletions web/src/components/datasets/Assertions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: Apache-2.0

import { Assertion } from '../../types/api'
import { Table, TableBody, TableCell, TableHead, TableRow } from '@mui/material'
import { theme } from '../../helpers/theme'
import MqStatus from '../core/status/MqStatus'
import MqText from '../core/text/MqText'
import React from 'react'

interface OwnProps {
assertions: Assertion[]
hasHeader?: boolean
}

const Assertions: React.FC<OwnProps> = ({ assertions, hasHeader }) => {
if (assertions.length === 0) {
return null
}
return (
<Table size={'small'}>
{hasHeader && (
<TableHead>
<TableRow>
<TableCell align={'left'}>
<MqText bold>COLUMN</MqText>
</TableCell>
<TableCell align={'left'}>
<MqText bold>ASSERTION</MqText>
</TableCell>
<TableCell align={'left'}>
<MqText bold>STATUS</MqText>
</TableCell>
</TableRow>
</TableHead>
)}
<TableBody>
{assertions.map((assertion) => {
const sx = { borderBottom: 'none' }
return (
<TableRow key={`${assertion.column}-${assertion.assertion}`}>
<TableCell align={'left'} sx={sx}>
<MqText font={'mono'}>{assertion.column}</MqText>
</TableCell>
<TableCell align={'left'} sx={sx}>
<MqText subdued>{assertion.assertion}</MqText>
</TableCell>
<TableCell align={'left'} sx={sx}>
{
<MqStatus
label={assertion.success ? 'pass'.toUpperCase() : 'fail'.toUpperCase()}
color={
assertion.success ? theme.palette.primary.main : theme.palette.error.main
}
></MqStatus>
}
</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
)
}

export default Assertions
65 changes: 56 additions & 9 deletions web/src/components/datasets/DatasetDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -38,16 +38,19 @@ 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'
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 {
Expand Down Expand Up @@ -143,6 +146,8 @@ const DatasetDetailPage: FunctionComponent<IProps> = (props) => {
const { name, tags, description } = firstVersion
const facetsStatus = datasetFacetsStatus(firstVersion.facets)

const assertions = datasetFacetsQualityAssertions(firstVersion.facets)

return (
<Box px={2}>
<Box
Expand All @@ -155,11 +160,6 @@ const DatasetDetailPage: FunctionComponent<IProps> = (props) => {
mb={2}
>
<Box display={'flex'} alignItems={'center'} justifyContent={'space-between'} pb={2}>
{facetsStatus && (
<Box mr={1}>
<MqStatus label={'Quality'} color={facetsStatus} />
</Box>
)}
<Box display={'flex'} alignItems={'center'}>
<Box>
<Box display={'flex'} alignItems={'center'}>
Expand Down Expand Up @@ -224,27 +224,74 @@ const DatasetDetailPage: FunctionComponent<IProps> = (props) => {
</Box>
</Box>
<Grid container spacing={2}>
<Grid item xs={4}>
<Grid item xs={6}>
<MqInfo
icon={<CalendarIcon color={'disabled'} />}
label={'Updated at'.toUpperCase()}
value={formatUpdatedAt(firstVersion.createdAt)}
/>
</Grid>
<Grid item xs={4}>
<Grid item xs={6}>
<MqInfo
icon={<StorageIcon color={'disabled'} />}
label={'Dataset Type'.toUpperCase()}
value={<MqText font={'mono'}>{firstVersion.type}</MqText>}
/>
</Grid>
<Grid item xs={4}>
<Grid item xs={6}>
<MqInfo
icon={<ListIcon color={'disabled'} />}
label={'Fields'.toUpperCase()}
value={`${firstVersion.fields.length} columns`}
/>
</Grid>
<Grid item xs={6}>
<MqInfo
icon={<RuleIcon color={'disabled'} />}
label={'Quality'.toUpperCase()}
value={
facetsStatus ? (
<Box display={'flex'}>
<MQTooltip
title={
<Assertions
assertions={assertions.filter((assertion) => assertion.success)}
/>
}
>
<Box>
<MqStatus
label={`${
assertions.filter((assertion) => assertion.success).length
} Passing`.toUpperCase()}
color={theme.palette.primary.main}
/>
</Box>
</MQTooltip>
<Divider sx={{ mx: 1 }} orientation={'vertical'} />
<MQTooltip
title={
<Assertions
assertions={assertions.filter((assertion) => !assertion.success)}
/>
}
>
<Box>
<MqStatus
label={`${
assertions.filter((assertion) => !assertion.success).length
} Failing`.toUpperCase()}
color={theme.palette.error.main}
/>
</Box>
</MQTooltip>
</Box>
) : (
<MqStatus label={'N/A'} color={theme.palette.secondary.main} />
)
}
/>
</Grid>
</Grid>
<Divider sx={{ my: 2 }} />
<Box display={'flex'} justifyContent={'space-between'} alignItems={'center'}>
Expand Down
6 changes: 1 addition & 5 deletions web/src/components/jobs/Runs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down Expand Up @@ -139,10 +138,7 @@ const Runs: FunctionComponent<RunsProps> = (props) => {
>
<TableCell align='left'>{run.id}</TableCell>
<TableCell align='left'>
<Box display={'flex'} alignItems={'center'}>
<RunStatus run={run} />
<MqText>{run.state}</MqText>
</Box>
<MqStatus color={runStateColor(run.state)} label={run.state} />
</TableCell>
<TableCell align='left'>{formatUpdatedAt(run.createdAt)}</TableCell>
<TableCell align='left'>{formatUpdatedAt(run.startedAt)}</TableCell>
Expand Down
9 changes: 9 additions & 0 deletions web/src/components/namespace-select/NamespaceSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ const NamespaceSelect: React.FC<NamespaceSelectProps> = ({
</MqText>
</Box>
<Select
inputProps={{
MenuProps: {
PaperProps: {
sx: {
backgroundImage: 'none',
},
},
},
}}
labelId='namespace-label'
id='namespace-select'
value={selectedNamespace}
Expand Down
8 changes: 7 additions & 1 deletion web/src/helpers/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ export function jobRunsStatus(runs: Run[], limit = 14) {
return theme.palette.primary.main as string
}
}
export function datasetFacetsQualityAssertions(facets: DataQualityFacets) {
const assertions = facets?.dataQualityAssertions?.assertions
if (!assertions) {
return []
} else return assertions
}

export function datasetFacetsStatus(facets: DataQualityFacets, limit = 14) {
const assertions = facets?.dataQualityAssertions?.assertions?.slice(-limit)
Expand All @@ -121,7 +127,7 @@ export function datasetFacetsStatus(facets: DataQualityFacets, limit = 14) {
if (isAllFalse) {
return theme.palette.error.main as string
} else if (isSomeFalse) {
return theme.palette.info.main as string
return theme.palette.error.main as string
} else {
return theme.palette.primary.main as string
}
Expand Down
2 changes: 1 addition & 1 deletion web/src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ i18next
namespace_col: 'NAMESPACE',
source_col: 'SOURCE',
updated_col: 'UPDATED AT',
status_col: 'STATUS',
quality: 'QUALITY',
},
datasets_column_lineage: {
empty_title: 'No column lineage',
Expand Down
Loading

0 comments on commit df3a7f1

Please sign in to comment.