@centreon/ui 24.11.12 → 24.11.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Graph/Timeline/ResponsiveTimeline.tsx +147 -0
- package/src/Graph/Timeline/Timeline.cypress.spec.tsx +148 -0
- package/src/Graph/Timeline/Timeline.stories.tsx +91 -0
- package/src/Graph/Timeline/Timeline.tsx +14 -0
- package/src/Graph/Timeline/index.ts +1 -0
- package/src/Graph/Timeline/models.ts +20 -0
- package/src/Graph/Timeline/timeline.styles.ts +11 -0
- package/src/Graph/Timeline/translatedLabel.ts +6 -0
- package/src/Graph/Timeline/useTimeline.ts +90 -0
- package/src/Graph/index.ts +1 -0
- package/src/Listing/EmptyResult/EmptyResult.tsx +1 -1
- package/src/Listing/index.tsx +13 -4
- package/src/components/Layout/PageLayout/PageLayout.styles.ts +2 -2
package/package.json
CHANGED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
dateTimeFormat,
|
|
3
|
+
getXAxisTickFormat,
|
|
4
|
+
useLocaleDateTimeFormat
|
|
5
|
+
} from '@centreon/ui';
|
|
6
|
+
|
|
7
|
+
import { Typography, useTheme } from '@mui/material';
|
|
8
|
+
|
|
9
|
+
import dayjs from 'dayjs';
|
|
10
|
+
|
|
11
|
+
import { userAtom } from '@centreon/ui-context';
|
|
12
|
+
import { Axis } from '@visx/visx';
|
|
13
|
+
|
|
14
|
+
import { scaleTime } from '@visx/scale';
|
|
15
|
+
import { BarRounded } from '@visx/shape';
|
|
16
|
+
import { useAtomValue } from 'jotai';
|
|
17
|
+
import { equals } from 'ramda';
|
|
18
|
+
import { useCallback } from 'react';
|
|
19
|
+
import { Tooltip } from '../../components';
|
|
20
|
+
import { margins } from '../common/margins';
|
|
21
|
+
import type { TimelineProps } from './models';
|
|
22
|
+
import { useStyles } from './timeline.styles';
|
|
23
|
+
import { useTimeline } from './useTimeline';
|
|
24
|
+
|
|
25
|
+
interface Props extends TimelineProps {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const axisPadding = 4;
|
|
31
|
+
|
|
32
|
+
const Timeline = ({
|
|
33
|
+
data,
|
|
34
|
+
startDate,
|
|
35
|
+
endDate,
|
|
36
|
+
width,
|
|
37
|
+
height,
|
|
38
|
+
TooltipContent,
|
|
39
|
+
tooltipClassName
|
|
40
|
+
}: Props) => {
|
|
41
|
+
const { classes, cx } = useStyles();
|
|
42
|
+
const { format } = useLocaleDateTimeFormat();
|
|
43
|
+
const { timezone } = useAtomValue(userAtom);
|
|
44
|
+
|
|
45
|
+
const theme = useTheme();
|
|
46
|
+
|
|
47
|
+
const xScale = scaleTime({
|
|
48
|
+
domain: [new Date(startDate), new Date(endDate)],
|
|
49
|
+
range: [margins.left, width - margins.right],
|
|
50
|
+
clamp: true
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const numTicks = Math.min(Math.ceil(width / 82), 12);
|
|
54
|
+
|
|
55
|
+
const { getTimeDifference } = useTimeline();
|
|
56
|
+
|
|
57
|
+
const getFormattedStart = useCallback(
|
|
58
|
+
(start) =>
|
|
59
|
+
format({
|
|
60
|
+
date: dayjs(start).tz(timezone).toDate(),
|
|
61
|
+
formatString: dateTimeFormat
|
|
62
|
+
}),
|
|
63
|
+
[dateTimeFormat, timezone]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const getFormattedEnd = useCallback(
|
|
67
|
+
(end) =>
|
|
68
|
+
format({
|
|
69
|
+
date: dayjs(end).tz(timezone).toDate(),
|
|
70
|
+
formatString: dateTimeFormat
|
|
71
|
+
}),
|
|
72
|
+
[dateTimeFormat, timezone]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<svg width={width} height={height + axisPadding}>
|
|
77
|
+
{data.map(({ start, end, color }, idx) => (
|
|
78
|
+
<Tooltip
|
|
79
|
+
hasCaret
|
|
80
|
+
classes={{
|
|
81
|
+
tooltip: cx(classes.tooltip, tooltipClassName)
|
|
82
|
+
}}
|
|
83
|
+
followCursor={false}
|
|
84
|
+
key={`rect-${start}--${end}`}
|
|
85
|
+
label={
|
|
86
|
+
TooltipContent ? (
|
|
87
|
+
<TooltipContent
|
|
88
|
+
start={getFormattedStart(start)}
|
|
89
|
+
end={getFormattedEnd(end)}
|
|
90
|
+
color={color}
|
|
91
|
+
duration={getTimeDifference({
|
|
92
|
+
start: dayjs(start),
|
|
93
|
+
end: dayjs(end)
|
|
94
|
+
})}
|
|
95
|
+
/>
|
|
96
|
+
) : (
|
|
97
|
+
<div style={{ color }}>
|
|
98
|
+
<Typography variant="body2">
|
|
99
|
+
{getTimeDifference({ start: dayjs(start), end: dayjs(end) })}
|
|
100
|
+
</Typography>
|
|
101
|
+
<Typography variant="body2">{`${format({ date: start, formatString: 'L LT' })} - ${format({ date: end, formatString: 'L LT' })}`}</Typography>
|
|
102
|
+
</div>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
position="top"
|
|
106
|
+
>
|
|
107
|
+
<g>
|
|
108
|
+
<BarRounded
|
|
109
|
+
x={xScale(dayjs(start).tz(timezone))}
|
|
110
|
+
y={0}
|
|
111
|
+
width={
|
|
112
|
+
xScale(dayjs(end).tz(timezone)) -
|
|
113
|
+
xScale(dayjs(start).tz(timezone))
|
|
114
|
+
}
|
|
115
|
+
height={height - margins.bottom}
|
|
116
|
+
fill={color}
|
|
117
|
+
left={equals(idx, 0)}
|
|
118
|
+
radius={4}
|
|
119
|
+
right={equals(idx, data.length - 1)}
|
|
120
|
+
/>
|
|
121
|
+
</g>
|
|
122
|
+
</Tooltip>
|
|
123
|
+
))}
|
|
124
|
+
|
|
125
|
+
<Axis.AxisBottom
|
|
126
|
+
top={height - margins.bottom + axisPadding}
|
|
127
|
+
scale={xScale}
|
|
128
|
+
numTicks={numTicks}
|
|
129
|
+
tickFormat={(value) =>
|
|
130
|
+
format({
|
|
131
|
+
date: new Date(value),
|
|
132
|
+
formatString: getXAxisTickFormat({ end: endDate, start: startDate })
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
stroke={theme.palette.text.primary}
|
|
136
|
+
tickStroke={theme.palette.text.primary}
|
|
137
|
+
tickLabelProps={() => ({
|
|
138
|
+
fill: theme.palette.text.primary,
|
|
139
|
+
fontSize: theme.typography.caption.fontSize,
|
|
140
|
+
textAnchor: 'middle'
|
|
141
|
+
})}
|
|
142
|
+
/>
|
|
143
|
+
</svg>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default Timeline;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { userAtom } from '@centreon/ui-context';
|
|
2
|
+
import { Provider, createStore } from 'jotai';
|
|
3
|
+
import Timeline from './Timeline';
|
|
4
|
+
import { Tooltip } from './models';
|
|
5
|
+
|
|
6
|
+
const data = [
|
|
7
|
+
{
|
|
8
|
+
start: '2024-09-09T10:57:42+02:00',
|
|
9
|
+
end: '2024-09-09T11:15:00+02:00',
|
|
10
|
+
color: 'green'
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
start: '2024-09-09T11:15:00+02:00',
|
|
14
|
+
end: '2024-09-09T11:30:00+02:00',
|
|
15
|
+
color: 'red'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
start: '2024-09-09T11:30:00+02:00',
|
|
19
|
+
end: '2024-09-09T11:45:00+02:00',
|
|
20
|
+
color: 'gray'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
start: '2024-09-09T11:45:00+02:00',
|
|
24
|
+
end: '2024-09-09T12:00:00+02:00',
|
|
25
|
+
color: 'green'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
start: '2024-09-09T12:00:00+02:00',
|
|
29
|
+
end: '2024-09-09T12:20:00+02:00',
|
|
30
|
+
color: 'red'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
start: '2024-09-09T12:20:00+02:00',
|
|
34
|
+
end: '2024-09-09T12:40:00+02:00',
|
|
35
|
+
color: 'gray'
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
start: '2024-09-09T12:40:00+02:00',
|
|
39
|
+
end: '2024-09-09T12:57:42+02:00',
|
|
40
|
+
color: 'green'
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const startDate = '2024-09-09T10:57:42+02:00';
|
|
45
|
+
const endDate = '2024-09-09T12:57:42+02:00';
|
|
46
|
+
|
|
47
|
+
const TooltipContent = ({ start, end, color, duration }: Tooltip) => (
|
|
48
|
+
<div
|
|
49
|
+
data-testid="tooltip-content"
|
|
50
|
+
style={{
|
|
51
|
+
display: 'flex',
|
|
52
|
+
flexDirection: 'column',
|
|
53
|
+
justifyContent: 'center',
|
|
54
|
+
alignItems: 'center',
|
|
55
|
+
gap: '10px',
|
|
56
|
+
padding: '5px'
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<span>{start}</span>
|
|
60
|
+
<span>{end}</span>
|
|
61
|
+
<span>{color}</span>
|
|
62
|
+
<span>{duration}</span>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const store = createStore();
|
|
67
|
+
store.set(userAtom, { timezone: 'Europe/Paris', locale: 'en' });
|
|
68
|
+
|
|
69
|
+
const initialize = (displayDefaultTooltip = true): void => {
|
|
70
|
+
cy.mount({
|
|
71
|
+
Component: (
|
|
72
|
+
<Provider store={store}>
|
|
73
|
+
<div
|
|
74
|
+
style={{
|
|
75
|
+
height: '100px',
|
|
76
|
+
width: '70%'
|
|
77
|
+
}}
|
|
78
|
+
>
|
|
79
|
+
<Timeline
|
|
80
|
+
data={data}
|
|
81
|
+
startDate={startDate}
|
|
82
|
+
endDate={endDate}
|
|
83
|
+
TooltipContent={displayDefaultTooltip ? undefined : TooltipContent}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
</Provider>
|
|
87
|
+
)
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
describe('Timeline', () => {
|
|
92
|
+
it('checks that the correct number of bars are rendered', () => {
|
|
93
|
+
initialize();
|
|
94
|
+
|
|
95
|
+
cy.get('path').should('have.length', data.length);
|
|
96
|
+
|
|
97
|
+
cy.makeSnapshot();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('checks that each bar has the correct color', () => {
|
|
101
|
+
initialize();
|
|
102
|
+
|
|
103
|
+
data.forEach(({ color }, index) => {
|
|
104
|
+
cy.get('path').eq(index).should('have.attr', 'fill', color);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('displays tooltip with correct information when hovered over a bar', () => {
|
|
109
|
+
initialize(false);
|
|
110
|
+
|
|
111
|
+
cy.get('path').first().trigger('mouseover');
|
|
112
|
+
|
|
113
|
+
cy.get('[data-testid="tooltip-content"]').within(() => {
|
|
114
|
+
cy.contains('09/09/2024 10:57 AM').should('be.visible');
|
|
115
|
+
cy.contains('09/09/2024 11:15 AM').should('be.visible');
|
|
116
|
+
cy.contains('green').should('be.visible');
|
|
117
|
+
cy.contains('17 minutes').should('be.visible');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
cy.makeSnapshot();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('displays the default tooltip with correct information when hovered over a bar', () => {
|
|
124
|
+
initialize();
|
|
125
|
+
|
|
126
|
+
cy.get('path').first().trigger('mouseover');
|
|
127
|
+
|
|
128
|
+
cy.get('[role="tooltip"]').within(() => {
|
|
129
|
+
cy.contains('09/09/2024 10:57 AM')
|
|
130
|
+
.should('be.visible')
|
|
131
|
+
.and('have.css', 'color', 'rgb(0, 128, 0)');
|
|
132
|
+
cy.contains('09/09/2024 11:15 AM')
|
|
133
|
+
.should('be.visible')
|
|
134
|
+
.and('have.css', 'color', 'rgb(0, 128, 0)');
|
|
135
|
+
cy.contains('17 minutes')
|
|
136
|
+
.should('be.visible')
|
|
137
|
+
.and('have.css', 'color', 'rgb(0, 128, 0)');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
cy.makeSnapshot();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('displays correct tick labels on the x-axis', () => {
|
|
144
|
+
initialize();
|
|
145
|
+
|
|
146
|
+
cy.get('.visx-axis-bottom .visx-axis-tick').first().contains('11:00');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { Typography } from '@mui/material';
|
|
4
|
+
import Timeline from './Timeline';
|
|
5
|
+
|
|
6
|
+
const data = [
|
|
7
|
+
{
|
|
8
|
+
start: '2024-09-25T21:00:42+01:00',
|
|
9
|
+
end: '2024-09-25T21:15:00+01:00',
|
|
10
|
+
color: 'gray'
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
start: '2024-09-25T21:15:00+01:00',
|
|
14
|
+
end: '2024-09-25T21:54:00+01:00',
|
|
15
|
+
color: 'green'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
start: '2024-09-25T21:54:00+01:00',
|
|
19
|
+
end: '2024-09-25T22:30:00+01:00',
|
|
20
|
+
color: 'red'
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const startDate = '2024-09-25T21:00:42+01:00';
|
|
25
|
+
const endDate = '2024-09-25T22:30:00+01:00';
|
|
26
|
+
|
|
27
|
+
const Template = (args): JSX.Element => {
|
|
28
|
+
return (
|
|
29
|
+
<div style={{ width: '700px', height: '100px' }}>
|
|
30
|
+
<Timeline {...args} />
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const meta: Meta<typeof Timeline> = {
|
|
36
|
+
component: Timeline,
|
|
37
|
+
parameters: {
|
|
38
|
+
chromatic: {
|
|
39
|
+
delay: 1000
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
render: Template
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default meta;
|
|
46
|
+
type Story = StoryObj<typeof Timeline>;
|
|
47
|
+
|
|
48
|
+
export const Normal: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
data,
|
|
51
|
+
startDate,
|
|
52
|
+
endDate
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const WithoutData: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
data: [],
|
|
59
|
+
startDate,
|
|
60
|
+
endDate
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const WithSmallerTimeRangeThanData: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
data,
|
|
67
|
+
startDate,
|
|
68
|
+
endDate: '2024-09-25T22:00:00+01:00'
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const WithCustomTooltip: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
data,
|
|
75
|
+
startDate,
|
|
76
|
+
endDate,
|
|
77
|
+
TooltipContent: ({ duration, color }) => (
|
|
78
|
+
<div style={{ display: 'flex', flexDirection: 'row', gap: '8px' }}>
|
|
79
|
+
<div
|
|
80
|
+
style={{
|
|
81
|
+
backgroundColor: color,
|
|
82
|
+
width: '20px',
|
|
83
|
+
height: '20px',
|
|
84
|
+
borderRadius: '4px'
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
<Typography>{duration}</Typography>
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ParentSize } from '../..';
|
|
2
|
+
|
|
3
|
+
import ResponsiveTimeline from './ResponsiveTimeline';
|
|
4
|
+
import type { TimelineProps } from './models';
|
|
5
|
+
|
|
6
|
+
const Timeline = (props: TimelineProps): JSX.Element => (
|
|
7
|
+
<ParentSize>
|
|
8
|
+
{({ width, height }) => (
|
|
9
|
+
<ResponsiveTimeline {...props} height={height} width={width} />
|
|
10
|
+
)}
|
|
11
|
+
</ParentSize>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export default Timeline;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Timeline } from './Timeline';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface Data {
|
|
2
|
+
start: string;
|
|
3
|
+
end: string;
|
|
4
|
+
color: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface Tooltip {
|
|
8
|
+
start: string;
|
|
9
|
+
end: string;
|
|
10
|
+
color: string;
|
|
11
|
+
duration: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TimelineProps {
|
|
15
|
+
data: Array<Data>;
|
|
16
|
+
startDate: string;
|
|
17
|
+
endDate: string;
|
|
18
|
+
TooltipContent?: (props: Tooltip) => JSX.Element;
|
|
19
|
+
tooltipClassName?: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { makeStyles } from 'tss-react/mui';
|
|
2
|
+
|
|
3
|
+
export const useStyles = makeStyles()((theme) => ({
|
|
4
|
+
tooltip: {
|
|
5
|
+
backgroundColor: theme.palette.background.paper,
|
|
6
|
+
color: theme.palette.text.primary,
|
|
7
|
+
padding: theme.spacing(1),
|
|
8
|
+
boxShadow: theme.shadows[3],
|
|
9
|
+
maxWidth: 'none'
|
|
10
|
+
}
|
|
11
|
+
}));
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import dayjs, { Dayjs } from 'dayjs';
|
|
2
|
+
|
|
3
|
+
import { usePluralizedTranslation } from '@centreon/ui';
|
|
4
|
+
import { lt } from 'ramda';
|
|
5
|
+
import { useCallback } from 'react';
|
|
6
|
+
import {
|
|
7
|
+
labelDay,
|
|
8
|
+
labelHour,
|
|
9
|
+
labelMinute,
|
|
10
|
+
labelMonth,
|
|
11
|
+
labelYear
|
|
12
|
+
} from './translatedLabel';
|
|
13
|
+
|
|
14
|
+
interface StartEndProps {
|
|
15
|
+
start: Dayjs;
|
|
16
|
+
end: Dayjs;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface GetWidthProps extends StartEndProps {
|
|
20
|
+
timezone: string;
|
|
21
|
+
xScale;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface UseTimelineState {
|
|
25
|
+
getTimeDifference: (props: StartEndProps) => string;
|
|
26
|
+
getWidth: (props: GetWidthProps) => number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const useTimeline = (): UseTimelineState => {
|
|
30
|
+
const { pluralizedT } = usePluralizedTranslation();
|
|
31
|
+
|
|
32
|
+
const getTimeDifference = useCallback(
|
|
33
|
+
({ start, end }: StartEndProps): string => {
|
|
34
|
+
const diffInMilliseconds = end.diff(start);
|
|
35
|
+
const diffDuration = dayjs.duration(diffInMilliseconds);
|
|
36
|
+
|
|
37
|
+
const timeUnits = [
|
|
38
|
+
{
|
|
39
|
+
value: diffDuration.years(),
|
|
40
|
+
unit: pluralizedT({ label: labelYear, count: diffDuration.years() })
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: diffDuration.months(),
|
|
44
|
+
unit: pluralizedT({ label: labelMonth, count: diffDuration.months() })
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: diffDuration.days(),
|
|
48
|
+
unit: pluralizedT({ label: labelDay, count: diffDuration.days() })
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
value: diffDuration.hours(),
|
|
52
|
+
unit: pluralizedT({ label: labelHour, count: diffDuration.hours() })
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
value: diffDuration.minutes(),
|
|
56
|
+
unit: pluralizedT({
|
|
57
|
+
label: labelMinute,
|
|
58
|
+
count: diffDuration.minutes()
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
const readableUnits = timeUnits
|
|
64
|
+
.filter((unit) => unit.value > 0)
|
|
65
|
+
.map((unit) => `${unit.value} ${unit.unit}`);
|
|
66
|
+
|
|
67
|
+
return readableUnits.slice(0, 2).join(', ');
|
|
68
|
+
},
|
|
69
|
+
[]
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const getWidth = useCallback(
|
|
73
|
+
({ start, end, timezone, xScale }: GetWidthProps): number => {
|
|
74
|
+
const baseWidth =
|
|
75
|
+
xScale(dayjs(end).tz(timezone)) - xScale(dayjs(start).tz(timezone));
|
|
76
|
+
|
|
77
|
+
if (Number.isNaN(baseWidth) || lt(baseWidth, 0)) {
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return baseWidth;
|
|
82
|
+
},
|
|
83
|
+
[]
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
getTimeDifference,
|
|
88
|
+
getWidth
|
|
89
|
+
};
|
|
90
|
+
};
|
package/src/Graph/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { Text as GraphText } from './Text';
|
|
|
9
9
|
export { HeatMap } from './HeatMap';
|
|
10
10
|
export { BarStack } from './BarStack';
|
|
11
11
|
export { PieChart } from './PieChart';
|
|
12
|
+
export { Timeline } from './Timeline';
|
|
12
13
|
export * from './Tree';
|
|
13
14
|
export type { LineChartData } from './common/models';
|
|
14
15
|
export * from './common/timeSeries';
|
package/src/Listing/index.tsx
CHANGED
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
SortOrder
|
|
62
62
|
} from './models';
|
|
63
63
|
import { subItemsPivotsAtom } from './tableAtoms';
|
|
64
|
-
import { labelNoResultFound } from './translatedLabels';
|
|
64
|
+
import { labelNoResultFound as defaultLabelNoResultFound } from './translatedLabels';
|
|
65
65
|
import useStyleTable from './useStyleTable';
|
|
66
66
|
|
|
67
67
|
const subItemPrefixKey = 'listing';
|
|
@@ -140,6 +140,7 @@ export interface Props<TRow> {
|
|
|
140
140
|
viewerModeConfiguration?: ViewerModeConfiguration;
|
|
141
141
|
widthToMoveTablePagination?: number;
|
|
142
142
|
isActionBarVisible: boolean;
|
|
143
|
+
labelNoResultFound?: string | JSX.Element;
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
const defaultColumnConfiguration = {
|
|
@@ -199,7 +200,8 @@ const Listing = <
|
|
|
199
200
|
labelCollapse: 'Collapse',
|
|
200
201
|
labelExpand: 'Expand'
|
|
201
202
|
},
|
|
202
|
-
isActionBarVisible = true
|
|
203
|
+
isActionBarVisible = true,
|
|
204
|
+
labelNoResultFound = defaultLabelNoResultFound
|
|
203
205
|
}: Props<TRow>): JSX.Element => {
|
|
204
206
|
const currentVisibleColumns = getVisibleColumns({
|
|
205
207
|
columnConfiguration,
|
|
@@ -703,7 +705,11 @@ const Listing = <
|
|
|
703
705
|
(loading ? (
|
|
704
706
|
<SkeletonLoader rows={limit} />
|
|
705
707
|
) : (
|
|
706
|
-
<EmptyResult
|
|
708
|
+
<EmptyResult
|
|
709
|
+
label={
|
|
710
|
+
labelNoResultFound || t(defaultLabelNoResultFound)
|
|
711
|
+
}
|
|
712
|
+
/>
|
|
707
713
|
))}
|
|
708
714
|
</TableBody>
|
|
709
715
|
</Table>
|
|
@@ -739,6 +745,7 @@ export const MemoizedListing = <TRow extends { id: string | number }>({
|
|
|
739
745
|
moveTablePagination,
|
|
740
746
|
widthToMoveTablePagination,
|
|
741
747
|
listingVariant,
|
|
748
|
+
labelNoResultFound,
|
|
742
749
|
...props
|
|
743
750
|
}: MemoizedListingProps<TRow>): JSX.Element =>
|
|
744
751
|
useMemoComponent({
|
|
@@ -761,6 +768,7 @@ export const MemoizedListing = <TRow extends { id: string | number }>({
|
|
|
761
768
|
sortOrder={sortOrder}
|
|
762
769
|
totalRows={totalRows}
|
|
763
770
|
widthToMoveTablePagination={widthToMoveTablePagination}
|
|
771
|
+
labelNoResultFound={labelNoResultFound}
|
|
764
772
|
{...props}
|
|
765
773
|
/>
|
|
766
774
|
),
|
|
@@ -783,7 +791,8 @@ export const MemoizedListing = <TRow extends { id: string | number }>({
|
|
|
783
791
|
sortOrder,
|
|
784
792
|
sortField,
|
|
785
793
|
innerScrollDisabled,
|
|
786
|
-
listingVariant
|
|
794
|
+
listingVariant,
|
|
795
|
+
labelNoResultFound
|
|
787
796
|
]
|
|
788
797
|
});
|
|
789
798
|
|