@centreon/ui 24.11.11 → 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/Dashboard/Dashboard.styles.ts +1 -1
- package/src/Dashboard/Grid.tsx +2 -8
- package/src/Dashboard/Layout.tsx +40 -43
- package/src/Form/Inputs/Autocomplete.tsx +4 -2
- package/src/Form/Inputs/ConnectedAutocomplete.tsx +1 -1
- package/src/Form/Inputs/Radio.tsx +1 -1
- package/src/Form/Inputs/Text.tsx +1 -1
- package/src/Graph/BarChart/BarChart.cypress.spec.tsx +1 -1
- package/src/Graph/Chart/Chart.tsx +5 -2
- package/src/Graph/Chart/InteractiveComponents/index.tsx +1 -1
- package/src/Graph/Chart/index.tsx +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/common/utils.ts +2 -2
- package/src/Graph/index.ts +1 -0
- package/src/Icon/BusinessActivityIcon.tsx +12 -0
- package/src/Icon/ContainerIcon.tsx +20 -0
- package/src/Icon/DowntimeIcon.tsx +8 -1
- package/src/Icon/HostGroupIcon.tsx +8 -0
- package/src/Icon/MetaServiceIcon.tsx +12 -0
- package/src/Icon/ServiceGroupIcon.tsx +8 -0
- package/src/Icon/index.ts +7 -2
- package/src/Listing/EmptyResult/EmptyResult.tsx +1 -1
- package/src/Listing/index.tsx +39 -31
- package/src/Typography/EllipsisTypography.tsx +7 -3
- package/src/components/Layout/PageLayout/PageLayout.styles.ts +3 -3
- /package/src/Icon/{AcnowledgementIcon.tsx → AcknowledgementIcon.tsx} +0 -0
package/package.json
CHANGED
package/src/Dashboard/Grid.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactElement, useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { scaleLinear } from '@visx/scale';
|
|
4
4
|
import { Grid as VisxGrid } from '@visx/visx';
|
|
@@ -13,15 +13,9 @@ interface Props {
|
|
|
13
13
|
columns: number;
|
|
14
14
|
height: number;
|
|
15
15
|
width: number;
|
|
16
|
-
containerRef: MutableRefObject<HTMLDivElement | null>;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
const Grid = ({
|
|
20
|
-
width,
|
|
21
|
-
height,
|
|
22
|
-
columns,
|
|
23
|
-
containerRef
|
|
24
|
-
}: Props): ReactElement => {
|
|
18
|
+
const Grid = ({ width, height, columns }: Props): ReactElement => {
|
|
25
19
|
const theme = useTheme();
|
|
26
20
|
|
|
27
21
|
const xScale = useMemo(
|
package/src/Dashboard/Layout.tsx
CHANGED
|
@@ -4,10 +4,7 @@ import { useSetAtom } from 'jotai';
|
|
|
4
4
|
import GridLayout, { Layout, WidthProvider } from 'react-grid-layout';
|
|
5
5
|
import 'react-grid-layout/css/styles.css';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
ParentSize,
|
|
9
|
-
useMemoComponent
|
|
10
|
-
} from '..';
|
|
7
|
+
import { ParentSize, useMemoComponent } from '..';
|
|
11
8
|
|
|
12
9
|
import { Box } from '@mui/material';
|
|
13
10
|
import { useDashboardLayoutStyles } from './Dashboard.styles';
|
|
@@ -33,10 +30,10 @@ const bottom = (layout: Array<Layout>): number => {
|
|
|
33
30
|
layout.forEach((panel) => {
|
|
34
31
|
bottomY = panel.y + panel.h;
|
|
35
32
|
if (bottomY > max) max = bottomY;
|
|
36
|
-
})
|
|
33
|
+
});
|
|
37
34
|
|
|
38
35
|
return max;
|
|
39
|
-
}
|
|
36
|
+
};
|
|
40
37
|
|
|
41
38
|
const DashboardLayout = <T extends Layout>({
|
|
42
39
|
children,
|
|
@@ -67,14 +64,10 @@ const DashboardLayout = <T extends Layout>({
|
|
|
67
64
|
}, []);
|
|
68
65
|
|
|
69
66
|
const containerHeight = useMemo((): number | undefined => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
(nbRow - 1) * 20 +
|
|
75
|
-
containerPaddingY * 2
|
|
76
|
-
);
|
|
77
|
-
}, [layout, rowHeight])
|
|
67
|
+
const nbRow = bottom(getLayout(layout));
|
|
68
|
+
const containerPaddingY = 4;
|
|
69
|
+
return nbRow * rowHeight + (nbRow - 1) * 20 + containerPaddingY * 2;
|
|
70
|
+
}, [layout, rowHeight]) ?? 0;
|
|
78
71
|
|
|
79
72
|
useEffect(() => {
|
|
80
73
|
window.addEventListener('resize', resize);
|
|
@@ -86,36 +79,40 @@ const DashboardLayout = <T extends Layout>({
|
|
|
86
79
|
|
|
87
80
|
return useMemoComponent({
|
|
88
81
|
Component: (
|
|
89
|
-
<Box
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
cols={columns}
|
|
103
|
-
containerPadding={[4, 0]}
|
|
104
|
-
layout={getLayout(layout)}
|
|
105
|
-
margin={[20, 20]}
|
|
106
|
-
resizeHandles={['s', 'e', 'se']}
|
|
107
|
-
rowHeight={rowHeight}
|
|
82
|
+
<Box
|
|
83
|
+
ref={dashboardContainerRef}
|
|
84
|
+
sx={{ overflowY: 'auto', overflowX: 'hidden' }}
|
|
85
|
+
>
|
|
86
|
+
<ParentSize>
|
|
87
|
+
{({ width, height }): JSX.Element => (
|
|
88
|
+
<Box className={classes.container}>
|
|
89
|
+
{displayGrid && (
|
|
90
|
+
<Grid
|
|
91
|
+
columns={columns}
|
|
92
|
+
height={
|
|
93
|
+
containerHeight > height ? containerHeight : height
|
|
94
|
+
}
|
|
108
95
|
width={width}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
<ReactGridLayout
|
|
99
|
+
cols={columns}
|
|
100
|
+
containerPadding={[4, 0]}
|
|
101
|
+
layout={getLayout(layout)}
|
|
102
|
+
margin={[20, 20]}
|
|
103
|
+
resizeHandles={['s', 'e', 'se']}
|
|
104
|
+
rowHeight={rowHeight}
|
|
105
|
+
width={width}
|
|
106
|
+
onLayoutChange={changeLayout}
|
|
107
|
+
onResizeStart={startResize}
|
|
108
|
+
onResizeStop={stopResize}
|
|
109
|
+
>
|
|
110
|
+
{children}
|
|
111
|
+
</ReactGridLayout>
|
|
112
|
+
</Box>
|
|
113
|
+
)}
|
|
114
|
+
</ParentSize>
|
|
115
|
+
</Box>
|
|
119
116
|
),
|
|
120
117
|
memoProps: [columns, layout, displayGrid, isStatic, ...additionalMemoProps]
|
|
121
118
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useCallback, useMemo, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { FormikValues, useFormikContext } from 'formik';
|
|
4
|
-
import { equals, isNil, map, not,
|
|
4
|
+
import { path, equals, isNil, map, not, prop, type } from 'ramda';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import { FormHelperText, Stack } from '@mui/material';
|
|
@@ -188,7 +188,9 @@ const Autocomplete = ({
|
|
|
188
188
|
value={getValues() ?? null}
|
|
189
189
|
onChange={changeValues}
|
|
190
190
|
onTextChange={textChange}
|
|
191
|
-
style={{
|
|
191
|
+
style={{
|
|
192
|
+
width: (autocomplete?.fullWidth ?? true) ? 'auto' : '180px'
|
|
193
|
+
}}
|
|
192
194
|
/>
|
|
193
195
|
{inputErrors && (
|
|
194
196
|
<Stack>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { FormikValues, useFormikContext } from 'formik';
|
|
4
|
-
import { equals, isEmpty,
|
|
4
|
+
import { path, equals, isEmpty, propEq, reject, split } from 'ramda';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import {
|
package/src/Form/Inputs/Text.tsx
CHANGED
|
@@ -62,14 +62,17 @@ interface Props extends LineChartProps {
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const filterLines = (
|
|
65
|
+
const filterLines = (
|
|
66
|
+
lines: Array<Line>,
|
|
67
|
+
displayThreshold: boolean
|
|
68
|
+
): Array<Line> => {
|
|
66
69
|
if (!displayThreshold) {
|
|
67
70
|
return lines;
|
|
68
71
|
}
|
|
69
72
|
const lineOriginMetric = findLineOfOriginMetricThreshold(lines);
|
|
70
73
|
|
|
71
74
|
if (isEmpty(lineOriginMetric)) {
|
|
72
|
-
|
|
75
|
+
return lines;
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
const findLinesUpperLower = lines.map((line) =>
|
|
@@ -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';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
|
2
|
+
import { SvgIconProps } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
import BaseIcon from './BaseIcon';
|
|
5
|
+
|
|
6
|
+
export const BusinessActivityIcon = (props: SvgIconProps): JSX.Element => (
|
|
7
|
+
<BaseIcon
|
|
8
|
+
Icon={AccountTreeIcon}
|
|
9
|
+
dataTestId="BusinessActivityIcon"
|
|
10
|
+
{...props}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SvgIconProps } from '@mui/material';
|
|
2
|
+
|
|
3
|
+
import BaseIcon from './BaseIcon';
|
|
4
|
+
|
|
5
|
+
const icon = (
|
|
6
|
+
<g>
|
|
7
|
+
<path d="M301 745.9L28 662.4c-7.4-2.3-12.5-9.2-12.5-16.9V270.4c0-5.7 2.7-10.9 7.3-14.3 4.6-3.3 10.4-4.2 15.8-2.5l273.1 88.5c7.3 2.4 12.2 9.1 12.2 16.8V729c0 5.6-2.7 10.9-7.2 14.2-3.1 2.3-6.8 3.5-10.5 3.5-1.8-.1-3.5-.3-5.2-.8zm5.2-16.9l5.2-16.9-5.2 16.9zM50.8 632.4l237.8 72.7V371.7l-237.8-77v337.7z" />
|
|
8
|
+
<path d="M295.7 743.2c-4.5-3.3-7.2-8.6-7.2-14.2V358.8c0-7.6 4.9-14.4 12.2-16.8l273.1-88.5c5.4-1.8 11.3-.8 15.8 2.5 4.6 3.4 7.3 8.7 7.3 14.3v375.1c0 7.8-5 14.6-12.5 16.9l-273.1 83.4-5.2-16.9 5.2 16.9c-1.7.5-3.4.8-5.2.8-3.6.1-7.3-1-10.4-3.3zm28.2-371.5V705l237.8-72.7V294.7l-237.8 77zM16.3 275.9c-3-9.3 2.1-19.3 11.4-22.3L300.8 165c9.2-3 19.2 2.1 22.2 11.3 3 9.3-2.1 19.3-11.3 22.2L38.6 287.2c-1.8.6-3.7.9-5.5.9-7.4-.1-14.3-4.8-16.8-12.2z" />
|
|
9
|
+
<path d="M573.9 287.2l-273-88.5c-9.3-3-14.4-13-11.4-22.2 3-9.3 13-14.4 22.2-11.3l273.1 88.5c9.3 3 14.4 13 11.4 22.3-2.4 7.4-9.4 12.2-16.8 12.2-1.9-.1-3.7-.5-5.5-1zm-131.3 42.5l-273.1-88.5c-9.3-3-14.4-13-11.4-22.2 3-9.3 12.9-14.4 22.3-11.4l273 88.5c9.3 3 14.4 13 11.4 22.3-2.4 7.4-9.3 12.2-16.8 12.2-1.7 0-3.5-.3-5.4-.9z" />
|
|
10
|
+
</g>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const ContainerIcon = (props: SvgIconProps): JSX.Element => (
|
|
14
|
+
<BaseIcon
|
|
15
|
+
{...props}
|
|
16
|
+
dataTestId="ContainerIcon"
|
|
17
|
+
Icon={icon}
|
|
18
|
+
viewBox="6 156 600 600"
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
@@ -10,5 +10,12 @@ const icon = (
|
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
export const DowntimeIcon = (props: SvgIconProps): JSX.Element => (
|
|
13
|
-
<BaseIcon
|
|
13
|
+
<BaseIcon
|
|
14
|
+
{...props}
|
|
15
|
+
dataTestId="DowntimeIcon"
|
|
16
|
+
Icon={icon}
|
|
17
|
+
height="24"
|
|
18
|
+
viewBox="0 0 24 24"
|
|
19
|
+
width="24"
|
|
20
|
+
/>
|
|
14
21
|
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import BusinessIcon from '@mui/icons-material/Business';
|
|
2
|
+
import { SvgIconProps } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
import BaseIcon from './BaseIcon';
|
|
5
|
+
|
|
6
|
+
export const HostGroupIcon = (props: SvgIconProps): JSX.Element => (
|
|
7
|
+
<BaseIcon Icon={BusinessIcon} dataTestId="HostGroupIcon" {...props} />
|
|
8
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import SettingsInputSvideoIcon from '@mui/icons-material/SettingsInputSvideo';
|
|
2
|
+
import { SvgIconProps } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
import BaseIcon from './BaseIcon';
|
|
5
|
+
|
|
6
|
+
export const MetaServiceIcon = (props: SvgIconProps): JSX.Element => (
|
|
7
|
+
<BaseIcon
|
|
8
|
+
Icon={SettingsInputSvideoIcon}
|
|
9
|
+
dataTestId="MetaServiceIcon"
|
|
10
|
+
{...props}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import LinearScaleIcon from '@mui/icons-material/LinearScale';
|
|
2
|
+
import { SvgIconProps } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
import BaseIcon from './BaseIcon';
|
|
5
|
+
|
|
6
|
+
export const ServiceGroupIcon = (props: SvgIconProps): JSX.Element => (
|
|
7
|
+
<BaseIcon Icon={LinearScaleIcon} dataTestId="ServiceGroupIcon" {...props} />
|
|
8
|
+
);
|
package/src/Icon/index.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
export { DowntimeIcon } from './DowntimeIcon';
|
|
2
|
+
export { AcknowledgementIcon } from './AcknowledgementIcon';
|
|
1
3
|
export { HostIcon } from './HostIcon';
|
|
2
4
|
export { ServiceIcon } from './ServiceIcon';
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
+
export { BusinessActivityIcon } from './BusinessActivityIcon';
|
|
6
|
+
export { HostGroupIcon } from './HostGroupIcon';
|
|
7
|
+
export { ServiceGroupIcon } from './ServiceGroupIcon';
|
|
8
|
+
export { MetaServiceIcon } from './MetaServiceIcon';
|
|
9
|
+
export { ContainerIcon } from './ContainerIcon';
|
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,
|
|
@@ -526,33 +528,32 @@ const Listing = <
|
|
|
526
528
|
className={classes.container}
|
|
527
529
|
ref={containerRef as RefObject<HTMLDivElement>}
|
|
528
530
|
>
|
|
529
|
-
{
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
531
|
+
{isActionBarVisible && (
|
|
532
|
+
<div
|
|
533
|
+
className={classes.actionBar}
|
|
534
|
+
ref={actionBarRef as RefObject<HTMLDivElement>}
|
|
535
|
+
>
|
|
536
|
+
<ListingActionBar
|
|
537
|
+
actions={actions}
|
|
538
|
+
actionsBarMemoProps={actionsBarMemoProps}
|
|
539
|
+
columnConfiguration={columnConfiguration}
|
|
540
|
+
columns={columns}
|
|
541
|
+
currentPage={currentPage}
|
|
542
|
+
customPaginationClassName={customPaginationClassName}
|
|
543
|
+
limit={limit}
|
|
544
|
+
listingVariant={listingVariant}
|
|
545
|
+
moveTablePagination={moveTablePagination}
|
|
546
|
+
paginated={paginated}
|
|
547
|
+
totalRows={totalRows}
|
|
548
|
+
viewerModeConfiguration={viewerModeConfiguration}
|
|
549
|
+
widthToMoveTablePagination={widthToMoveTablePagination}
|
|
550
|
+
onLimitChange={changeLimit}
|
|
551
|
+
onPaginate={onPaginate}
|
|
552
|
+
onResetColumns={onResetColumns}
|
|
553
|
+
onSelectColumns={onSelectColumns}
|
|
554
|
+
/>
|
|
555
|
+
</div>
|
|
556
|
+
)}
|
|
556
557
|
|
|
557
558
|
<ParentSize
|
|
558
559
|
parentSizeStyles={{
|
|
@@ -704,7 +705,11 @@ const Listing = <
|
|
|
704
705
|
(loading ? (
|
|
705
706
|
<SkeletonLoader rows={limit} />
|
|
706
707
|
) : (
|
|
707
|
-
<EmptyResult
|
|
708
|
+
<EmptyResult
|
|
709
|
+
label={
|
|
710
|
+
labelNoResultFound || t(defaultLabelNoResultFound)
|
|
711
|
+
}
|
|
712
|
+
/>
|
|
708
713
|
))}
|
|
709
714
|
</TableBody>
|
|
710
715
|
</Table>
|
|
@@ -740,6 +745,7 @@ export const MemoizedListing = <TRow extends { id: string | number }>({
|
|
|
740
745
|
moveTablePagination,
|
|
741
746
|
widthToMoveTablePagination,
|
|
742
747
|
listingVariant,
|
|
748
|
+
labelNoResultFound,
|
|
743
749
|
...props
|
|
744
750
|
}: MemoizedListingProps<TRow>): JSX.Element =>
|
|
745
751
|
useMemoComponent({
|
|
@@ -762,6 +768,7 @@ export const MemoizedListing = <TRow extends { id: string | number }>({
|
|
|
762
768
|
sortOrder={sortOrder}
|
|
763
769
|
totalRows={totalRows}
|
|
764
770
|
widthToMoveTablePagination={widthToMoveTablePagination}
|
|
771
|
+
labelNoResultFound={labelNoResultFound}
|
|
765
772
|
{...props}
|
|
766
773
|
/>
|
|
767
774
|
),
|
|
@@ -784,7 +791,8 @@ export const MemoizedListing = <TRow extends { id: string | number }>({
|
|
|
784
791
|
sortOrder,
|
|
785
792
|
sortField,
|
|
786
793
|
innerScrollDisabled,
|
|
787
|
-
listingVariant
|
|
794
|
+
listingVariant,
|
|
795
|
+
labelNoResultFound
|
|
788
796
|
]
|
|
789
797
|
});
|
|
790
798
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type ForwardedRef, forwardRef } from 'react';
|
|
2
2
|
|
|
3
3
|
import { Box, Typography, type TypographyProps } from '@mui/material';
|
|
4
4
|
|
|
5
5
|
const EllipsisTypography = forwardRef(
|
|
6
6
|
(
|
|
7
|
-
{
|
|
8
|
-
|
|
7
|
+
{
|
|
8
|
+
containerClassname,
|
|
9
|
+
...props
|
|
10
|
+
}: TypographyProps & { containerClassname?: string },
|
|
11
|
+
ref?: ForwardedRef<HTMLSpanElement>
|
|
12
|
+
) => {
|
|
9
13
|
return (
|
|
10
14
|
<Box className={containerClassname} sx={{ width: '100%' }}>
|
|
11
15
|
<Typography
|
|
@@ -4,8 +4,8 @@ export const useStyles = makeStyles()((theme) => ({
|
|
|
4
4
|
pageLayout: {
|
|
5
5
|
display: 'grid',
|
|
6
6
|
gridTemplateRows: 'auto 1fr',
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
overflow: 'hidden',
|
|
8
|
+
height: '100%'
|
|
9
9
|
},
|
|
10
10
|
pageLayoutActions: {
|
|
11
11
|
'& > span': {
|
|
@@ -24,7 +24,7 @@ export const useStyles = makeStyles()((theme) => ({
|
|
|
24
24
|
backgroundColor: theme.palette.layout.body.background
|
|
25
25
|
},
|
|
26
26
|
'&[data-has-actions="true"]': {
|
|
27
|
-
gridTemplateRows: 'min-content auto'
|
|
27
|
+
gridTemplateRows: 'min-content auto'
|
|
28
28
|
},
|
|
29
29
|
display: 'grid',
|
|
30
30
|
gridTemplateRows: 'auto',
|
|
File without changes
|