Skip to content

Commit

Permalink
present column lineage of a dataset (#2293)
Browse files Browse the repository at this point in the history
* display column lineage JSON

Signed-off-by: Pawel Leszczynski <[email protected]>

* refactoring for display column lineage JSON (#2294)

Signed-off-by: tito1212 <[email protected]>

Signed-off-by: tito1212 <[email protected]>
Co-authored-by: tito1212 <[email protected]>

* Refactoring for display column lineage JSON  (#2301)

* refactoring for display column lineage JSON

Signed-off-by: tito1212 <[email protected]>

* request api after click

Signed-off-by: tito1212 <[email protected]>

Signed-off-by: tito1212 <[email protected]>
Co-authored-by: tito1212 <[email protected]>

* call backend on tab switch

Signed-off-by: Pawel Leszczynski <[email protected]>

* changes after review. refactoring. fix type and name of file

Signed-off-by: tito12 <[email protected]>

* Changes after review. Separate fetching data in child component

Signed-off-by: tito12 <[email protected]>

* eslint fix changes

Signed-off-by: tito12 <[email protected]>

Signed-off-by: Pawel Leszczynski <[email protected]>
Signed-off-by: tito1212 <[email protected]>
Signed-off-by: tito12 <[email protected]>
Co-authored-by: tito12 <[email protected]>
Co-authored-by: tito1212 <[email protected]>
Co-authored-by: Pawel Leszczynski <[email protected]>
  • Loading branch information
4 people authored Dec 27, 2022
1 parent 65669ca commit 39bcd3a
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 33 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

### Added

* Column-lineage endpoints supports point-in-time requests [`#2265`](https://github.com/MarquezProject/marquez/pull/2265) [@pawel-big-lebowski](https://github.com/pawel-big-lebowski)
*Enable requesting `column-lineage` endpoint by a dataset version, job version or dataset field of a specific dataset version.*
* Present column lineage of a dataset [`#2293`](https://github.com/MarquezProject/marquez/pull/2293) [@pawel-big-lebowski](https://github.com/pawel-big-lebowski)
*Column lineage of a dataset with a single level of depth can
be displayed in datase details tab.*
* Add point-in-time requests support to column-lineage endpoints [`#2265`](https://github.com/MarquezProject/marquez/pull/2265) [@pawel-big-lebowski](https://github.com/pawel-big-lebowski)
*Enables requesting `column-lineage` endpoint by a dataset version, job version or dataset field of a specific dataset version.*
* Add column lineage point-in-time Java client methods [`#2269`](https://github.com/MarquezProject/marquez/pull/2269) [@pawel-big-lebowski](https://github.com/pawel-big-lebowski)
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/bottom-bar/BottomBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class BottomBar extends React.Component<BottomBarProps> {
<Box className={classes.overflow} height={bottomBarHeight}>
<Container maxWidth={'lg'} disableGutters={true}>
{lineageJob && <JobDetailPage job={lineageJob} />}
{lineageDataset && <DatasetDetailPage dataset={lineageDataset} />}
{lineageDataset && <DatasetDetailPage lineageDataset={lineageDataset} />}
</Container>
</Box>
</Box>
Expand Down
105 changes: 105 additions & 0 deletions web/src/components/datasets/DatasetColumnLineage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: Apache-2.0

import * as Redux from 'redux'
import { Box, Button } from '@material-ui/core'
import { Dataset } from '../../types/api'
import { IState } from '../../store/reducers'
import { LineageDataset } from '../lineage/types'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { fetchDataset, resetDataset } from '../../store/actionCreators'
import { fileSize } from '../../helpers'
import { saveAs } from 'file-saver'
import MqEmpty from '../core/empty/MqEmpty'
import MqJson from '../core/code/MqJson'
import MqText from '../core/text/MqText'
import React, { FunctionComponent, useEffect } from 'react'

interface DatasetColumnLineageProps {
lineageDataset: LineageDataset
}

interface StateProps {
dataset: Dataset
}

interface DispatchProps {
fetchDataset: typeof fetchDataset
resetDataset: typeof resetDataset
}

type IProps = DatasetColumnLineageProps & DispatchProps & StateProps

const DatasetColumnLineage: FunctionComponent<IProps> = props => {
const { dataset, lineageDataset, fetchDataset, resetDataset } = props
const columnLineage = dataset.columnLineage

useEffect(() => {
fetchDataset(lineageDataset.namespace, lineageDataset.name)
}, [lineageDataset.name])

// unmounting
useEffect(
() => () => {
resetDataset()
},
[]
)

const handleDownloadPayload = (data: object) => {
const title = `${lineageDataset.name}-${lineageDataset.namespace}-columnLineage`
const blob = new Blob([JSON.stringify(data)], { type: 'application/json' })
saveAs(blob, `${title}.json`)
}

return (
<>
{columnLineage ? (
<>
{fileSize(JSON.stringify(columnLineage)).kiloBytes > 500 ? (
<Box p={2}>
<MqEmpty title={'Payload is too big for render'}>
<div>
<MqText subdued>Please click on button and download payload as file</MqText>
<br />
<Button
variant='outlined'
color='primary'
onClick={() => handleDownloadPayload(columnLineage)}
>
Download payload
</Button>
</div>
</MqEmpty>
</Box>
) : (
<MqJson code={columnLineage} wrapLongLines={true} showLineNumbers={true} />
)}
</>
) : (
<MqEmpty
title={'No column lineage'}
body={'Column lineage not available for the specified dataset.'}
/>
)}
</>
)
}

const mapStateToProps = (state: IState) => ({
dataset: state.dataset.result
})

const mapDispatchToProps = (dispatch: Redux.Dispatch) =>
bindActionCreators(
{
fetchDataset: fetchDataset,
resetDataset: resetDataset
},
dispatch
)

export default connect(
mapStateToProps,
mapDispatchToProps
)(DatasetColumnLineage)
65 changes: 38 additions & 27 deletions web/src/components/datasets/DatasetDetailPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: Apache-2.0

import React, { ChangeEvent, FunctionComponent, SetStateAction, useEffect } from 'react'

import * as Redux from 'redux'
import { Box, Chip, Tab, Tabs } from '@material-ui/core'
import { DatasetVersion } from '../../types/api'
Expand All @@ -15,14 +13,20 @@ import {
import { LineageDataset } from '../lineage/types'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { fetchDatasetVersions, resetDatasetVersions } from '../../store/actionCreators'
import {
fetchDatasetVersions,
resetDataset,
resetDatasetVersions
} from '../../store/actionCreators'
import { useHistory } from 'react-router-dom'
import CircularProgress from '@material-ui/core/CircularProgress/CircularProgress'
import CloseIcon from '@material-ui/icons/Close'
import DatasetColumnLineage from './DatasetColumnLineage'
import DatasetInfo from './DatasetInfo'
import DatasetVersions from './DatasetVersions'
import IconButton from '@material-ui/core/IconButton'
import MqText from '../core/text/MqText'
import React, { ChangeEvent, FunctionComponent, SetStateAction, useEffect } from 'react'

const styles = ({ spacing }: ITheme) => {
return createStyles({
Expand All @@ -40,29 +44,20 @@ const styles = ({ spacing }: ITheme) => {
'&:not(:last-of-type)': {
marginRight: spacing(1)
}
},
noData: {
padding: '125px 0 0 0'
},
infoIcon: {
paddingLeft: '3px',
paddingTop: '3px'
},
updated: {
marginTop: '10px'
}
})
}

interface StateProps {
dataset: LineageDataset
lineageDataset: LineageDataset
versions: DatasetVersion[]
versionsLoading: boolean
}

interface DispatchProps {
fetchDatasetVersions: typeof fetchDatasetVersions
resetDatasetVersions: typeof resetDatasetVersions
resetDataset: typeof resetDataset
}

type IProps = IWithStyles<typeof styles> & StateProps & DispatchProps
Expand All @@ -75,21 +70,30 @@ function a11yProps(index: number) {
}

const DatasetDetailPage: FunctionComponent<IProps> = props => {
const { classes, fetchDatasetVersions, resetDatasetVersions, versions, versionsLoading } = props
const {
classes,
fetchDatasetVersions,
resetDataset,
resetDatasetVersions,
versions,
versionsLoading
} = props
const { root } = classes
const history = useHistory()
const i18next = require('i18next')

useEffect(() => {
fetchDatasetVersions(props.dataset.namespace, props.dataset.name)
}, [props.dataset.name])
fetchDatasetVersions(props.lineageDataset.namespace, props.lineageDataset.name)
}, [props.lineageDataset.name])

// unmounting
useEffect(() => {
return () => {
useEffect(
() => () => {
resetDataset()
resetDatasetVersions()
}
}, [])
},
[]
)

const [tab, setTab] = React.useState(0)
const handleChange = (event: ChangeEvent, newValue: SetStateAction<number>) => {
Expand All @@ -108,8 +112,8 @@ const DatasetDetailPage: FunctionComponent<IProps> = props => {
return null
}

const dataset = versions[0]
const { name, tags, description } = dataset
const firstVersion = versions[0]
const { name, tags, description } = firstVersion

return (
<Box my={2} className={root}>
Expand All @@ -136,6 +140,11 @@ const DatasetDetailPage: FunctionComponent<IProps> = props => {
{...a11yProps(1)}
disableRipple={true}
/>
<Tab
label={i18next.t('datasets.column_lineage')}
{...a11yProps(1)}
disableRipple={true}
/>
</Tabs>
</Box>
<IconButton onClick={() => history.push('/datasets')}>
Expand All @@ -151,12 +160,13 @@ const DatasetDetailPage: FunctionComponent<IProps> = props => {
</Box>
{tab === 0 && (
<DatasetInfo
datasetFields={dataset.fields}
facets={dataset.facets}
run={dataset.createdByRun}
datasetFields={firstVersion.fields}
facets={firstVersion.facets}
run={firstVersion.createdByRun}
/>
)}
{tab === 1 && <DatasetVersions versions={props.versions} />}
{tab === 2 && <DatasetColumnLineage lineageDataset={props.lineageDataset} />}
</Box>
)
}
Expand All @@ -171,7 +181,8 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) =>
bindActionCreators(
{
fetchDatasetVersions: fetchDatasetVersions,
resetDatasetVersions: resetDatasetVersions
resetDatasetVersions: resetDatasetVersions,
resetDataset: resetDataset
},
dispatch
)
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/sidenav/Sidenav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ class Sidenav extends React.Component<SidenavProps> {
title={i18next.t('sidenav.events')}
active={this.props.location.pathname === '/events'}
>
<SVG
src="https://raw.githubusercontent.com/MarquezProject/marquez/main/web/src/img/iconSearchArrow.svg"
width={'30px'}
<SVG
src='https://raw.githubusercontent.com/MarquezProject/marquez/main/web/src/img/iconSearchArrow.svg'
width={'30px'}
/>
</MqIconButton>
</RouterLink>
Expand Down
3 changes: 2 additions & 1 deletion web/src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ i18next
},
datasets: {
latest_tab: 'LATEST SCHEMA',
history_tab: 'VERSION HISTORY'
history_tab: 'VERSION HISTORY',
column_lineage: 'COLUMN LINEAGE'
},
datasets_route: {
empty_title: 'No datasets found',
Expand Down
3 changes: 3 additions & 0 deletions web/src/store/actionCreators/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ export const RESET_JOBS = 'RESET_JOBS'

// datasets
export const FETCH_DATASETS = 'FETCH_DATASETS'
export const FETCH_DATASET = 'FETCH_DATASET'
export const FETCH_DATASETS_SUCCESS = 'FETCH_DATASETS_SUCCESS'
export const FETCH_DATASET_SUCCESS = 'FETCH_DATASET_SUCCESS'
export const RESET_DATASETS = 'RESET_DATASETS'
export const RESET_DATASET = 'RESET_DATASET'
export const FETCH_DATASET_VERSIONS = 'FETCH_DATASET_VERSIONS'
export const FETCH_DATASET_VERSIONS_SUCCESS = 'FETCH_DATASET_VERSIONS_SUCCESS'
export const RESET_DATASET_VERSIONS = 'RESET_DATASET_VERSIONS'
Expand Down
19 changes: 19 additions & 0 deletions web/src/store/actionCreators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ export const fetchDatasetsSuccess = (datasets: Dataset[]) => ({
}
})

export const fetchDataset = (namespace: string, name: string) => ({
type: actionTypes.FETCH_DATASET,
payload: {
namespace,
name
}
})

export const fetchDatasetSuccess = (dataset: Dataset) => ({
type: actionTypes.FETCH_DATASET_SUCCESS,
payload: {
dataset
}
})

export const fetchDatasetVersions = (namespace: string, name: string) => ({
type: actionTypes.FETCH_DATASET_VERSIONS,
payload: {
Expand All @@ -67,6 +82,10 @@ export const resetDatasetVersions = () => ({
type: actionTypes.RESET_DATASET_VERSIONS
})

export const resetDataset = () => ({
type: actionTypes.RESET_DATASET
})

export const resetDatasets = () => ({
type: actionTypes.RESET_DATASETS
})
Expand Down
26 changes: 26 additions & 0 deletions web/src/store/reducers/dataset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0

import { Dataset } from '../../types/api'
import { FETCH_DATASET, FETCH_DATASET_SUCCESS, RESET_DATASET } from '../actionCreators/actionTypes'
import { fetchDatasetSuccess } from '../actionCreators'

export type IDatasetState = { isLoading: boolean; result: Dataset; init: boolean }

export const initialState: IDatasetState = { isLoading: false, init: false, result: {} as Dataset }

type IDatasetAction = ReturnType<typeof fetchDatasetSuccess>

export default (state: IDatasetState = initialState, action: IDatasetAction): IDatasetState => {
const { type, payload } = action

switch (type) {
case FETCH_DATASET:
return { ...state, isLoading: true }
case FETCH_DATASET_SUCCESS:
return { ...state, isLoading: false, init: true, result: payload.dataset }
case RESET_DATASET:
return initialState
default:
return state
}
}
3 changes: 3 additions & 0 deletions web/src/store/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { History } from 'history'
import { Reducer, combineReducers } from 'redux'
import { connectRouter } from 'connected-react-router'
import dataset, { IDatasetState } from './dataset'
import datasetVersions, { IDatasetVersionsState } from './datasetVersions'
import datasets, { IDatasetsState } from './datasets'
import display, { IDisplayState } from './display'
Expand All @@ -15,6 +16,7 @@ import search, { ISearchState } from './search'

export interface IState {
datasets: IDatasetsState
dataset: IDatasetState
datasetVersions: IDatasetVersionsState
events: IEventsState
jobs: IJobsState
Expand All @@ -29,6 +31,7 @@ export interface IState {
export default (history: History): Reducer =>
combineReducers({
router: connectRouter(history),
dataset,
datasets,
datasetVersions,
events,
Expand Down
Loading

0 comments on commit 39bcd3a

Please sign in to comment.