Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

* 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.*


### Fixed

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
31 changes: 31 additions & 0 deletions web/src/components/datasets/DatasetColumnLineage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0

import { Box } from '@material-ui/core'
import MqEmpty from '../core/empty/MqEmpty'
import MqJson from '../core/code/MqJson'
import React, { FunctionComponent } from 'react'

interface DatasetColumnLineageProps {
columnLineage: object
}

const DatasetColumnLineage: FunctionComponent<DatasetColumnLineageProps> = props => {
const { columnLineage } = props

return (
<Box>
Comment thread
tito12 marked this conversation as resolved.
Outdated
{columnLineage
? (
<Box mt={2}>
<MqJson code={columnLineage} />
</Box>
Comment thread
tito12 marked this conversation as resolved.
Outdated
)
: (
<MqEmpty title={'No column lineage'} body={'Column lineage not available for the specified dataset.'} />
)
}
</Box>
)
}

export default DatasetColumnLineage
70 changes: 43 additions & 27 deletions web/src/components/datasets/DatasetDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { ChangeEvent, FunctionComponent, SetStateAction, useEffect } from

import * as Redux from 'redux'
import { Box, Chip, Tab, Tabs } from '@material-ui/core'
import { DatasetVersion } from '../../types/api'
import { Dataset, DatasetVersion } from '../../types/api'
import { IState } from '../../store/reducers'
import {
Theme as ITheme,
Expand All @@ -15,10 +15,16 @@ import {
import { LineageDataset } from '../lineage/types'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { fetchDatasetVersions, resetDatasetVersions } from '../../store/actionCreators'
import {
fetchDataset,
resetDataset,
fetchDatasetVersions,
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'
Expand All @@ -40,29 +46,23 @@ 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[]
dataset: Dataset
versionsLoading: boolean
isDatasetInit: boolean
}

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

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

const DatasetDetailPage: FunctionComponent<IProps> = props => {
const { classes, fetchDatasetVersions, resetDatasetVersions, versions, versionsLoading } = props
const { classes, fetchDatasetVersions, fetchDataset, 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 () => {
resetDatasetVersions()
}
useEffect(() => () => {
resetDataset()
resetDatasetVersions()
}, [])

const [tab, setTab] = React.useState(0)
const handleChange = (event: ChangeEvent, newValue: SetStateAction<number>) => {
setTab(newValue)
}

const handleFetchDataset = () => {
if(!props.isDatasetInit) {
fetchDataset(props.lineageDataset.namespace, props.lineageDataset.name)
}
return true
}
Comment thread
tito12 marked this conversation as resolved.
Outdated

if (versionsLoading) {
return (
<Box display={'flex'} justifyContent={'center'}>
Expand All @@ -108,8 +114,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 +142,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,27 +162,32 @@ 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 && handleFetchDataset() && <DatasetColumnLineage columnLineage={props.dataset.columnLineage} />}
Comment thread
tito12 marked this conversation as resolved.
Outdated
</Box>
)
}

const mapStateToProps = (state: IState) => ({
datasets: state.datasets.result,
versions: state.datasetVersions.result.versions,
versionsLoading: state.datasetVersions.isLoading
dataset: state.dataset.result,
versionsLoading: state.datasetVersions.isLoading,
isDatasetInit: state.dataset.init,
})

const mapDispatchToProps = (dispatch: Redux.Dispatch) =>
bindActionCreators(
{
fetchDatasetVersions: fetchDatasetVersions,
resetDatasetVersions: resetDatasetVersions
fetchDataset: fetchDataset,
resetDatasetVersions: resetDatasetVersions,
resetDataset: resetDataset
},
dispatch
)
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 @@ -57,7 +57,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 @@ -39,6 +39,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 @@ -58,6 +73,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
30 changes: 30 additions & 0 deletions web/src/store/reducers/dataset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 events, { IEventsState } from './events'
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
9 changes: 8 additions & 1 deletion web/src/store/requests/datasets.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0

import { API_URL } from '../../globals'
import { DatasetVersions, Datasets } from '../../types/api'
import { Dataset, DatasetVersions, Datasets } from "../../types/api";
import { genericFetchWrapper } from './index'

export const getDatasets = async (namespace: string, limit = 25, offset = 0) => {
Expand All @@ -26,3 +26,10 @@ export const getDatasetVersions = async (
(versions: DatasetVersions) => versions.versions
)
}

export const getDataset = async (namespace: string, dataset: string) => {
const url = `${API_URL}/namespaces/${encodeURIComponent(namespace)}/datasets/${encodeURIComponent(
dataset
)}`
return genericFetchWrapper(url, { method: 'GET' }, 'fetchDataset').then((d: Dataset) => d)
}
23 changes: 18 additions & 5 deletions web/src/store/sagas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
FETCH_LINEAGE,
FETCH_RUNS,
FETCH_SEARCH,
FETCH_EVENTS
} from '../actionCreators/actionTypes'
FETCH_EVENTS, FETCH_DATASET
} from "../actionCreators/actionTypes";
import { Namespaces } from '../../types/api'
import { all, put, take } from 'redux-saga/effects'

Expand All @@ -24,9 +24,9 @@ import {
fetchLineageSuccess,
fetchNamespacesSuccess,
fetchRunsSuccess,
fetchSearchSuccess
} from '../actionCreators'
import { getDatasetVersions, getDatasets, getEvents, getJobs, getNamespaces, getRuns } from '../requests'
fetchSearchSuccess, fetchDatasetSuccess
} from "../actionCreators";
import { getDatasetVersions, getDatasets, getDataset, getEvents, getJobs, getNamespaces, getRuns } from '../requests'
import { getLineage } from '../requests/lineage'
import { getSearch } from '../requests/search'

Expand Down Expand Up @@ -112,6 +112,18 @@ export function* fetchEventsSaga() {
}
}

export function* fetchDatasetSaga() {
while (true) {
try {
const { payload } = yield take(FETCH_DATASET)
const datasets = yield call(getDataset, payload.namespace, payload.name)
yield put(fetchDatasetSuccess(datasets))
} catch (e) {
yield put(applicationError('Something went wrong while fetching dataset'))
}
}
}

export function* fetchDatasetVersionsSaga() {
while (true) {
try {
Expand All @@ -130,6 +142,7 @@ export default function* rootSaga(): Generator {
fetchJobsSaga(),
fetchRunsSaga(),
fetchDatasetsSaga(),
fetchDatasetSaga(),
fetchDatasetVersionsSaga(),
fetchEventsSaga(),
fetchLineage(),
Expand Down
Loading