@scality/core-ui 0.174.0 → 0.176.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.
Files changed (46) hide show
  1. package/dist/components/barchartv2/Barchart.component.d.ts +4 -4
  2. package/dist/components/barchartv2/Barchart.component.d.ts.map +1 -1
  3. package/dist/components/barchartv2/Barchart.component.js +22 -32
  4. package/dist/components/barchartv2/BarchartTooltip.d.ts +1 -1
  5. package/dist/components/barchartv2/BarchartTooltip.d.ts.map +1 -1
  6. package/dist/components/barchartv2/BarchartTooltip.js +6 -6
  7. package/dist/components/barchartv2/utils.d.ts.map +1 -1
  8. package/dist/components/chartlegend/ChartLegendWrapper.js +1 -1
  9. package/dist/components/charttooltip/ChartTooltip.d.ts +6 -0
  10. package/dist/components/charttooltip/ChartTooltip.d.ts.map +1 -1
  11. package/dist/components/charttooltip/ChartTooltip.js +22 -0
  12. package/dist/components/date/FormattedDateTime.d.ts +23 -8
  13. package/dist/components/date/FormattedDateTime.d.ts.map +1 -1
  14. package/dist/components/date/FormattedDateTime.js +51 -7
  15. package/dist/components/icon/Icon.component.d.ts +1 -0
  16. package/dist/components/icon/Icon.component.d.ts.map +1 -1
  17. package/dist/components/icon/Icon.component.js +1 -0
  18. package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts +2 -1
  19. package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts.map +1 -1
  20. package/dist/components/linetimeseriechart/linetimeseriechart.component.js +19 -17
  21. package/dist/components/linetimeseriechart/utils.d.ts +1 -1
  22. package/dist/components/linetimeseriechart/utils.d.ts.map +1 -1
  23. package/dist/components/linetimeseriechart/utils.js +13 -13
  24. package/dist/components/scrollbarwrapper/ScrollbarWrapper.component.d.ts.map +1 -1
  25. package/dist/components/scrollbarwrapper/ScrollbarWrapper.component.js +2 -0
  26. package/dist/components/sparkline/sparkline.component.d.ts +2 -1
  27. package/dist/components/sparkline/sparkline.component.d.ts.map +1 -1
  28. package/dist/components/sparkline/sparkline.component.js +3 -3
  29. package/package.json +1 -1
  30. package/src/lib/components/barchartv2/Barchart.component.test.tsx +23 -25
  31. package/src/lib/components/barchartv2/Barchart.component.tsx +36 -45
  32. package/src/lib/components/barchartv2/BarchartTooltip.test.tsx +3 -3
  33. package/src/lib/components/barchartv2/BarchartTooltip.tsx +14 -18
  34. package/src/lib/components/barchartv2/utils.ts +1 -5
  35. package/src/lib/components/chartlegend/ChartLegendWrapper.tsx +1 -1
  36. package/src/lib/components/charttooltip/ChartTooltip.tsx +40 -0
  37. package/src/lib/components/date/FormattedDateTime.tsx +73 -8
  38. package/src/lib/components/icon/Icon.component.tsx +1 -0
  39. package/src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx +43 -34
  40. package/src/lib/components/linetimeseriechart/utils.test.ts +30 -68
  41. package/src/lib/components/linetimeseriechart/utils.ts +14 -18
  42. package/src/lib/components/scrollbarwrapper/ScrollbarWrapper.component.tsx +3 -1
  43. package/src/lib/components/sparkline/sparkline.component.tsx +5 -3
  44. package/stories/formattedate.stories.tsx +2 -0
  45. package/stories/linetimeseriechart.stories.tsx +1 -0
  46. package/stories/sparkline.stories.tsx +19 -0
