mirror of
https://github.com/datahub-project/datahub.git
synced 2025-10-07 06:54:48 +00:00
feat(React): deprecation status in header (#2097)
This commit is contained in:
parent
c2698b99f1
commit
7f2ca12e36
1
datahub-web-react/.eslintignore
Normal file
1
datahub-web-react/.eslintignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
**/*.graphql
|
@ -0,0 +1,65 @@
|
|||||||
|
import { Avatar, Badge, Popover, Space, Tooltip, Typography } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Dataset, EntityType } from '../../../../types.generated';
|
||||||
|
import { useEntityRegistry } from '../../../useEntityRegistry';
|
||||||
|
import defaultAvatar from '../../../../images/default_avatar.png';
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
dataset: Dataset;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function DatasetHeader({ dataset: { description, ownership, deprecation } }: Props) {
|
||||||
|
const entityRegistry = useEntityRegistry();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Typography.Paragraph>{description}</Typography.Paragraph>
|
||||||
|
<Space direction="vertical">
|
||||||
|
<Avatar.Group maxCount={6} size="large">
|
||||||
|
{ownership &&
|
||||||
|
ownership.owners &&
|
||||||
|
ownership.owners.map((owner: any) => (
|
||||||
|
<Tooltip title={owner.owner.info?.fullName}>
|
||||||
|
<Link to={`/${entityRegistry.getPathName(EntityType.CorpUser)}/${owner.owner.urn}`}>
|
||||||
|
<Avatar
|
||||||
|
style={{
|
||||||
|
color: '#f56a00',
|
||||||
|
backgroundColor: '#fde3cf',
|
||||||
|
}}
|
||||||
|
src={
|
||||||
|
(owner.owner.editableInfo && owner.owner.editableInfo.pictureLink) ||
|
||||||
|
defaultAvatar
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
|
</Avatar.Group>
|
||||||
|
<div>
|
||||||
|
{deprecation?.deprecated && (
|
||||||
|
<Popover
|
||||||
|
placement="bottomLeft"
|
||||||
|
content={
|
||||||
|
<>
|
||||||
|
<Typography.Paragraph>By: {deprecation?.actor}</Typography.Paragraph>
|
||||||
|
{deprecation.decommissionTime && (
|
||||||
|
<Typography.Paragraph>
|
||||||
|
On: {new Date(deprecation?.decommissionTime).toUTCString()}
|
||||||
|
</Typography.Paragraph>
|
||||||
|
)}
|
||||||
|
{deprecation?.note && (
|
||||||
|
<Typography.Paragraph>{deprecation.note}</Typography.Paragraph>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
title="Deprecated"
|
||||||
|
>
|
||||||
|
<Badge count="Deprecated" />
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -1,17 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Avatar, Tooltip, Typography } from 'antd';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { useGetDatasetQuery, useUpdateDatasetMutation } from '../../../../graphql/dataset.generated';
|
import { useGetDatasetQuery, useUpdateDatasetMutation } from '../../../../graphql/dataset.generated';
|
||||||
import defaultAvatar from '../../../../images/default_avatar.png';
|
|
||||||
import { Ownership as OwnershipView } from './Ownership';
|
import { Ownership as OwnershipView } from './Ownership';
|
||||||
import SchemaView from './schema/Schema';
|
import SchemaView from './schema/Schema';
|
||||||
import { EntityProfile } from '../../../shared/EntityProfile';
|
import { EntityProfile } from '../../../shared/EntityProfile';
|
||||||
import { Dataset, EntityType } from '../../../../types.generated';
|
import { Dataset } from '../../../../types.generated';
|
||||||
import { useEntityRegistry } from '../../../useEntityRegistry';
|
|
||||||
import LineageView from './Lineage';
|
import LineageView from './Lineage';
|
||||||
import PropertiesView from './Properties';
|
import PropertiesView from './Properties';
|
||||||
import DocumentsView from './Documentation';
|
import DocumentsView from './Documentation';
|
||||||
import { sampleDownstreamEntities, sampleUpstreamEntities } from './stories/lineageEntities';
|
import { sampleDownstreamEntities, sampleUpstreamEntities } from './stories/lineageEntities';
|
||||||
|
import DatasetHeader from './DatasetHeader';
|
||||||
|
|
||||||
export enum TabType {
|
export enum TabType {
|
||||||
Ownership = 'Ownership',
|
Ownership = 'Ownership',
|
||||||
@ -28,37 +25,10 @@ const EMPTY_ARR: never[] = [];
|
|||||||
* Responsible for display the Dataset Page
|
* Responsible for display the Dataset Page
|
||||||
*/
|
*/
|
||||||
export const Profile = ({ urn }: { urn: string }): JSX.Element => {
|
export const Profile = ({ urn }: { urn: string }): JSX.Element => {
|
||||||
const entityRegistry = useEntityRegistry();
|
|
||||||
|
|
||||||
const { loading, error, data } = useGetDatasetQuery({ variables: { urn } });
|
const { loading, error, data } = useGetDatasetQuery({ variables: { urn } });
|
||||||
|
|
||||||
const [updateDataset] = useUpdateDatasetMutation();
|
const [updateDataset] = useUpdateDatasetMutation();
|
||||||
|
|
||||||
const getBody = (description: string, ownership: any) => (
|
const getHeader = (dataset: Dataset) => <DatasetHeader dataset={dataset} />;
|
||||||
<>
|
|
||||||
<Typography.Paragraph>{description}</Typography.Paragraph>
|
|
||||||
<Avatar.Group maxCount={6} size="large">
|
|
||||||
{ownership &&
|
|
||||||
ownership.owners &&
|
|
||||||
ownership.owners.map((owner: any) => (
|
|
||||||
<Tooltip title={owner.owner.info?.fullName}>
|
|
||||||
<Link to={`/${entityRegistry.getPathName(EntityType.CorpUser)}/${owner.owner.urn}`}>
|
|
||||||
<Avatar
|
|
||||||
style={{
|
|
||||||
color: '#f56a00',
|
|
||||||
backgroundColor: '#fde3cf',
|
|
||||||
}}
|
|
||||||
src={
|
|
||||||
(owner.owner.editableInfo && owner.owner.editableInfo.pictureLink) ||
|
|
||||||
defaultAvatar
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</Tooltip>
|
|
||||||
))}
|
|
||||||
</Avatar.Group>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
const getTabs = ({ ownership, properties, institutionalMemory, schema }: Dataset) => {
|
const getTabs = ({ ownership, properties, institutionalMemory, schema }: Dataset) => {
|
||||||
return [
|
return [
|
||||||
@ -118,8 +88,8 @@ export const Profile = ({ urn }: { urn: string }): JSX.Element => {
|
|||||||
<EntityProfile
|
<EntityProfile
|
||||||
title={data.dataset.name}
|
title={data.dataset.name}
|
||||||
tags={data.dataset.tags}
|
tags={data.dataset.tags}
|
||||||
body={getBody(data.dataset?.description || '', data.dataset?.ownership)}
|
|
||||||
tabs={getTabs(data.dataset as Dataset)}
|
tabs={getTabs(data.dataset as Dataset)}
|
||||||
|
header={getHeader(data.dataset as Dataset)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{error && <p>Failed to load dataset with urn {urn}</p>}
|
{error && <p>Failed to load dataset with urn {urn}</p>}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Story, Meta } from '@storybook/react';
|
||||||
|
|
||||||
|
import TestPageContainer from '../../../../../utils/test-utils/TestPageContainer';
|
||||||
|
import DatasetHeader, { Props } from '../DatasetHeader';
|
||||||
|
import { sampleDataset, sampleDeprecatedDataset } from './sampleDataset';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Dataset Profile / DatasetHeader',
|
||||||
|
component: DatasetHeader,
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<Props> = (args) => <DatasetHeader {...args} />;
|
||||||
|
|
||||||
|
export const DescriptionAndOwner = Template.bind({});
|
||||||
|
DescriptionAndOwner.args = { dataset: sampleDataset };
|
||||||
|
DescriptionAndOwner.decorators = [
|
||||||
|
(InnerStory) => (
|
||||||
|
<>
|
||||||
|
<TestPageContainer>
|
||||||
|
<InnerStory />
|
||||||
|
</TestPageContainer>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
export const Deprecated = Template.bind({});
|
||||||
|
Deprecated.args = { dataset: sampleDeprecatedDataset };
|
||||||
|
Deprecated.decorators = [
|
||||||
|
(InnerStory) => (
|
||||||
|
<>
|
||||||
|
<TestPageContainer>
|
||||||
|
<InnerStory />
|
||||||
|
</TestPageContainer>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
];
|
@ -0,0 +1,53 @@
|
|||||||
|
import { Dataset, EntityType, FabricType, OwnershipType } from '../../../../../types.generated';
|
||||||
|
|
||||||
|
export const sampleDataset: Dataset = {
|
||||||
|
__typename: 'Dataset',
|
||||||
|
urn: 'test:urn',
|
||||||
|
platform: {
|
||||||
|
type: EntityType.DataPlatform,
|
||||||
|
urn: 'test:hive:urn',
|
||||||
|
name: 'hive',
|
||||||
|
},
|
||||||
|
name: 'hive dataset',
|
||||||
|
origin: FabricType.Prod,
|
||||||
|
description: 'Some description',
|
||||||
|
type: EntityType.Dataset,
|
||||||
|
created: { time: 1 },
|
||||||
|
lastModified: { time: 1 },
|
||||||
|
tags: [],
|
||||||
|
ownership: {
|
||||||
|
owners: [
|
||||||
|
{ owner: { urn: 'user:urn', type: EntityType.CorpUser, username: 'UserA' }, type: OwnershipType.Dataowner },
|
||||||
|
],
|
||||||
|
lastModified: { time: 1 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sampleDeprecatedDataset: Dataset = {
|
||||||
|
__typename: 'Dataset',
|
||||||
|
urn: 'test:urn',
|
||||||
|
platform: {
|
||||||
|
type: EntityType.DataPlatform,
|
||||||
|
urn: 'test:hive:urn',
|
||||||
|
name: 'hive',
|
||||||
|
},
|
||||||
|
name: 'hive dataset',
|
||||||
|
origin: FabricType.Prod,
|
||||||
|
description: 'Some deprecated description',
|
||||||
|
type: EntityType.Dataset,
|
||||||
|
created: { time: 1 },
|
||||||
|
lastModified: { time: 1 },
|
||||||
|
tags: [],
|
||||||
|
ownership: {
|
||||||
|
owners: [
|
||||||
|
{ owner: { urn: 'user:urn', type: EntityType.CorpUser, username: 'UserA' }, type: OwnershipType.Dataowner },
|
||||||
|
],
|
||||||
|
lastModified: { time: 1 },
|
||||||
|
},
|
||||||
|
deprecation: {
|
||||||
|
actor: 'UserB',
|
||||||
|
deprecated: true,
|
||||||
|
note: "Don't touch this dataset with a 10 foot pole",
|
||||||
|
decommissionTime: 1612565520292,
|
||||||
|
},
|
||||||
|
};
|
@ -5,7 +5,7 @@ import { RoutedTabs } from './RoutedTabs';
|
|||||||
export interface EntityProfileProps {
|
export interface EntityProfileProps {
|
||||||
title: string;
|
title: string;
|
||||||
tags?: Array<string>;
|
tags?: Array<string>;
|
||||||
body: React.ReactNode;
|
header: React.ReactNode;
|
||||||
tabs?: Array<{
|
tabs?: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
path: string;
|
path: string;
|
||||||
@ -21,8 +21,8 @@ const defaultProps = {
|
|||||||
/**
|
/**
|
||||||
* A default container view for presenting Entity details.
|
* A default container view for presenting Entity details.
|
||||||
*/
|
*/
|
||||||
export const EntityProfile = ({ title: _title, tags: _tags, body: _body, tabs: _tabs }: EntityProfileProps) => {
|
export const EntityProfile = ({ title, tags, header, tabs }: EntityProfileProps) => {
|
||||||
const defaultTabPath = _tabs && _tabs?.length > 0 ? _tabs[0].path : '';
|
const defaultTabPath = tabs && tabs?.length > 0 ? tabs[0].path : '';
|
||||||
|
|
||||||
/* eslint-disable spaced-comment */
|
/* eslint-disable spaced-comment */
|
||||||
return (
|
return (
|
||||||
@ -30,18 +30,18 @@ export const EntityProfile = ({ title: _title, tags: _tags, body: _body, tabs: _
|
|||||||
<Row style={{ padding: '20px 0px 10px 0px' }}>
|
<Row style={{ padding: '20px 0px 10px 0px' }}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<div>
|
<div>
|
||||||
<h1 style={{ float: 'left' }}>{_title}</h1>
|
<h1 style={{ float: 'left' }}>{title}</h1>
|
||||||
<div style={{ float: 'left', margin: '5px 20px' }}>
|
<div style={{ float: 'left', margin: '5px 20px' }}>
|
||||||
{_tags && _tags.map((t) => <Tag color="blue">{t}</Tag>)}
|
{tags && tags.map((t) => <Tag color="blue">{t}</Tag>)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{_body}
|
{header}
|
||||||
<Divider style={{ marginBottom: '0px' }} />
|
<Divider style={{ marginBottom: '0px' }} />
|
||||||
<Row style={{ padding: '0px 0px 10px 0px' }}>
|
<Row style={{ padding: '0px 0px 10px 0px' }}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<RoutedTabs defaultPath={defaultTabPath} tabs={_tabs || []} />
|
<RoutedTabs defaultPath={defaultTabPath} tabs={tabs || []} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
|
@ -78,6 +78,12 @@ query getDataset($urn: String!) {
|
|||||||
}
|
}
|
||||||
primaryKeys
|
primaryKeys
|
||||||
}
|
}
|
||||||
|
deprecation {
|
||||||
|
actor
|
||||||
|
deprecated
|
||||||
|
note
|
||||||
|
decommissionTime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,5 +152,11 @@ mutation updateDataset($input: DatasetUpdateInput!) {
|
|||||||
}
|
}
|
||||||
primaryKeys
|
primaryKeys
|
||||||
}
|
}
|
||||||
|
deprecation {
|
||||||
|
actor
|
||||||
|
deprecated
|
||||||
|
note
|
||||||
|
decommissionTime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export default ({ children }: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<EntityRegistryContext.Provider value={entityRegistry}>{children}</EntityRegistryContext.Provider>;
|
<EntityRegistryContext.Provider value={entityRegistry}>{children}</EntityRegistryContext.Provider>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user