Skip to content

Commit 34928ad

Browse files
authored
fix(ui): humanize timestamps on ML entities UI (datahub-project#12788)
1 parent 372feee commit 34928ad

File tree

7 files changed

+85
-66
lines changed

7 files changed

+85
-66
lines changed

datahub-web-react/src/app/entity/dataProcessInstance/profile/DataProcessInstanceSummary.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import styled from 'styled-components';
33
import { Space, Table, Typography } from 'antd';
44
import { formatDetailedDuration } from '@src/app/shared/time/timeUtils';
55
import { capitalize } from 'lodash';
6-
import moment from 'moment';
6+
import { Pill } from '@components';
77
import { MlHyperParam, MlMetric, DataProcessInstanceRunResultType } from '../../../../types.generated';
88
import { useBaseEntity } from '../../shared/EntityContext';
99
import { InfoItem } from '../../shared/components/styled/InfoItem';
1010
import { GetDataProcessInstanceQuery } from '../../../../graphql/dataProcessInstance.generated';
11-
import { Pill } from '../../../../alchemy-components/components/Pills';
11+
import { TimestampPopover } from '../../../sharedV2/TimestampPopover';
1212

1313
const TabContent = styled.div`
1414
padding: 16px;
@@ -39,7 +39,7 @@ const propertyTableColumns = [
3939
},
4040
];
4141

42-
export default function MLModelSummary() {
42+
export default function DataProcessInstanceSummary() {
4343
const baseEntity = useBaseEntity<GetDataProcessInstanceQuery>();
4444
const dpi = baseEntity?.dataProcessInstance;
4545

@@ -61,11 +61,7 @@ export default function MLModelSummary() {
6161
<Typography.Title level={3}>Details</Typography.Title>
6262
<InfoItemContainer justifyContent="left">
6363
<InfoItem title="Created At">
64-
<InfoItemContent>
65-
{dpi?.properties?.created?.time
66-
? moment(dpi.properties.created.time).format('YYYY-MM-DD HH:mm:ss')
67-
: '-'}
68-
</InfoItemContent>
64+
<TimestampPopover timestamp={dpi?.properties?.created?.time} title="Created At" />
6965
</InfoItem>
7066
<InfoItem title="Status">
7167
<InfoItemContent>{formatStatus(dpi?.state)}</InfoItemContent>

datahub-web-react/src/app/entity/mlModel/profile/MLModelSummary.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import styled from 'styled-components';
33
import { Space, Table, Typography } from 'antd';
44
import { Link } from 'react-router-dom';
55
import { colors } from '@src/alchemy-components/theme';
6-
import moment from 'moment';
76
import { useEntityRegistry } from '../../../useEntityRegistry';
87
import { MlHyperParam, MlMetric, EntityType } from '../../../../types.generated';
98
import { useBaseEntity } from '../../shared/EntityContext';
109
import { GetMlModelQuery } from '../../../../graphql/mlModel.generated';
1110
import { InfoItem } from '../../shared/components/styled/InfoItem';
1211
import { notEmpty } from '../../shared/utils';
1312
import { Pill } from '../../../../alchemy-components/components/Pills';
13+
import { TimestampPopover } from '../../../sharedV2/TimestampPopover';
1414

1515
const TabContent = styled.div`
1616
padding: 16px;
@@ -85,21 +85,13 @@ export default function MLModelSummary() {
8585
<InfoItemContent>{model?.versionProperties?.version?.versionTag}</InfoItemContent>
8686
</InfoItem>
8787
<InfoItem title="Registered At">
88-
<InfoItemContent>
89-
{model?.properties?.created?.time
90-
? moment(model.properties.created.time).format('YYYY-MM-DD HH:mm:ss')
91-
: '-'}
92-
</InfoItemContent>
88+
<TimestampPopover timestamp={model?.properties?.created?.time} title="Registered At" />
9389
</InfoItem>
9490
<InfoItem title="Last Modified At">
95-
<InfoItemContent>
96-
{model?.properties?.lastModified?.time
97-
? moment(model.properties.lastModified.time).format('YYYY-MM-DD HH:mm:ss')
98-
: '-'}
99-
</InfoItemContent>
91+
<TimestampPopover timestamp={model?.properties?.lastModified?.time} title="Last Modified At" />
10092
</InfoItem>
10193
<InfoItem title="Created By">
102-
<InfoItemContent>{model?.properties?.created?.actor}</InfoItemContent>
94+
<InfoItemContent>{model?.properties?.created?.actor || '-'}</InfoItemContent>
10395
</InfoItem>
10496
</InfoItemContainer>
10597
<InfoItemContainer justifyContent="left">

datahub-web-react/src/app/entity/mlModelGroup/profile/ModelGroupModels.tsx

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import React from 'react';
33
import styled from 'styled-components';
44
import { colors } from '@src/alchemy-components/theme';
55
import { Pill } from '@src/alchemy-components/components/Pills';
6-
import moment from 'moment';
76
import { GetMlModelGroupQuery } from '../../../../graphql/mlModelGroup.generated';
87
import { EntityType } from '../../../../types.generated';
98
import { useEntityRegistry } from '../../../useEntityRegistry';
109
import { useBaseEntity } from '../../shared/EntityContext';
1110
import { notEmpty } from '../../shared/utils';
1211
import { EmptyTab } from '../../shared/components/styled/EmptyTab';
1312
import { InfoItem } from '../../shared/components/styled/InfoItem';
13+
import { TimestampPopover } from '../../../sharedV2/TimestampPopover';
1414

1515
const InfoItemContainer = styled.div<{ justifyContent }>`
1616
display: flex;
@@ -33,6 +33,7 @@ const NameLink = styled.a`
3333
font-weight: 700;
3434
color: inherit;
3535
font-size: 0.9rem;
36+
3637
&:hover {
3738
color: ${colors.blue[400]} !important;
3839
}
@@ -101,11 +102,7 @@ export default function MLGroupModels() {
101102
key: 'createdAt',
102103
width: 150,
103104
render: (_: any, record: any) => (
104-
<Typography.Text>
105-
{record.properties?.createdTS?.time
106-
? moment(record.properties.createdTS.time).format('YYYY-MM-DD HH:mm:ss')
107-
: '-'}
108-
</Typography.Text>
105+
<TimestampPopover timestamp={record.properties?.createdTS?.time} title="Created At" showPopover />
109106
),
110107
},
111108
{
@@ -159,18 +156,10 @@ export default function MLGroupModels() {
159156
<Typography.Title level={3}>Model Group Details</Typography.Title>
160157
<InfoItemContainer justifyContent="left">
161158
<InfoItem title="Created At">
162-
<InfoItemContent>
163-
{modelGroup?.properties?.created?.time
164-
? moment(modelGroup.properties.created.time).format('YYYY-MM-DD HH:mm:ss')
165-
: '-'}
166-
</InfoItemContent>
159+
<TimestampPopover timestamp={modelGroup?.properties?.created?.time} title="Created At" />
167160
</InfoItem>
168161
<InfoItem title="Last Modified At">
169-
<InfoItemContent>
170-
{modelGroup?.properties?.lastModified?.time
171-
? moment(modelGroup.properties.lastModified.time).format('YYYY-MM-DD HH:mm:ss')
172-
: '-'}
173-
</InfoItemContent>
162+
<TimestampPopover timestamp={modelGroup?.properties?.lastModified?.time} title="Last Modified At" />
174163
</InfoItem>
175164
{modelGroup?.properties?.created?.actor && (
176165
<InfoItem title="Created By">

datahub-web-react/src/app/entityV2/mlModel/profile/MLModelSummary.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import styled from 'styled-components';
1010
import { Space, Table, Typography } from 'antd';
1111
import { Link } from 'react-router-dom';
1212
import { colors } from '@src/alchemy-components/theme';
13-
import moment from 'moment';
13+
import { TimestampPopover } from '../../../sharedV2/TimestampPopover';
1414

1515
const TabContent = styled.div`
1616
padding: 16px;
@@ -87,21 +87,13 @@ export default function MLModelSummary() {
8787
<InfoItemContent>{model?.versionProperties?.version?.versionTag}</InfoItemContent>
8888
</InfoItem>
8989
<InfoItem title="Registered At">
90-
<InfoItemContent>
91-
{model?.properties?.created?.time
92-
? moment(model.properties.created.time).format('YYYY-MM-DD HH:mm:ss')
93-
: '-'}
94-
</InfoItemContent>
90+
<TimestampPopover timestamp={model?.properties?.created?.time} title="Registered At" />
9591
</InfoItem>
9692
<InfoItem title="Last Modified At">
97-
<InfoItemContent>
98-
{model?.properties?.lastModified?.time
99-
? moment(model.properties.lastModified.time).format('YYYY-MM-DD HH:mm:ss')
100-
: '-'}
101-
</InfoItemContent>
93+
<TimestampPopover timestamp={model?.properties?.lastModified?.time} title="Last Modified At" />
10294
</InfoItem>
10395
<InfoItem title="Created By">
104-
<InfoItemContent>{model?.properties?.created?.actor}</InfoItemContent>
96+
<InfoItemContent>{model?.properties?.created?.actor || '-'}</InfoItemContent>
10597
</InfoItem>
10698
</InfoItemContainer>
10799
<InfoItemContainer justifyContent="left">

datahub-web-react/src/app/entityV2/mlModelGroup/profile/ModelGroupModels.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import React from 'react';
1010
import styled from 'styled-components';
1111
import { colors } from '@src/alchemy-components/theme';
1212
import { Pill } from '@src/alchemy-components/components/Pills';
13-
import moment from 'moment';
13+
import { TimestampPopover } from '../../../sharedV2/TimestampPopover';
1414

1515
const InfoItemContainer = styled.div<{ justifyContent }>`
1616
display: flex;
@@ -104,11 +104,7 @@ export default function MLGroupModels() {
104104
key: 'createdAt',
105105
width: 150,
106106
render: (_: any, record: any) => (
107-
<Typography.Text>
108-
{record.properties?.createdTS?.time
109-
? moment(record.properties.createdTS.time).format('YYYY-MM-DD HH:mm:ss')
110-
: '-'}
111-
</Typography.Text>
107+
<TimestampPopover timestamp={record.properties?.createdTS?.time} title="Created At" showPopover />
112108
),
113109
},
114110
{
@@ -162,18 +158,10 @@ export default function MLGroupModels() {
162158
<Typography.Title level={3}>Model Group Details</Typography.Title>
163159
<InfoItemContainer justifyContent="left">
164160
<InfoItem title="Created At">
165-
<InfoItemContent>
166-
{modelGroup?.properties?.created?.time
167-
? moment(modelGroup.properties.created.time).format('YYYY-MM-DD HH:mm:ss')
168-
: '-'}
169-
</InfoItemContent>
161+
<TimestampPopover timestamp={modelGroup?.properties?.created?.time} title="Created At" />
170162
</InfoItem>
171163
<InfoItem title="Last Modified At">
172-
<InfoItemContent>
173-
{modelGroup?.properties?.lastModified?.time
174-
? moment(modelGroup.properties.lastModified.time).format('YYYY-MM-DD HH:mm:ss')
175-
: '-'}
176-
</InfoItemContent>
164+
<TimestampPopover timestamp={modelGroup?.properties?.lastModified?.time} title="Last Modified At" />
177165
</InfoItem>
178166
{modelGroup?.properties?.created?.actor && (
179167
<InfoItem title="Created By">
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import { Popover } from '@components';
4+
import colors from '@src/alchemy-components/theme/foundations/colors';
5+
import { toRelativeTimeString, toLocalDateTimeString } from '@src/app/shared/time/timeUtils';
6+
7+
const PopoverContent = styled.div`
8+
color: ${colors.gray[500]};
9+
font-size: 0.8rem;
10+
`;
11+
12+
const Title = styled.div`
13+
color: ${colors.gray[500]};
14+
border-bottom: none;
15+
font-size: 0.8rem;
16+
font-weight: 600;
17+
`;
18+
19+
const InfoItemContent = styled.div`
20+
padding-top: 8px;
21+
width: 100px;
22+
overflow-wrap: break-word;
23+
`;
24+
25+
const popoverStyles = {
26+
overlayInnerStyle: {
27+
borderRadius: '10px',
28+
},
29+
overlayStyle: {
30+
margin: '5px',
31+
},
32+
};
33+
34+
interface TimestampProps {
35+
timestamp?: number;
36+
title: string;
37+
showPopover?: boolean;
38+
}
39+
40+
export const TimestampPopover: React.FC<TimestampProps> = ({ timestamp, title, showPopover = true }) => {
41+
if (!timestamp) {
42+
return <InfoItemContent>-</InfoItemContent>;
43+
}
44+
45+
const relativeTime = toRelativeTimeString(timestamp);
46+
const absoluteTime = toLocalDateTimeString(timestamp);
47+
48+
if (!showPopover) {
49+
return <InfoItemContent>{relativeTime}</InfoItemContent>;
50+
}
51+
52+
return (
53+
<Popover
54+
content={<PopoverContent>{absoluteTime}</PopoverContent>}
55+
title={<Title>{title}</Title>}
56+
trigger="hover"
57+
overlayInnerStyle={popoverStyles.overlayInnerStyle}
58+
overlayStyle={popoverStyles.overlayStyle}
59+
>
60+
<InfoItemContent>{relativeTime}</InfoItemContent>
61+
</Popover>
62+
);
63+
};

smoke-test/tests/cypress/cypress/e2e/ml/model_mlflow.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ describe("models", () => {
2121
cy.wait("@graphqlRequest");
2222

2323
// Ensure page has loaded by checking for specific content
24-
cy.contains("2025-03-03").should("be.visible");
25-
cy.contains("2025-03-04").should("be.visible");
24+
cy.contains("ago").should("be.visible"); // relative time
2625
cy.contains("urn:li:corpuser:datahub").should("be.visible");
2726

2827
// Navigate to Properties tab with verification

0 commit comments

Comments
 (0)