@@ -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,eACL,WAAW,GAAG,MAAM,cACrB,cAAc,EAAE,KAC1B,MAgBF,CAAC"}
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 { DAY_MONTH_ABBREVIATED_HOUR_MINUTE, YEAR_MONTH_DAY_FORMATTER, MONTH_DAY_FORMATTER, } from '../date/FormattedDateTime';
1
+ import { TIME_FORMATER, DAY_MONTH_ABBREVIATED, DAY_MONTH_ABBREVIATED_YEAR, } 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, timeFormat = 'date-time', chartData = []) => {
13
+ export const formatXAxisLabel = (timestamp, duration) => {
14
14
  const date = new Date(timestamp);
15
- if (!chartData.length) {
16
- return YEAR_MONTH_DAY_FORMATTER.format(date);
15
+ if (duration <= 24 * 60 * 60) {
16
+ return TIME_FORMATER.format(date);
17
17
  }
18
- if (timeFormat === 'date-time') {
19
- return DAY_MONTH_ABBREVIATED_HOUR_MINUTE.format(date).replace(',', '');
18
+ else if (duration <= 7 * 24 * 60 * 60) {
19
+ return DAY_MONTH_ABBREVIATED.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
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ScrollbarWrapper.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/scrollbarwrapper/ScrollbarWrapper.component.tsx"],"names":[],"mappings":"AAEA,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAmDF,iBAAS,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE,KAAK,2CAO5C;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"ScrollbarWrapper.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/scrollbarwrapper/ScrollbarWrapper.component.tsx"],"names":[],"mappings":"AAEA,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAqDF,iBAAS,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE,KAAK,2CAO5C;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -20,6 +20,7 @@ ${(props) => {
20
20
  width: 4px;
21
21
  height: 4px;
22
22
  min-height: 20px;
23
+ background: ${brand.border}; // fallback for gradient themes
23
24
  background: ${brand.buttonSecondary};
24
25
  border-radius: 4px;
25
26
  -webkit-border-radius: 4px;
@@ -42,6 +43,7 @@ ${(props) => {
42
43
  }
43
44
 
44
45
  // Firefox
46
+ scrollbar-color: ${brand.border} ${brand.backgroundLevel3}; // fallback for gradient themes
45
47
  scrollbar-color: ${brand.buttonSecondary} ${brand.backgroundLevel3};
46
48
  scrollbar-width: thin;
47
49
  }
@@ -6,11 +6,12 @@ type SparklineProps = {
6
6
  startingTimeStamp: number;
7
7
  sampleDuration: number;
8
8
  sampleInterval: number;
9
+ yAxisType?: 'default' | 'percentage';
9
10
  };
10
11
  /**
11
12
  * Sparkline is a simple dynamically sized area chart.
12
13
  * Used to show trends in data over time.
13
14
  */
14
- export declare function Sparkline({ serie, startingTimeStamp, sampleDuration, sampleInterval }: SparklineProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function Sparkline({ serie, startingTimeStamp, sampleDuration, sampleInterval, yAxisType }: SparklineProps): import("react/jsx-runtime").JSX.Element;
15
16
  export {};
16
17
  //# sourceMappingURL=sparkline.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sparkline.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/sparkline/sparkline.component.tsx"],"names":[],"mappings":"AAMA,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE;QACL,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,GAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAA;CACvB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,EAAE,cAAc,2CAiCrG"}
1
+ {"version":3,"file":"sparkline.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/sparkline/sparkline.component.tsx"],"names":[],"mappings":"AAMA,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE;QACL,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,GAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;CACtC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,cAAc,2CAkChH"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
- import { Area, AreaChart, CartesianGrid, ResponsiveContainer } from "recharts";
3
+ import { Area, AreaChart, CartesianGrid, ResponsiveContainer, YAxis } from "recharts";
4
4
  import { useTheme } from "styled-components";
5
5
  import { chartColors } from "../../style/theme";
6
6
  import { addMissingDataPoint } from "../linetemporalchart/ChartUtil";
@@ -8,7 +8,7 @@ import { addMissingDataPoint } from "../linetemporalchart/ChartUtil";
8
8
  * Sparkline is a simple dynamically sized area chart.
9
9
  * Used to show trends in data over time.
10
10
  */
11
- export function Sparkline({ serie, startingTimeStamp, sampleDuration, sampleInterval }) {
11
+ export function Sparkline({ serie, startingTimeStamp, sampleDuration, sampleInterval, yAxisType }) {
12
12
  var _a;
13
13
  const data = useMemo(() => {
14
14
  const dataMdp = addMissingDataPoint(serie.data, startingTimeStamp, sampleDuration, sampleInterval);
@@ -16,5 +16,5 @@ export function Sparkline({ serie, startingTimeStamp, sampleDuration, sampleInte
16
16
  }, [serie.data]);
17
17
  const color = (_a = serie.color) !== null && _a !== void 0 ? _a : chartColors.lineColor1;
18
18
  const strokeGridColor = useTheme().border;
19
- return (_jsx(ResponsiveContainer, { children: _jsxs(AreaChart, { data: data, children: [_jsx("defs", { children: _jsxs("linearGradient", { id: `gradient-${color}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "0%", stopColor: color, stopOpacity: 0.7 }), _jsx("stop", { offset: "100%", stopColor: color, stopOpacity: 0.1 })] }) }), _jsx(CartesianGrid, { horizontal: false, stroke: strokeGridColor, strokeOpacity: 0.5 }), _jsx(Area, { type: "linear", dataKey: "y", stroke: color, fill: `url(#gradient-${color})`, dot: false, activeDot: false, isAnimationActive: false })] }) }));
19
+ return (_jsx(ResponsiveContainer, { children: _jsxs(AreaChart, { data: data, children: [_jsx("defs", { children: _jsxs("linearGradient", { id: `gradient-${color}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "0%", stopColor: color, stopOpacity: 0.7 }), _jsx("stop", { offset: "100%", stopColor: color, stopOpacity: 0.1 })] }) }), _jsx(CartesianGrid, { horizontal: false, stroke: strokeGridColor, strokeOpacity: 0.5 }), _jsx(Area, { type: "linear", dataKey: "y", stroke: color, fill: `url(#gradient-${color})`, dot: false, activeDot: false, isAnimationActive: false }), yAxisType === 'percentage' && _jsx(YAxis, { domain: [0, 100], hide: true })] }) }));
20
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scality/core-ui",
3
- "version": "0.174.0",
3
+ "version": "0.176.0",
4
4
  "description": "Scality common React component library",
5
5
  "author": "Scality Engineering",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -89,9 +89,9 @@ describe('Barchart', () => {
89
89
  </Wrapper>,
90
90
  );
91
91
 
92
- expect(screen.getByText('Fri05Jul')).toBeInTheDocument();
93
- expect(screen.getByText('Sat06Jul')).toBeInTheDocument();
94
- expect(screen.getByText('Sun07Jul')).toBeInTheDocument();
92
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
93
+ expect(screen.getByText('06 Jul')).toBeInTheDocument();
94
+ expect(screen.getByText('07 Jul')).toBeInTheDocument();
95
95
  });
96
96
  it('should render the Barchart component with error state', async () => {
97
97
  const { Wrapper } = getWrapper();
@@ -153,11 +153,11 @@ describe('Barchart', () => {
153
153
  </ChartLegendWrapper>
154
154
  </Wrapper>,
155
155
  );
156
- expect(screen.getByText('Wed03Jul')).toBeInTheDocument();
157
- expect(screen.getByText('Thu04Jul')).toBeInTheDocument();
158
- expect(screen.getByText('Fri05Jul')).toBeInTheDocument();
159
- expect(screen.getByText('Sat06Jul')).toBeInTheDocument();
160
- expect(screen.getByText('Sun07Jul')).toBeInTheDocument();
156
+ expect(screen.getByText('03 Jul')).toBeInTheDocument();
157
+ expect(screen.getByText('04 Jul')).toBeInTheDocument();
158
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
159
+ expect(screen.getByText('06 Jul')).toBeInTheDocument();
160
+ expect(screen.getByText('07 Jul')).toBeInTheDocument();
161
161
  });
162
162
  it('should render when there are missing data in the time range', async () => {
163
163
  const bars = [
@@ -203,10 +203,10 @@ describe('Barchart', () => {
203
203
 
204
204
  // Check that all days are present
205
205
  await waitFor(() => {
206
- expect(screen.getByText('Fri05Jul')).toBeInTheDocument();
207
- expect(screen.getByText('Sat06Jul')).toBeInTheDocument();
208
- expect(screen.getByText('Sun07Jul')).toBeInTheDocument();
209
- expect(screen.getByText('Mon08Jul')).toBeInTheDocument();
206
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
207
+ expect(screen.getByText('06 Jul')).toBeInTheDocument();
208
+ expect(screen.getByText('07 Jul')).toBeInTheDocument();
209
+ expect(screen.getByText('08 Jul')).toBeInTheDocument();
210
210
  });
211
211
  });
212
212
  it('should render for a specific time range', async () => {
@@ -244,13 +244,13 @@ describe('Barchart', () => {
244
244
  </Wrapper>,
245
245
  );
246
246
  await waitFor(() => {
247
- expect(screen.getByText('Fri05Jul')).toBeInTheDocument();
248
- expect(screen.getByText('Sat06Jul')).toBeInTheDocument();
249
- expect(screen.getByText('Sun07Jul')).toBeInTheDocument();
250
- expect(screen.getByText('Mon08Jul')).toBeInTheDocument();
251
- expect(screen.getByText('Tue09Jul')).toBeInTheDocument();
252
- expect(screen.getByText('Wed10Jul')).toBeInTheDocument();
253
- expect(screen.getByText('Thu11Jul')).toBeInTheDocument();
247
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
248
+ expect(screen.getByText('06 Jul')).toBeInTheDocument();
249
+ expect(screen.getByText('07 Jul')).toBeInTheDocument();
250
+ expect(screen.getByText('08 Jul')).toBeInTheDocument();
251
+ expect(screen.getByText('09 Jul')).toBeInTheDocument();
252
+ expect(screen.getByText('10 Jul')).toBeInTheDocument();
253
+ expect(screen.getByText('11 Jul')).toBeInTheDocument();
254
254
  });
255
255
  });
256
256
  it('should render the Barchart component with hourly intervals', async () => {
@@ -411,7 +411,7 @@ describe('Barchart', () => {
411
411
  />
412
412
  </Wrapper>,
413
413
  );
414
- expect(screen.getByText('Fri05Jul 10:00')).toBeInTheDocument();
414
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
415
415
  });
416
416
 
417
417
  it('should render the CustomTick component with day format', () => {
@@ -435,7 +435,7 @@ describe('Barchart', () => {
435
435
  />
436
436
  </Wrapper>,
437
437
  );
438
- expect(screen.getByText('Fri05Jul')).toBeInTheDocument();
438
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
439
439
  });
440
440
  it('should render the CustomTick component with hour format', () => {
441
441
  const { Wrapper } = getWrapper();
@@ -458,7 +458,7 @@ describe('Barchart', () => {
458
458
  />
459
459
  </Wrapper>,
460
460
  );
461
- expect(screen.getByText('10:00')).toBeInTheDocument();
461
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
462
462
  });
463
463
  it('should render the CustomTick component with minute format', () => {
464
464
  const { Wrapper } = getWrapper();
@@ -481,9 +481,7 @@ describe('Barchart', () => {
481
481
  />
482
482
  </Wrapper>,
483
483
  );
484
- expect(
485
- screen.getByText(new Date('2024-07-05T10:00:00').getTime()),
486
- ).toBeInTheDocument();
484
+ expect(screen.getByText('05 Jul')).toBeInTheDocument();
487
485
  });
488
486
  });
489
487
  });
@@ -3,7 +3,6 @@ import {
3
3
  Bar,
4
4
  BarChart,
5
5
  CartesianGrid,
6
- ReferenceLine,
7
6
  ResponsiveContainer,
8
7
  Tooltip,
9
8
  TooltipContentProps,
@@ -112,33 +111,19 @@ interface CustomTickProps {
112
111
  /* ---------------------------------- COMPONENTS ---------------------------------- */
113
112
 
114
113
  /**
115
- * Formats a date based on the interval
116
- * @param timestamp - Timestamp
117
- * @param interval - Interval in milliseconds
114
+ * Get the format of the date based on the duration
115
+ * @param duration - Duration in milliseconds
118
116
  * @returns Formatted string
119
117
  */
120
118
  export const formatDate = (
121
- timestamp: number,
122
- interval: number,
123
- ): React.ReactNode => {
124
- const date = new Date(timestamp);
125
- // More than 24 hours interval - use day and time format
126
- if (interval > 24 * 60 * 60 * 1000) {
127
- return (
128
- <>
129
- <FormattedDateTime format="chart-date" value={date} />{' '}
130
- <FormattedDateTime format="time" value={date} />
131
- </>
132
- );
133
- } else if (interval === 24 * 60 * 60 * 1000) {
134
- // Daily interval - use day format
135
- return <FormattedDateTime format="chart-date" value={date} />;
136
- } else if (interval >= 60 * 1000) {
137
- //Hourly and minute intervals - use minute format
138
- return <FormattedDateTime format="time" value={date} />;
119
+ duration: number,
120
+ ): 'time' | 'day-month-abbreviated' | 'chart-long-term-date' => {
121
+ if (duration <= 24 * 60 * 60 * 1000) {
122
+ return 'time';
123
+ } else if (duration <= 7 * 24 * 60 * 60 * 1000) {
124
+ return 'day-month-abbreviated';
139
125
  } else {
140
- // minute interval or less - use full timestamp
141
- return timestamp;
126
+ return 'chart-long-term-date';
142
127
  }
143
128
  };
144
129
 
@@ -155,10 +140,15 @@ export const CustomTick = ({
155
140
  width / visibleTicksCount - CHART_CONSTANTS.TICK_WIDTH_OFFSET;
156
141
  const centerX = x - tickWidth / 2;
157
142
 
143
+ const duration =
144
+ type.type === 'time'
145
+ ? type.timeRange.endDate.getTime() - type.timeRange.startDate.getTime()
146
+ : 0;
147
+
158
148
  return (
159
149
  <foreignObject
160
150
  x={centerX}
161
- y={y}
151
+ y={y - 8}
162
152
  width={tickWidth}
163
153
  color={theme.textSecondary}
164
154
  overflow="visible"
@@ -167,9 +157,14 @@ export const CustomTick = ({
167
157
  color="textSecondary"
168
158
  text={
169
159
  <Text variant="Smaller">
170
- {type.type === 'time'
171
- ? formatDate(payload.value, type.timeRange.interval)
172
- : String(payload.value)}
160
+ {type.type === 'time' ? (
161
+ <FormattedDateTime
162
+ format={formatDate(duration)}
163
+ value={new Date(payload.value)}
164
+ />
165
+ ) : (
166
+ String(payload.value)
167
+ )}
173
168
  </Text>
174
169
  }
175
170
  centered
@@ -185,7 +180,7 @@ export const CustomTick = ({
185
180
  );
186
181
  };
187
182
 
188
- const StyledResponsiveContainer = styled(ResponsiveContainer)`
183
+ export const StyledResponsiveContainer = styled(ResponsiveContainer)`
189
184
  // Avoid tooltip over constrained text to be cut off
190
185
  & .recharts-surface {
191
186
  overflow: visible;
@@ -304,7 +299,7 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
304
299
  );
305
300
 
306
301
  return (
307
- <Stack direction="vertical" gap="r8">
302
+ <Stack direction="vertical">
308
303
  <ChartHeader
309
304
  title={title}
310
305
  secondaryTitle={secondaryTitle}
@@ -332,9 +327,13 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
332
327
  barCategoryGap={type.type === 'category' ? type.gap : undefined}
333
328
  >
334
329
  <CartesianGrid
335
- vertical={false}
336
- horizontal={false}
337
- fill={theme.backgroundLevel1}
330
+ vertical={true}
331
+ horizontal={true}
332
+ verticalPoints={[0]}
333
+ horizontalPoints={[0]}
334
+ stroke={theme.border}
335
+ fill={theme.backgroundLevel4}
336
+ strokeWidth={1}
338
337
  />
339
338
  {rechartsBars.map((bar) => {
340
339
  const { fill, dataKey, stackId } = bar;
@@ -354,29 +353,21 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
354
353
 
355
354
  <YAxis
356
355
  tickCount={1}
356
+ interval={0}
357
357
  unit={` ${unitLabel}`}
358
358
  domain={[0, roundReferenceValue]}
359
359
  tickFormatter={
360
360
  (value) =>
361
361
  new Intl.NumberFormat('fr-FR').format(value.toFixed(0)) // Add a space as thousand separator
362
362
  }
363
- axisLine={false}
363
+ axisLine={{ stroke: theme.border }}
364
364
  tick={{
365
365
  fill: theme.textSecondary,
366
366
  fontSize: fontSize.smaller,
367
367
  }}
368
- tickLine={false}
369
- label={{
370
- fill: theme.textSecondary,
371
- }}
372
368
  orientation="right"
373
369
  />
374
370
 
375
- <ReferenceLine
376
- y={roundReferenceValue}
377
- fill={theme.border}
378
- strokeWidth={0.5} // Reduce stroke width to make it less visible
379
- />
380
371
  <XAxis
381
372
  dataKey="category"
382
373
  tick={(props) => <CustomTick {...props} type={type} />}
@@ -384,10 +375,10 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
384
375
  interval={0}
385
376
  allowDataOverflow={true}
386
377
  tickLine={{
387
- stroke: theme.textSecondary,
378
+ stroke: theme.border,
388
379
  }}
389
380
  axisLine={{
390
- stroke: theme.textSecondary,
381
+ stroke: theme.border,
391
382
  }}
392
383
  />
393
384
 
@@ -30,6 +30,7 @@ describe('ChartTooltip', () => {
30
30
  longDate: () => screen.queryByText(/01 July 2024/),
31
31
  date: () => screen.queryByText(/\b01 Jul\b/),
32
32
  time: () => screen.queryByText(/00:00:00/),
33
+ dateTime: () => screen.queryByText(/01 Jul 00:00:00/),
33
34
  };
34
35
  it('should render the BarchartTooltip component', () => {
35
36
  render(
@@ -89,9 +90,8 @@ describe('ChartTooltip', () => {
89
90
  expect(selectors.successValue()).toBeInTheDocument();
90
91
  expect(selectors.failed()).toBeInTheDocument();
91
92
  expect(selectors.failedValue()).toBeInTheDocument();
92
- expect(selectors.date()).not.toBeInTheDocument();
93
- expect(selectors.longDate()).toBeInTheDocument();
94
- expect(selectors.time()).not.toBeInTheDocument();
93
+
94
+ expect(selectors.dateTime()).toBeInTheDocument();
95
95
  });
96
96
  it('should render time tooltip when type is time and interval is one hour', () => {
97
97
  const label = date;
@@ -1,19 +1,19 @@
1
+ import { TooltipContentProps } from 'recharts';
2
+ import { LegendShape } from '../chartlegend/ChartLegend';
3
+ import {
4
+ ChartTooltipContainer,
5
+ ChartTooltipHeader,
6
+ ChartTooltipItem,
7
+ ChartTooltipItemsContainer,
8
+ TooltipHeader,
9
+ } from '../charttooltip/ChartTooltip';
1
10
  import {
2
11
  BarchartBars,
3
12
  BarchartTooltipFn,
4
13
  CategoryType,
5
14
  TimeType,
6
15
  } from './Barchart.component';
7
- import { FormattedDateTime } from '../date/FormattedDateTime';
8
- import { TooltipContentProps } from 'recharts';
9
16
  import { getCurrentPoint } from './utils';
10
- import {
11
- ChartTooltipContainer,
12
- ChartTooltipItem,
13
- ChartTooltipHeader,
14
- ChartTooltipItemsContainer,
15
- } from '../charttooltip/ChartTooltip';
16
- import { LegendShape } from '../chartlegend/ChartLegend';
17
17
 
18
18
  export const BarchartTooltip = <T extends BarchartBars>({
19
19
  type,
@@ -40,19 +40,15 @@ export const BarchartTooltip = <T extends BarchartBars>({
40
40
  if (tooltip) {
41
41
  return tooltip(currentPoint);
42
42
  }
43
-
43
+ const duration =
44
+ type.type === 'time'
45
+ ? type.timeRange.startDate.getTime() - type.timeRange.endDate.getTime()
46
+ : 0;
44
47
  return (
45
48
  <ChartTooltipContainer>
46
49
  <ChartTooltipHeader>
47
50
  {type.type === 'time' ? (
48
- <FormattedDateTime
49
- format={
50
- type.timeRange.interval < 24 * 60 * 60 * 1000
51
- ? 'day-month-abbreviated-hour-minute-second'
52
- : 'long-date-without-weekday'
53
- }
54
- value={new Date(currentPoint.category)}
55
- />
51
+ <TooltipHeader duration={duration} value={currentPoint.category} />
56
52
  ) : (
57
53
  currentPoint.category
58
54
  )}
@@ -1,8 +1,4 @@
1
- import {
2
- BarchartProps,
3
- BarchartBars,
4
- BarchartTooltipFn,
5
- } from './Barchart.component';
1
+ import { BarchartProps, BarchartBars } from './Barchart.component';
6
2
  import { TooltipContentProps } from 'recharts';
7
3
  import { chartColors, ChartColors } from '../../style/theme';
8
4
  import { useChartLegend } from '../chartlegend/ChartLegendWrapper';
@@ -133,7 +133,7 @@ export const ChartLegendWrapper = ({
133
133
  );
134
134
 
135
135
  const listResources = useCallback(() => {
136
- return Object.keys(internalColorSet);
136
+ return Object.keys(internalColorSet).sort();
137
137
  }, [internalColorSet]);
138
138
 
139
139
  const chartLegendState = useMemo(
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import styled from 'styled-components';
3
3
  import { spacing } from '../../spacing';
4
4
  import { fontSize, fontWeight } from '../../style/theme';
5
+ import { FormattedDateTime } from '../date/FormattedDateTime';
5
6
 
6
7
  export const ChartTooltipContainer = styled.div`
7
8
  border: 1px solid ${({ theme }) => theme.border};
@@ -81,3 +82,42 @@ export const ChartTooltipItemsContainer = styled.div`
81
82
  gap: ${spacing.r8};
82
83
  width: 100%;
83
84
  `;
85
+
86
+ export const ChartTooltipSeparator = styled.div`
87
+ height: 1px;
88
+ background-color: ${({ theme }) => theme.border};
89
+ margin: ${spacing.r4} 0;
90
+ width: 100%;
91
+ `;
92
+
93
+ export type TooltipDateFormat =
94
+ | 'day-month-abbreviated-year-hour-minute'
95
+ | 'day-month-abbreviated-hour-minute-second'
96
+ | 'day-month-abbreviated-hour-minute';
97
+
98
+ const getTooltipDateFormat: (duration: number) => TooltipDateFormat = (
99
+ duration: number,
100
+ ) => {
101
+ if (duration <= 60 * 60 * 1000) {
102
+ return 'day-month-abbreviated-hour-minute-second';
103
+ } else if (duration <= 7 * 24 * 60 * 60 * 1000) {
104
+ return 'day-month-abbreviated-hour-minute';
105
+ } else {
106
+ return 'day-month-abbreviated-year-hour-minute';
107
+ }
108
+ };
109
+
110
+ export const TooltipHeader = ({
111
+ duration,
112
+ value,
113
+ }: {
114
+ duration: number;
115
+ value: string | number;
116
+ }) => {
117
+ const timeFormat = getTooltipDateFormat(duration);
118
+ return (
119
+ <ChartTooltipHeader>
120
+ <FormattedDateTime format={timeFormat} value={new Date(value)} />
121
+ </ChartTooltipHeader>
122
+ );
123
+ };