@scality/core-ui 0.175.0 → 0.177.0
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/dist/components/barchartv2/Barchart.component.d.ts +4 -5
- package/dist/components/barchartv2/Barchart.component.d.ts.map +1 -1
- package/dist/components/barchartv2/Barchart.component.js +23 -27
- package/dist/components/barchartv2/BarchartTooltip.d.ts +4 -3
- package/dist/components/barchartv2/BarchartTooltip.d.ts.map +1 -1
- package/dist/components/barchartv2/BarchartTooltip.js +10 -12
- package/dist/components/barchartv2/utils.d.ts +6 -1
- package/dist/components/barchartv2/utils.d.ts.map +1 -1
- package/dist/components/barchartv2/utils.js +34 -8
- package/dist/components/chartlegend/ChartLegendWrapper.js +1 -1
- package/dist/components/charttooltip/ChartTooltip.d.ts +29 -0
- package/dist/components/charttooltip/ChartTooltip.d.ts.map +1 -1
- package/dist/components/charttooltip/ChartTooltip.js +105 -1
- package/dist/components/date/FormattedDateTime.d.ts +23 -8
- package/dist/components/date/FormattedDateTime.d.ts.map +1 -1
- package/dist/components/date/FormattedDateTime.js +51 -7
- package/dist/components/globalhealthbar/GlobalHealthBarRecharts.component.d.ts.map +1 -1
- package/dist/components/globalhealthbar/GlobalHealthBarRecharts.component.js +27 -1
- package/dist/components/globalhealthbar/components/GlobalHealthBarTooltip.d.ts +1 -1
- package/dist/components/globalhealthbar/components/GlobalHealthBarTooltip.d.ts.map +1 -1
- package/dist/components/globalhealthbar/components/GlobalHealthBarTooltip.js +19 -59
- package/dist/components/globalhealthbar/components/HealthBarXAxis.js +1 -1
- package/dist/components/globalhealthbar/useHealthBarData.d.ts +1 -0
- package/dist/components/globalhealthbar/useHealthBarData.d.ts.map +1 -1
- package/dist/components/globalhealthbar/useHealthBarData.js +1 -0
- package/dist/components/globalhealthbar/useHealthBarData.spec.js +2 -0
- package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts +2 -1
- package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts.map +1 -1
- package/dist/components/linetimeseriechart/linetimeseriechart.component.js +45 -47
- package/dist/components/linetimeseriechart/utils.d.ts +1 -1
- package/dist/components/linetimeseriechart/utils.d.ts.map +1 -1
- package/dist/components/linetimeseriechart/utils.js +13 -13
- package/dist/style/theme.js +1 -1
- package/package.json +1 -1
- package/src/lib/components/barchartv2/Barchart.component.test.tsx +23 -25
- package/src/lib/components/barchartv2/Barchart.component.tsx +41 -39
- package/src/lib/components/barchartv2/BarchartTooltip.test.tsx +33 -3
- package/src/lib/components/barchartv2/BarchartTooltip.tsx +33 -24
- package/src/lib/components/barchartv2/utils.test.ts +72 -17
- package/src/lib/components/barchartv2/utils.ts +40 -12
- package/src/lib/components/chartlegend/ChartLegendWrapper.tsx +1 -1
- package/src/lib/components/charttooltip/ChartTooltip.tsx +174 -1
- package/src/lib/components/date/FormattedDateTime.tsx +73 -8
- package/src/lib/components/globalhealthbar/GlobalHealthBarRecharts.component.tsx +56 -11
- package/src/lib/components/globalhealthbar/components/GlobalHealthBarTooltip.tsx +75 -117
- package/src/lib/components/globalhealthbar/components/HealthBarXAxis.tsx +1 -1
- package/src/lib/components/globalhealthbar/useHealthBarData.spec.tsx +2 -0
- package/src/lib/components/globalhealthbar/useHealthBarData.ts +2 -0
- package/src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx +101 -90
- package/src/lib/components/linetimeseriechart/utils.test.ts +30 -68
- package/src/lib/components/linetimeseriechart/utils.ts +13 -17
- package/src/lib/style/theme.ts +1 -1
- package/stories/BarChart/barchart.stories.tsx +23 -8
- package/stories/formattedate.stories.tsx +2 -0
- package/stories/linetimeseriechart.stories.tsx +1 -0
|
@@ -3,7 +3,7 @@ import { getDateDaysDiff } from './dateDiffer';
|
|
|
3
3
|
import { Tooltip } from '../tooltip/Tooltip.component';
|
|
4
4
|
/**
|
|
5
5
|
* @description Long date formatter, with weekday, year, month and day. Used for describing long term date.
|
|
6
|
-
* @example Wednesday
|
|
6
|
+
* @example Wednesday 06 October 2025
|
|
7
7
|
*/
|
|
8
8
|
export const LONG_DATE_FORMATER = Intl.DateTimeFormat('en-GB', {
|
|
9
9
|
weekday: 'long',
|
|
@@ -32,7 +32,7 @@ export const DATE_FORMATER = Intl.DateTimeFormat('fr-CA', {
|
|
|
32
32
|
});
|
|
33
33
|
/**
|
|
34
34
|
* @description Day month formatter, with weekday, day and month. Used for describing long term date.
|
|
35
|
-
* @example Wed
|
|
35
|
+
* @example Wed 06 Oct
|
|
36
36
|
*/
|
|
37
37
|
export const DAY_MONTH_FORMATER = Intl.DateTimeFormat('en-GB', {
|
|
38
38
|
weekday: 'short',
|
|
@@ -58,9 +58,28 @@ export const TIME_FORMATER = Intl.DateTimeFormat('en-GB', {
|
|
|
58
58
|
hour: '2-digit',
|
|
59
59
|
minute: '2-digit',
|
|
60
60
|
});
|
|
61
|
+
/**
|
|
62
|
+
* @description Day month abbreviated formatter. Used for describing long term date.
|
|
63
|
+
* @example 06 Oct
|
|
64
|
+
*/
|
|
65
|
+
export const DAY_MONTH_ABBREVIATED = Intl.DateTimeFormat('en-GB', {
|
|
66
|
+
day: '2-digit',
|
|
67
|
+
month: 'short',
|
|
68
|
+
hour12: false,
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* @description Day month abbreviated formatter. Used for describing long term date.
|
|
72
|
+
* @example 06 Oct 25
|
|
73
|
+
*/
|
|
74
|
+
export const DAY_MONTH_ABBREVIATED_YEAR = Intl.DateTimeFormat('en-GB', {
|
|
75
|
+
day: '2-digit',
|
|
76
|
+
month: 'short',
|
|
77
|
+
year: '2-digit',
|
|
78
|
+
hour12: false,
|
|
79
|
+
});
|
|
61
80
|
/**
|
|
62
81
|
* @description Day month abbreviated hour minute second formatter. Used for describing long term date.
|
|
63
|
-
* @example
|
|
82
|
+
* @example 06 Oct 18:33:00
|
|
64
83
|
*/
|
|
65
84
|
export const DAY_MONTH_ABBREVIATED_HOUR_MINUTE_SECOND = Intl.DateTimeFormat('en-GB', {
|
|
66
85
|
day: '2-digit',
|
|
@@ -72,7 +91,7 @@ export const DAY_MONTH_ABBREVIATED_HOUR_MINUTE_SECOND = Intl.DateTimeFormat('en-
|
|
|
72
91
|
});
|
|
73
92
|
/**
|
|
74
93
|
* @description Day month abbreviated hour minute formatter. Used for describing long term date.
|
|
75
|
-
* @example
|
|
94
|
+
* @example 06 Oct 18:33
|
|
76
95
|
*/
|
|
77
96
|
export const DAY_MONTH_ABBREVIATED_HOUR_MINUTE = Intl.DateTimeFormat('en-GB', {
|
|
78
97
|
day: '2-digit',
|
|
@@ -81,6 +100,18 @@ export const DAY_MONTH_ABBREVIATED_HOUR_MINUTE = Intl.DateTimeFormat('en-GB', {
|
|
|
81
100
|
minute: '2-digit',
|
|
82
101
|
hour12: false,
|
|
83
102
|
});
|
|
103
|
+
/**
|
|
104
|
+
* @description Day month abbreviated year hour minute formatter. Used for describing long term date.
|
|
105
|
+
* @example 06 Oct 2025 18:33
|
|
106
|
+
*/
|
|
107
|
+
export const DAY_MONTH_ABBREVIATED_YEAR_HOUR_MINUTE = Intl.DateTimeFormat('en-GB', {
|
|
108
|
+
day: '2-digit',
|
|
109
|
+
month: 'short',
|
|
110
|
+
year: 'numeric',
|
|
111
|
+
hour: '2-digit',
|
|
112
|
+
minute: '2-digit',
|
|
113
|
+
hour12: false,
|
|
114
|
+
});
|
|
84
115
|
/**
|
|
85
116
|
* @description Year month day formatter, without time. Used for describing long term date.
|
|
86
117
|
* @example 2025-01-01
|
|
@@ -115,10 +146,10 @@ const isItFutureOrIsItPast = (timeDiff, stringToBeFormatted) => {
|
|
|
115
146
|
* time: '00:00'
|
|
116
147
|
* 'time-second': '00:00:00'
|
|
117
148
|
* relative: '1 month ago'
|
|
118
|
-
* 'day-month-abbreviated-hour-minute': '
|
|
119
|
-
* 'day-month-abbreviated-hour-minute-second': '
|
|
149
|
+
* 'day-month-abbreviated-hour-minute': '06 Oct 18:33'
|
|
150
|
+
* 'day-month-abbreviated-hour-minute-second': '06 Oct 18:33:00'
|
|
120
151
|
* 'long-date': 'Wednesday 6 October 2025'
|
|
121
|
-
* 'chart-date': '
|
|
152
|
+
* 'chart-date': '06 Oct'
|
|
122
153
|
* 'year-month-day': '2025-10-06'
|
|
123
154
|
*/
|
|
124
155
|
export const FormattedDateTime = ({ format, value, }) => {
|
|
@@ -176,6 +207,19 @@ export const FormattedDateTime = ({ format, value, }) => {
|
|
|
176
207
|
return _jsx(_Fragment, { children: YEAR_MONTH_DAY_FORMATTER.format(value) });
|
|
177
208
|
case 'month-day':
|
|
178
209
|
return _jsx(_Fragment, { children: MONTH_DAY_FORMATTER.format(value) });
|
|
210
|
+
case 'day-month-abbreviated-year-hour-minute':
|
|
211
|
+
return (_jsx(_Fragment, { children: DAY_MONTH_ABBREVIATED_YEAR_HOUR_MINUTE.format(value)
|
|
212
|
+
.replace(',', '')
|
|
213
|
+
.replace(/Sept/g, 'Sep') }));
|
|
214
|
+
case 'day-month-abbreviated':
|
|
215
|
+
return (_jsx(_Fragment, { children: DAY_MONTH_ABBREVIATED.format(value)
|
|
216
|
+
.replace(',', '')
|
|
217
|
+
.replace(/Sept/g, 'Sep') }));
|
|
218
|
+
case 'chart-long-term-date':
|
|
219
|
+
return (_jsx(_Fragment, { children: DAY_MONTH_ABBREVIATED_YEAR.format(value)
|
|
220
|
+
.replace(/[ ,]/g, '')
|
|
221
|
+
// replace Sept with Sep to keep 3 letter month
|
|
222
|
+
.replace(/Sept/g, 'Sep') }));
|
|
179
223
|
default:
|
|
180
224
|
return _jsx(_Fragment, {});
|
|
181
225
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalHealthBarRecharts.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/globalhealthbar/GlobalHealthBarRecharts.component.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAE,KAAK,EAAoB,MAAM,oBAAoB,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;CACX;
|
|
1
|
+
{"version":3,"file":"GlobalHealthBarRecharts.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/globalhealthbar/GlobalHealthBarRecharts.component.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAE,KAAK,EAAoB,MAAM,oBAAoB,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;CACX;AAUD,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,2CAkN5E;AAGD,YAAY,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -8,11 +8,16 @@ import { CHART_CONFIG, getNavigationAction, getNavigationStateUpdate, } from './
|
|
|
8
8
|
import { useHealthBarData } from './useHealthBarData';
|
|
9
9
|
const ChartInteractiveContainer = styled.div `
|
|
10
10
|
position: relative;
|
|
11
|
+
outline: none;
|
|
12
|
+
.recharts-surface {
|
|
13
|
+
outline: none;
|
|
14
|
+
}
|
|
11
15
|
`;
|
|
12
16
|
export function GlobalHealthBar({ id, alerts, start, end }) {
|
|
13
17
|
const [tooltipData, setTooltipData] = useState(null);
|
|
14
18
|
const [focusedAlertIndex, setFocusedAlertIndex] = useState(-1);
|
|
15
19
|
const [keyboardActive, setKeyboardActive] = useState(false);
|
|
20
|
+
const [activeBarKey, setActiveBarKey] = useState(null);
|
|
16
21
|
const chartContainerRef = useRef(null);
|
|
17
22
|
const theme = useTheme();
|
|
18
23
|
const startTimestamp = new Date(start).getTime();
|
|
@@ -20,10 +25,12 @@ export function GlobalHealthBar({ id, alerts, start, end }) {
|
|
|
20
25
|
const { chartData, alertsMap, alertKeys } = useHealthBarData(alerts, startTimestamp, endTimestamp, id);
|
|
21
26
|
const handlePointerEnter = useCallback((key) => {
|
|
22
27
|
setTooltipData(alertsMap[key]);
|
|
28
|
+
setActiveBarKey(key);
|
|
23
29
|
}, [alertsMap]);
|
|
24
30
|
const handlePointerLeave = useCallback(() => {
|
|
25
31
|
if (!keyboardActive) {
|
|
26
32
|
setTooltipData(null);
|
|
33
|
+
setActiveBarKey(null);
|
|
27
34
|
}
|
|
28
35
|
}, [keyboardActive]);
|
|
29
36
|
const { warningKeys, criticalKeys, unavailableKeys } = alertKeys;
|
|
@@ -43,6 +50,10 @@ export function GlobalHealthBar({ id, alerts, start, end }) {
|
|
|
43
50
|
setFocusedAlertIndex(update.newIndex);
|
|
44
51
|
setTooltipData(update.selectedAlert);
|
|
45
52
|
setKeyboardActive(update.shouldActivateKeyboard);
|
|
53
|
+
// Set active bar key for keyboard navigation
|
|
54
|
+
if (update.selectedAlert) {
|
|
55
|
+
setActiveBarKey(update.selectedAlert.key);
|
|
56
|
+
}
|
|
46
57
|
}, [allAlertKeys, focusedAlertIndex]);
|
|
47
58
|
// Handle focus events
|
|
48
59
|
const handleFocus = useCallback(() => {
|
|
@@ -50,12 +61,15 @@ export function GlobalHealthBar({ id, alerts, start, end }) {
|
|
|
50
61
|
setFocusedAlertIndex(0);
|
|
51
62
|
setTooltipData(allAlertKeys[0]);
|
|
52
63
|
setKeyboardActive(true);
|
|
64
|
+
// Set active bar key for initial focus
|
|
65
|
+
setActiveBarKey(allAlertKeys[0].key);
|
|
53
66
|
}
|
|
54
67
|
}, [allAlertKeys, focusedAlertIndex]);
|
|
55
68
|
const handleBlur = useCallback(() => {
|
|
56
69
|
setKeyboardActive(false);
|
|
57
70
|
setFocusedAlertIndex(-1);
|
|
58
71
|
setTooltipData(null);
|
|
72
|
+
setActiveBarKey(null);
|
|
59
73
|
}, []);
|
|
60
74
|
// Handle mouse enter to disable keyboard mode
|
|
61
75
|
const handleMouseEnter = useCallback(() => {
|
|
@@ -74,5 +88,17 @@ export function GlobalHealthBar({ id, alerts, start, end }) {
|
|
|
74
88
|
position: 'fixed',
|
|
75
89
|
}, content: (props) => {
|
|
76
90
|
return (_jsx(GlobalHealthBarTooltip, { tooltipData: tooltipData, tooltipProps: props, chartContainerRef: chartContainerRef, isKeyboardActive: keyboardActive, startTimestamp: startTimestamp, endTimestamp: endTimestamp }));
|
|
77
|
-
} }), _jsx(YAxis, { yAxisId: 'background', type: "category", hide: true }), allAlertBars.map(({ key }) => (_jsx(YAxis, { yAxisId: key, type: "category", hide: true }, `yAxis${key}`))), _jsx(Bar, { dataKey: "range", fill: theme.statusHealthy, radius: CHART_CONFIG.RADIUS_SIZE, yAxisId: "background", isAnimationActive: false }), allAlertBars.map(({ key, fill }) =>
|
|
91
|
+
} }), _jsx(YAxis, { yAxisId: 'background', type: "category", hide: true }), allAlertBars.map(({ key }) => (_jsx(YAxis, { yAxisId: key, type: "category", hide: true }, `yAxis${key}`))), _jsx(Bar, { dataKey: "range", fill: theme.statusHealthy, radius: CHART_CONFIG.RADIUS_SIZE, yAxisId: "background", isAnimationActive: false }), allAlertBars.map(({ key, fill }) => {
|
|
92
|
+
const isActive = key === activeBarKey;
|
|
93
|
+
// Skip active bar here - it will be rendered last
|
|
94
|
+
if (isActive)
|
|
95
|
+
return null;
|
|
96
|
+
return (_jsx(Bar, { dataKey: key, yAxisId: key, fill: fill, onPointerEnter: () => handlePointerEnter(key), onPointerLeave: () => handlePointerLeave(), isAnimationActive: false }, key));
|
|
97
|
+
}), activeBarKey &&
|
|
98
|
+
(() => {
|
|
99
|
+
const activeBar = allAlertBars.find((bar) => bar.key === activeBarKey);
|
|
100
|
+
if (!activeBar)
|
|
101
|
+
return null;
|
|
102
|
+
return (_jsx(Bar, { dataKey: activeBar.key, yAxisId: activeBar.key, fill: activeBar.fill, stroke: theme.selectedActive, onPointerEnter: () => handlePointerEnter(activeBar.key), onPointerLeave: () => handlePointerLeave(), isAnimationActive: false }, `${activeBar.key}-active`));
|
|
103
|
+
})()] }) }) }));
|
|
78
104
|
}
|
|
@@ -13,6 +13,6 @@ interface GlobalHealthBarTooltipProps {
|
|
|
13
13
|
startTimestamp?: number;
|
|
14
14
|
endTimestamp?: number;
|
|
15
15
|
}
|
|
16
|
-
export declare const GlobalHealthBarTooltip: (props: GlobalHealthBarTooltipProps) =>
|
|
16
|
+
export declare const GlobalHealthBarTooltip: (props: GlobalHealthBarTooltipProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
17
17
|
export {};
|
|
18
18
|
//# sourceMappingURL=GlobalHealthBarTooltip.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalHealthBarTooltip.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/globalhealthbar/components/GlobalHealthBarTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"GlobalHealthBarTooltip.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/globalhealthbar/components/GlobalHealthBarTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,KAAK,EAAE,MAAM,sCAAsC,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAK/C,UAAU,2BAA2B;IACnC,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,YAAY,EAAE,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,iBAAiB,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACnD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAoBD,eAAO,MAAM,sBAAsB,UAAW,2BAA2B,mDA6FxE,CAAC"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { createPortal } from 'react-dom';
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
2
|
import styled, { css, useTheme } from 'styled-components';
|
|
5
|
-
import { useFloating, autoUpdate, offset, flip, shift, } from '@floating-ui/react';
|
|
6
3
|
import { FormattedDateTime, Stack, Text, Wrap, spacing } from '../../../index';
|
|
7
4
|
import { zIndex } from '../../../style/theme';
|
|
8
5
|
import { CHART_CONFIG, getTooltipPosition } from '../healthBarUtils';
|
|
6
|
+
import { ChartTooltipPortal } from '../../charttooltip/ChartTooltip';
|
|
9
7
|
const TooltipContainer = styled.div `
|
|
10
8
|
${(props) => {
|
|
11
9
|
const theme = useTheme();
|
|
@@ -25,28 +23,11 @@ const TooltipContainer = styled.div `
|
|
|
25
23
|
export const GlobalHealthBarTooltip = (props) => {
|
|
26
24
|
const { tooltipData, tooltipProps, chartContainerRef, isKeyboardActive = false, startTimestamp = 0, endTimestamp = 0, } = props;
|
|
27
25
|
const { coordinate } = tooltipProps;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
middleware: [
|
|
34
|
-
offset(({ placement }) => {
|
|
35
|
-
// Use larger offset when tooltip is on top
|
|
36
|
-
// to avoid tooltip over bar
|
|
37
|
-
return placement.includes('top') ? 20 : 30;
|
|
38
|
-
}),
|
|
39
|
-
flip(),
|
|
40
|
-
shift({ padding: 10 }),
|
|
41
|
-
],
|
|
42
|
-
whileElementsMounted: autoUpdate,
|
|
43
|
-
});
|
|
44
|
-
// Create virtual element from coordinate
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
if (chartContainerRef.current) {
|
|
47
|
-
const chartRect = chartContainerRef.current.getBoundingClientRect();
|
|
48
|
-
let tooltipX;
|
|
49
|
-
let tooltipY;
|
|
26
|
+
if (!tooltipData)
|
|
27
|
+
return null;
|
|
28
|
+
const { description, startsAt, endsAt, severity } = tooltipData;
|
|
29
|
+
const tooltipContent = (_jsxs(Stack, { direction: "vertical", gap: "r8", children: [_jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", children: "Severity" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", children: severity })] }), _jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", children: "Start" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", children: _jsx(FormattedDateTime, { format: "date-time", value: new Date(startsAt) }) })] }), _jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", children: "End" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", children: _jsx(FormattedDateTime, { format: "date-time", value: new Date(endsAt) }) })] }), _jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", style: { paddingRight: spacing.r32 }, children: "Description" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", style: { whiteSpace: 'wrap', textAlign: 'justify' }, children: description })] })] }));
|
|
30
|
+
return (_jsx(ChartTooltipPortal, { coordinate: coordinate, chartContainerRef: chartContainerRef, isVisible: !!tooltipData, customPosition: (chartRect, coordinate) => {
|
|
50
31
|
if (isKeyboardActive && tooltipData && startTimestamp && endTimestamp) {
|
|
51
32
|
// Calculate the chart's usable width (excluding margins)
|
|
52
33
|
const chartUsableWidth = chartRect.width -
|
|
@@ -54,42 +35,21 @@ export const GlobalHealthBarTooltip = (props) => {
|
|
|
54
35
|
CHART_CONFIG.MARGINS.right;
|
|
55
36
|
// Use the same positioning logic as alert bars
|
|
56
37
|
const alertCenterX = getTooltipPosition(tooltipData, startTimestamp, endTimestamp, chartUsableWidth);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
38
|
+
return {
|
|
39
|
+
x: chartRect.left + alertCenterX,
|
|
40
|
+
y: chartRect.top + CHART_CONFIG.BAR_SIZE,
|
|
41
|
+
};
|
|
61
42
|
}
|
|
62
43
|
else {
|
|
63
44
|
// For mouse navigation, use the provided coordinate
|
|
64
|
-
|
|
65
|
-
|
|
45
|
+
return {
|
|
46
|
+
x: chartRect.left + ((coordinate === null || coordinate === void 0 ? void 0 : coordinate.x) || 0),
|
|
47
|
+
y: chartRect.top + ((coordinate === null || coordinate === void 0 ? void 0 : coordinate.y) || 0),
|
|
48
|
+
};
|
|
66
49
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
x: tooltipX,
|
|
73
|
-
y: tooltipY,
|
|
74
|
-
left: tooltipX,
|
|
75
|
-
top: tooltipY,
|
|
76
|
-
right: tooltipX,
|
|
77
|
-
bottom: tooltipY,
|
|
78
|
-
};
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}, [
|
|
83
|
-
coordinate,
|
|
84
|
-
chartContainerRef,
|
|
85
|
-
isKeyboardActive,
|
|
86
|
-
tooltipData,
|
|
87
|
-
startTimestamp,
|
|
88
|
-
endTimestamp,
|
|
89
|
-
]);
|
|
90
|
-
if (!tooltipData)
|
|
91
|
-
return null;
|
|
92
|
-
const { description, startsAt, endsAt, severity } = tooltipData;
|
|
93
|
-
const tooltipContent = (_jsx(TooltipContainer, { ref: refs.setFloating, style: floatingStyles, children: _jsxs(Stack, { direction: "vertical", gap: "r8", children: [_jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", children: "Severity" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", children: severity })] }), _jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", children: "Start" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", children: _jsx(FormattedDateTime, { format: "date-time", value: new Date(startsAt) }) })] }), _jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", children: "End" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", children: _jsx(FormattedDateTime, { format: "date-time", value: new Date(endsAt) }) })] }), _jsxs(Wrap, { children: [_jsx(Text, { variant: "Smaller", style: { paddingRight: spacing.r32 }, children: "Description" }), _jsx(Text, { color: "textPrimary", variant: "Smaller", style: { whiteSpace: 'wrap', textAlign: 'justify' }, children: description })] })] }) }));
|
|
94
|
-
return createPortal(tooltipContent, document.body);
|
|
50
|
+
}, containerComponent: TooltipContainer, offset: ({ placement }) => {
|
|
51
|
+
// Use larger offset when tooltip is on top
|
|
52
|
+
// to avoid tooltip over bar
|
|
53
|
+
return placement.includes('top') ? 20 : 30;
|
|
54
|
+
}, children: tooltipContent }));
|
|
95
55
|
};
|
|
@@ -14,7 +14,7 @@ const CustomTick = ({ tickProps, startTimestamp, endTimestamp, }) => {
|
|
|
14
14
|
const edgeMargin = getEdgeMargin(index, visibleTicksCount, isDaySpan);
|
|
15
15
|
return (
|
|
16
16
|
// use coordinate to center the text
|
|
17
|
-
shouldShowLabel && (_jsx("g", { transform: `translate(${payload.coordinate},${y})`, children: _jsx("text", { textAnchor: "middle", dy: 10, dx: edgeMargin, fontSize: fontSize.smaller, fill: theme.textSecondary, children: is7DaySpan
|
|
17
|
+
shouldShowLabel && (_jsx("g", { transform: `translate(${payload.coordinate},${y})`, children: _jsx("text", { textAnchor: "middle", dy: 10, dx: edgeMargin, fontSize: fontSize.smaller, fill: theme.textSecondary, children: is7DaySpan ? (_jsx(FormattedDateTime, { format: "day-month-abbreviated-hour-minute", value: new Date(payload.value) })) : (_jsx(FormattedDateTime, { format: "time", value: new Date(payload.value) })) }) })));
|
|
18
18
|
};
|
|
19
19
|
export const HealthBarXAxis = ({ startTimestamp, endTimestamp, }) => {
|
|
20
20
|
const theme = useTheme();
|
|
@@ -3,6 +3,7 @@ export interface Alert {
|
|
|
3
3
|
startsAt: string;
|
|
4
4
|
endsAt: string;
|
|
5
5
|
severity: 'warning' | 'critical' | 'unavailable';
|
|
6
|
+
key: string;
|
|
6
7
|
}
|
|
7
8
|
export declare const useHealthBarData: (alerts: Alert[], startTimestamp: number, endTimestamp: number, id: string) => {
|
|
8
9
|
chartData: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useHealthBarData.d.ts","sourceRoot":"","sources":["../../../src/lib/components/globalhealthbar/useHealthBarData.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,KAAK;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,GAAG,UAAU,GAAG,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"useHealthBarData.d.ts","sourceRoot":"","sources":["../../../src/lib/components/globalhealthbar/useHealthBarData.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,KAAK;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,GAAG,UAAU,GAAG,aAAa,CAAC;IACjD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,gBAAgB,WACnB,KAAK,EAAE,kBACC,MAAM,gBACR,MAAM,MAChB,MAAM;;;;;;;;;;CA6DX,CAAC"}
|
|
@@ -20,6 +20,7 @@ export const useHealthBarData = (alerts, startTimestamp, endTimestamp, id) => {
|
|
|
20
20
|
// Store alert data separately for tooltip access
|
|
21
21
|
alertsMapData[uniqueKey] = {
|
|
22
22
|
...alert,
|
|
23
|
+
key: uniqueKey, // Add the consistent key to the alert object
|
|
23
24
|
};
|
|
24
25
|
});
|
|
25
26
|
// Chart data - ready for BarChart (as array)
|
|
@@ -10,6 +10,7 @@ describe('useHealthBarData', () => {
|
|
|
10
10
|
severity,
|
|
11
11
|
startsAt,
|
|
12
12
|
endsAt,
|
|
13
|
+
key: `${severity}_${startsAt}`,
|
|
13
14
|
});
|
|
14
15
|
describe('Alert Filtering', () => {
|
|
15
16
|
it('should include alerts that are completely within the time range', () => {
|
|
@@ -93,6 +94,7 @@ describe('useHealthBarData', () => {
|
|
|
93
94
|
severity: 'warning',
|
|
94
95
|
startsAt: '2023-12-01T02:00:00Z',
|
|
95
96
|
endsAt: '2023-12-01T04:00:00Z',
|
|
97
|
+
key: 'warning_0',
|
|
96
98
|
});
|
|
97
99
|
});
|
|
98
100
|
it('should handle multiple alerts with correct indexing', () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TooltipContentProps } from 'recharts';
|
|
2
|
+
import React from 'react';
|
|
2
3
|
export type Serie = {
|
|
3
4
|
resource: string;
|
|
4
5
|
data: [number, number | string | null][];
|
|
@@ -37,7 +38,7 @@ export type LineChartProps = (NonSymmetricalChartSerie | SymmetricalChartSerie)
|
|
|
37
38
|
timeFormat?: 'date-time' | 'date';
|
|
38
39
|
yAxisTitle?: string;
|
|
39
40
|
helpText?: string;
|
|
40
|
-
renderTooltip?: (tooltipProps: TooltipContentProps<number, string>, unitLabel?: string,
|
|
41
|
+
renderTooltip?: (tooltipProps: TooltipContentProps<number, string>, unitLabel?: string, duration?: number) => React.ReactNode;
|
|
41
42
|
};
|
|
42
43
|
export declare function LineTimeSerieChart({ series, title, height, startingTimeStamp, interval, duration, unitRange, isLoading, timeFormat, yAxisType, yAxisTitle, helpText, syncId, renderTooltip, ...rest }: LineChartProps): import("react/jsx-runtime").JSX.Element;
|
|
43
44
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linetimeseriechart.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,mBAAmB,EAGpB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"linetimeseriechart.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,mBAAmB,EAGpB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAiD,MAAM,OAAO,CAAC;AAiCtE,MAAM,MAAM,KAAK,GAAG;IAElB,QAAQ,EAAE,MAAM,CAAC;IAEjB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAEzC,eAAe,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtE,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,SAAS,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IACrC,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;CAC7B,CAAC;AAGF,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,EACF;QACE,KAAK,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;QAC3B,KAAK,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;KAC5B,GACD,SAAS,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CACzB,wBAAwB,GACxB,qBAAqB,CACxB,GAAG;IACF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;IACJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,CACd,YAAY,EAAE,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,EACjD,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,KACd,KAAK,CAAC,SAAS,CAAC;CACtB,CAAC;AAiHF,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,KAAK,EACL,MAAM,EACN,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAiB,EACjB,UAAwB,EACxB,SAAqB,EACrB,UAAU,EACV,QAAQ,EACR,MAAM,EACN,aAAa,EACb,GAAG,IAAI,EACR,EAAE,cAAc,2CAqWhB"}
|
|
@@ -1,60 +1,58 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { CartesianGrid, Line, LineChart, ReferenceLine, Tooltip, XAxis, YAxis, } from 'recharts';
|
|
3
|
-
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import styled, { useTheme } from 'styled-components';
|
|
5
|
-
import {
|
|
5
|
+
import { Stack } from '../../spacing';
|
|
6
6
|
import { fontSize } from '../../style/theme';
|
|
7
|
-
import { Box } from '../box/Box';
|
|
8
7
|
import { useChartLegend } from '../chartlegend/ChartLegendWrapper';
|
|
9
|
-
import { FormattedDateTime } from '../date/FormattedDateTime';
|
|
10
|
-
import { Icon } from '../icon/Icon.component';
|
|
11
8
|
import { addMissingDataPoint, getUnitLabel, } from '../linetemporalchart/ChartUtil';
|
|
12
9
|
import { Loader } from '../loader/Loader.component';
|
|
13
|
-
import { ChartTitleText
|
|
14
|
-
import { Tooltip as TooltipComponent } from '../tooltip/Tooltip.component';
|
|
10
|
+
import { ChartTitleText } from '../text/Text.component';
|
|
15
11
|
import { formatXAxisLabel } from './utils';
|
|
16
|
-
import {
|
|
12
|
+
import { ChartTooltipPortal, ChartTooltipItem, ChartTooltipHeader, ChartTooltipItemsContainer, ChartTooltipSeparator, TooltipHeader, } from '../charttooltip/ChartTooltip';
|
|
17
13
|
import { LegendShape } from '../chartlegend/ChartLegend';
|
|
18
14
|
import { StyledResponsiveContainer } from '../barchartv2/Barchart.component';
|
|
15
|
+
import { getRoundReferenceValue, getTicks } from '../barchartv2/utils';
|
|
16
|
+
import { IconHelp } from '../iconhelper/IconHelper';
|
|
17
|
+
const maxWidthTooltip = { maxWidth: '20rem' };
|
|
19
18
|
const LineTemporalChartWrapper = styled.div `
|
|
20
19
|
display: flex;
|
|
21
20
|
flex-direction: column;
|
|
22
21
|
justify-content: flex-start;
|
|
23
22
|
`;
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
align-items: center;
|
|
27
|
-
`;
|
|
28
|
-
const LineTimeSerieChartTooltip = ({ unitLabel, timeFormat, isChartActive, tooltipProps, renderTooltip, hoveredValue, }) => {
|
|
29
|
-
const { active, payload, label } = tooltipProps;
|
|
23
|
+
const LineTimeSerieChartTooltip = ({ unitLabel, duration, isChartActive, tooltipProps, renderTooltip, hoveredValue, isSymmetrical, chartContainerRef, }) => {
|
|
24
|
+
const { active, payload, label, coordinate } = tooltipProps;
|
|
30
25
|
if (!active || !payload || !payload.length || !label || !isChartActive)
|
|
31
26
|
return null;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
27
|
+
const tooltipContent = renderTooltip ? (renderTooltip(tooltipProps, unitLabel, duration)) : (_jsxs(_Fragment, { children: [_jsx(ChartTooltipHeader, { children: _jsx(TooltipHeader, { duration: duration, value: label }) }), _jsx(ChartTooltipItemsContainer, { children: (() => {
|
|
28
|
+
// We can't use the default itemSorter method because it's a custom tooltip.
|
|
29
|
+
// Sort the payload here instead
|
|
30
|
+
const sortedPayload = [...payload].sort((a, b) => {
|
|
31
|
+
const aValue = a.value;
|
|
32
|
+
const bValue = b.value;
|
|
33
|
+
if (aValue >= 0 && bValue >= 0) {
|
|
34
|
+
return bValue - aValue; // Higher positive values first
|
|
35
|
+
}
|
|
36
|
+
if (aValue < 0 && bValue < 0) {
|
|
37
|
+
return bValue - aValue; // Lower negative values first
|
|
38
|
+
}
|
|
39
|
+
return bValue - aValue; // Positives before negatives
|
|
40
|
+
});
|
|
41
|
+
// Find the transition point between positive and negative values
|
|
42
|
+
const separatorIndex = sortedPayload.findIndex((entry) => entry.value < 0);
|
|
43
|
+
const hasBothPositiveAndNegative = separatorIndex > 0 && separatorIndex < sortedPayload.length;
|
|
44
|
+
return sortedPayload.map((entry, index) => {
|
|
45
|
+
const legendIcon = (_jsx(LegendShape, { color: entry.color, shape: "line", chartColors: { [entry.color]: entry.color } }));
|
|
46
|
+
const isHovered = entry.name === hoveredValue;
|
|
47
|
+
const formattedValue = !Number.isFinite(entry.value)
|
|
48
|
+
? '-'
|
|
49
|
+
: `${entry.value.toFixed(2)} ${unitLabel}`;
|
|
50
|
+
return (_jsxs(React.Fragment, { children: [isSymmetrical &&
|
|
51
|
+
hasBothPositiveAndNegative &&
|
|
52
|
+
index === separatorIndex && _jsx(ChartTooltipSeparator, {}), _jsx(ChartTooltipItem, { label: entry.name, value: formattedValue, legendIcon: legendIcon, isHovered: isHovered })] }, index));
|
|
53
|
+
});
|
|
54
|
+
})() })] }));
|
|
55
|
+
return (_jsx(ChartTooltipPortal, { coordinate: coordinate, chartContainerRef: chartContainerRef, isVisible: active && isChartActive, children: tooltipContent }));
|
|
58
56
|
};
|
|
59
57
|
const isSymmetricalSeries = (series) => {
|
|
60
58
|
return 'above' in series && 'below' in series;
|
|
@@ -170,7 +168,8 @@ export function LineTimeSerieChart({ series, title, height, startingTimeStamp, i
|
|
|
170
168
|
const bottom = Math.abs(Math.min(...values));
|
|
171
169
|
const maxValue = Math.max(top, bottom);
|
|
172
170
|
const { valueBase, unitLabel } = getUnitLabel(unitRange !== null && unitRange !== void 0 ? unitRange : [], maxValue);
|
|
173
|
-
|
|
171
|
+
// Use round reference value to add extra padding to the top value
|
|
172
|
+
const topValue = getRoundReferenceValue(maxValue / valueBase);
|
|
174
173
|
const rechartsData = chartData.map((dataPoint) => {
|
|
175
174
|
const normalizedDataPoint = { ...dataPoint };
|
|
176
175
|
Object.entries(dataPoint).forEach(([key, value]) => {
|
|
@@ -219,16 +218,15 @@ export function LineTimeSerieChart({ series, title, height, startingTimeStamp, i
|
|
|
219
218
|
};
|
|
220
219
|
}, [series, getColor, selectedResources]);
|
|
221
220
|
// Format time for display the tick in the x axis
|
|
222
|
-
const formatXAxisLabelCallback = useCallback((timestamp) => formatXAxisLabel(timestamp,
|
|
223
|
-
return (_jsxs(LineTemporalChartWrapper, { children: [_jsxs(
|
|
221
|
+
const formatXAxisLabelCallback = useCallback((timestamp) => formatXAxisLabel(timestamp, duration), [duration]);
|
|
222
|
+
return (_jsxs(LineTemporalChartWrapper, { children: [_jsxs(Stack, { gap: "r4", children: [_jsxs(ChartTitleText, { children: [title, " ", unitLabel && `(${unitLabel})`] }), helpText && (_jsx(IconHelp, { tooltipMessage: helpText, overlayStyle: maxWidthTooltip })), isLoading && _jsx(Loader, {})] }), _jsx("div", { onFocus: () => setIsChartActive(true), onBlur: () => setIsChartActive(false), onFocusCapture: () => setIsChartActive(true), onBlurCapture: () => setIsChartActive(false), children: _jsx(StyledResponsiveContainer, { width: "100%", height: height, children: _jsxs(LineChart, { data: rechartsData, ref: chartRef, margin: { top: 0, right: 0, bottom: 0, left: 0 }, "aria-label": `Time series chart for ${title}`, syncId: syncId, onMouseEnter: () => setIsChartActive(true), onMouseLeave: () => setIsChartActive(false), accessibilityLayer: true, children: [_jsx(CartesianGrid, { vertical: true, horizontal: true, verticalPoints: [0], horizontalPoints: [0], stroke: theme.border, fill: theme.backgroundLevel4, strokeWidth: 1 }), _jsx(XAxis, { dataKey: "timestamp", type: "number", domain: ['dataMin', 'dataMax'], ticks: xAxisTicks, tickFormatter: formatXAxisLabelCallback, tickCount: 5, tick: {
|
|
224
223
|
fill: theme.textSecondary,
|
|
225
224
|
fontSize: fontSize.smaller,
|
|
226
225
|
}, axisLine: { stroke: theme.border } }), _jsx(YAxis, { orientation: "right", label: {
|
|
227
226
|
value: yAxisTitle,
|
|
228
227
|
angle: 90,
|
|
229
|
-
|
|
228
|
+
dx: 20,
|
|
230
229
|
style: {
|
|
231
|
-
textAnchor: 'middle',
|
|
232
230
|
fill: theme.textSecondary,
|
|
233
231
|
fontSize: fontSize.smaller,
|
|
234
232
|
},
|
|
@@ -239,7 +237,7 @@ export function LineTimeSerieChart({ series, title, height, startingTimeStamp, i
|
|
|
239
237
|
: [0, topValue], axisLine: { stroke: theme.border }, tick: {
|
|
240
238
|
fill: theme.textSecondary,
|
|
241
239
|
fontSize: fontSize.smaller,
|
|
242
|
-
}, tickFormatter: (value) => new Intl.NumberFormat('fr-FR').format(value
|
|
240
|
+
}, tickFormatter: (value) => new Intl.NumberFormat('fr-FR').format(value), ticks: getTicks(topValue, yAxisType === 'symmetrical'), interval: 0 }), _jsx(Tooltip, { content: (props) => (_jsx(LineTimeSerieChartTooltip, { unitLabel: unitLabel, duration: duration, renderTooltip: renderTooltip, isSymmetrical: yAxisType === 'symmetrical', tooltipProps: props, isChartActive: isChartActive, hoveredValue: hoveredValue, chartContainerRef: chartRef })) }), yAxisType === 'symmetrical' && (_jsx(ReferenceLine, { y: 0, stroke: theme.border })), Object.entries(groupedSeries).map(([resource, resourceSeries]) => resourceSeries.map((serie, serieIndex) => {
|
|
243
241
|
const label = serie.getTooltipLabel(serie.metricPrefix, serie.resource);
|
|
244
242
|
return (_jsx(Line, { type: "monotone", dataKey: label, stroke: colorMapping[resource], dot: false, isAnimationActive: false, strokeDasharray: serie.isLineDashed ? '4 4' : undefined, onMouseEnter: () => setHoveredValue(label), onMouseLeave: () => setHoveredValue(undefined) }, `${title}-${resource}-${serieIndex}`));
|
|
245
243
|
}))] }) }) })] }));
|
|
@@ -12,5 +12,5 @@ export type ChartDataPoint = {
|
|
|
12
12
|
* @param chartData - The chart data to determine time range for optimal formatting
|
|
13
13
|
* @returns Formatted string for display on X-axis
|
|
14
14
|
*/
|
|
15
|
-
export declare const formatXAxisLabel: (timestamp: number,
|
|
15
|
+
export declare const formatXAxisLabel: (timestamp: number, duration: number) => string;
|
|
16
16
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/components/linetimeseriechart/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,QAA4B,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AAElC;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,cAChB,MAAM,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/components/linetimeseriechart/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,QAA4B,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AAElC;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,cAChB,MAAM,YACP,MAAM,KACf,MAaF,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TIME_FORMATER, DAY_MONTH_ABBREVIATED_YEAR, DAY_MONTH_ABBREVIATED_HOUR_MINUTE, } from '../date/FormattedDateTime';
|
|
2
2
|
export const ONE_YEAR_MILLISECONDS = 366 * 24 * 60 * 60 * 1000;
|
|
3
3
|
/**
|
|
4
4
|
* Formats timestamp for X-axis labels based on time format and data range:
|
|
@@ -10,19 +10,19 @@ export const ONE_YEAR_MILLISECONDS = 366 * 24 * 60 * 60 * 1000;
|
|
|
10
10
|
* @param chartData - The chart data to determine time range for optimal formatting
|
|
11
11
|
* @returns Formatted string for display on X-axis
|
|
12
12
|
*/
|
|
13
|
-
export const formatXAxisLabel = (timestamp,
|
|
13
|
+
export const formatXAxisLabel = (timestamp, duration) => {
|
|
14
14
|
const date = new Date(timestamp);
|
|
15
|
-
if (
|
|
16
|
-
return
|
|
15
|
+
if (duration <= 24 * 60 * 60) {
|
|
16
|
+
return TIME_FORMATER.format(date);
|
|
17
17
|
}
|
|
18
|
-
if (
|
|
19
|
-
return DAY_MONTH_ABBREVIATED_HOUR_MINUTE.format(date)
|
|
18
|
+
else if (duration <= 7 * 24 * 60 * 60) {
|
|
19
|
+
return DAY_MONTH_ABBREVIATED_HOUR_MINUTE.format(date)
|
|
20
|
+
.replace(',', '')
|
|
21
|
+
.replace(/Sept/g, 'Sep');
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return DAY_MONTH_ABBREVIATED_YEAR.format(date)
|
|
25
|
+
.replace(/[ ,]/g, '')
|
|
26
|
+
.replace(/Sept/g, 'Sep');
|
|
20
27
|
}
|
|
21
|
-
const timestamps = chartData.map((d) => d.timestamp);
|
|
22
|
-
const minTimestamp = Math.min(...timestamps);
|
|
23
|
-
const maxTimestamp = Math.max(...timestamps);
|
|
24
|
-
const timeRangeMilliseconds = maxTimestamp - minTimestamp;
|
|
25
|
-
return timeRangeMilliseconds >= ONE_YEAR_MILLISECONDS
|
|
26
|
-
? YEAR_MONTH_DAY_FORMATTER.format(date)
|
|
27
|
-
: MONTH_DAY_FORMATTER.format(date);
|
|
28
28
|
};
|
package/dist/style/theme.js
CHANGED