@centreon/ui 24.6.2 → 24.6.4

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 (54) hide show
  1. package/package.json +1 -1
  2. package/src/Graph/BarChart/BarChart.cypress.spec.tsx +233 -0
  3. package/src/Graph/BarChart/BarChart.stories.tsx +213 -0
  4. package/src/Graph/BarChart/BarChart.tsx +101 -0
  5. package/src/Graph/BarChart/BarGroup.tsx +246 -0
  6. package/src/Graph/BarChart/BarStack.tsx +126 -0
  7. package/src/Graph/BarChart/ResponsiveBarChart.tsx +263 -0
  8. package/src/Graph/BarChart/SingleBar.tsx +62 -0
  9. package/src/Graph/BarChart/Tooltip/BarChartTooltip.tsx +122 -0
  10. package/src/Graph/BarChart/Tooltip/useBarChartTooltipStyles.ts +28 -0
  11. package/src/Graph/BarChart/atoms.ts +5 -0
  12. package/src/Graph/BarChart/models.ts +21 -0
  13. package/src/Graph/BarChart/useBarChartStyles.tsx +5 -0
  14. package/src/Graph/BarChart/useBarStack.ts +114 -0
  15. package/src/Graph/BarChart/useSingleBar.ts +199 -0
  16. package/src/Graph/Gauge/Gauge.cypress.spec.tsx +1 -1
  17. package/src/Graph/Gauge/Gauge.stories.tsx +1 -1
  18. package/src/Graph/LineChart/LineChart.cypress.spec.tsx +4 -4
  19. package/src/Graph/LineChart/LineChart.styles.ts +0 -5
  20. package/src/Graph/LineChart/LineChart.tsx +118 -122
  21. package/src/Graph/LineChart/index.stories.tsx +12 -12
  22. package/src/Graph/SingleBar/SingleBar.cypress.spec.tsx +1 -1
  23. package/src/Graph/SingleBar/SingleBar.stories.tsx +1 -1
  24. package/src/Graph/Text/Text.cypress.spec.tsx +1 -1
  25. package/src/Graph/Text/Text.stories.tsx +1 -1
  26. package/src/Graph/common/Axes/index.tsx +40 -13
  27. package/src/Graph/common/BaseChart/BaseChart.tsx +25 -6
  28. package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +15 -4
  29. package/src/Graph/{LineChart → common/BaseChart}/Header/index.tsx +3 -3
  30. package/src/Graph/common/BaseChart/Header/models.ts +4 -0
  31. package/src/Graph/common/BaseChart/Header/useHeaderStyles.ts +9 -0
  32. package/src/Graph/common/BaseChart/useBaseChartStyles.ts +6 -0
  33. package/src/Graph/{LineChart/BasicComponents → common/Thresholds}/ThresholdLine.tsx +20 -10
  34. package/src/Graph/{LineChart/BasicComponents → common/Thresholds}/Thresholds.tsx +8 -4
  35. package/src/Graph/common/timeSeries/index.ts +33 -11
  36. package/src/Graph/common/timeSeries/models.ts +1 -0
  37. package/src/Graph/common/useTooltipStyles.ts +1 -0
  38. package/src/Graph/mockedData/pingService.json +203 -0
  39. package/src/Graph/mockedData/pingServiceMixedStacked.json +203 -0
  40. package/src/Graph/mockedData/pingServiceStacked.json +203 -0
  41. /package/src/Graph/{LineChart/mockedData → mockedData}/annotationData.json +0 -0
  42. /package/src/Graph/{LineChart/mockedData → mockedData}/curvesWithSameColor.json +0 -0
  43. /package/src/Graph/{LineChart/mockedData → mockedData}/exclusionPeriodFirstPeriod.json +0 -0
  44. /package/src/Graph/{LineChart/mockedData → mockedData}/exclusionPeriodSecondPeriod.json +0 -0
  45. /package/src/Graph/{LineChart/mockedData → mockedData}/exclusionPeriodThirdPeriod.json +0 -0
  46. /package/src/Graph/{LineChart/mockedData → mockedData}/lastDay.json +0 -0
  47. /package/src/Graph/{LineChart/mockedData → mockedData}/lastDayAreaStack.json +0 -0
  48. /package/src/Graph/{LineChart/mockedData → mockedData}/lastDayForward.json +0 -0
  49. /package/src/Graph/{LineChart/mockedData → mockedData}/lastDayThreshold.json +0 -0
  50. /package/src/Graph/{LineChart/mockedData → mockedData}/lastDayWithIncompleteValues.json +0 -0
  51. /package/src/Graph/{LineChart/mockedData → mockedData}/lastDayWithNullValues.json +0 -0
  52. /package/src/Graph/{LineChart/mockedData → mockedData}/lastMonth.json +0 -0
  53. /package/src/Graph/{LineChart/mockedData → mockedData}/lastWeek.json +0 -0
  54. /package/src/Graph/{LineChart/mockedData → mockedData}/zoomPreview.json +0 -0
@@ -0,0 +1,246 @@
1
+ import { memo, useMemo } from 'react';
2
+
3
+ import { BarGroupHorizontal, BarGroup as VisxBarGroup } from '@visx/shape';
4
+ import { difference, equals, isEmpty, keys, omit, pick } from 'ramda';
5
+ import { scaleBand, scaleOrdinal } from '@visx/scale';
6
+ import { Group } from '@visx/group';
7
+
8
+ import { useDeepMemo } from '../../utils';
9
+ import { Line, TimeValue } from '../common/timeSeries/models';
10
+ import {
11
+ getSortedStackedLines,
12
+ getTime,
13
+ getTimeSeriesForLines
14
+ } from '../common/timeSeries';
15
+
16
+ import SingleBar from './SingleBar';
17
+ import BarStack from './BarStack';
18
+ import { BarStyle } from './models';
19
+
20
+ interface Props {
21
+ barStyle: BarStyle;
22
+ isCenteredZero?: boolean;
23
+ isTooltipHidden: boolean;
24
+ leftScale;
25
+ lines: Array<Line>;
26
+ orientation: 'horizontal' | 'vertical';
27
+ rightScale;
28
+ secondUnit?: string;
29
+ size: number;
30
+ timeSeries: Array<TimeValue>;
31
+ xScale;
32
+ }
33
+
34
+ const BarGroup = ({
35
+ orientation,
36
+ timeSeries,
37
+ size,
38
+ lines,
39
+ xScale,
40
+ leftScale,
41
+ rightScale,
42
+ secondUnit,
43
+ isCenteredZero,
44
+ isTooltipHidden,
45
+ barStyle
46
+ }: Props): JSX.Element => {
47
+ const isHorizontal = equals(orientation, 'horizontal');
48
+
49
+ const BarComponent = useMemo(
50
+ () => (isHorizontal ? VisxBarGroup : BarGroupHorizontal),
51
+ [isHorizontal]
52
+ );
53
+
54
+ const stackedLines = getSortedStackedLines(lines);
55
+ const notStackedLines = difference(lines, stackedLines);
56
+
57
+ const stackLinesRight = stackedLines.filter(({ unit }) =>
58
+ equals(unit, secondUnit)
59
+ );
60
+ const stackLinesLeft = stackedLines.filter(
61
+ ({ unit }) => !equals(unit, secondUnit)
62
+ );
63
+ const hasStackedLinesRight = !isEmpty(stackLinesRight)
64
+ ? { stackedRight: null }
65
+ : {};
66
+ const hasStackedLinesLeft = !isEmpty(stackLinesLeft)
67
+ ? { stackedLeft: null }
68
+ : {};
69
+
70
+ const stackedTimeSeriesRight = getTimeSeriesForLines({
71
+ lines: stackLinesRight,
72
+ timeSeries
73
+ });
74
+ const stackedTimeSeriesLeft = getTimeSeriesForLines({
75
+ lines: stackLinesLeft,
76
+ timeSeries
77
+ });
78
+ const notStackedTimeSeries = getTimeSeriesForLines({
79
+ lines: notStackedLines,
80
+ timeSeries
81
+ });
82
+
83
+ const normalizedTimeSeries = notStackedTimeSeries.map((timeSerie) => ({
84
+ ...timeSerie,
85
+ ...hasStackedLinesRight,
86
+ ...hasStackedLinesLeft
87
+ }));
88
+
89
+ const lineKeys = useDeepMemo({
90
+ deps: [normalizedTimeSeries],
91
+ variable: keys(omit(['timeTick'], normalizedTimeSeries[0]))
92
+ });
93
+ const colors = useDeepMemo({
94
+ deps: [lineKeys, lines],
95
+ variable: lineKeys.map((key) => {
96
+ const metric = lines.find(({ metric_id }) =>
97
+ equals(metric_id, Number(key))
98
+ );
99
+
100
+ return metric?.lineColor || '';
101
+ })
102
+ });
103
+
104
+ const colorScale = useMemo(
105
+ () =>
106
+ scaleOrdinal<number, string>({
107
+ domain: lineKeys,
108
+ range: colors
109
+ }),
110
+ [...lineKeys, ...colors]
111
+ );
112
+ const metricScale = useMemo(
113
+ () =>
114
+ scaleBand({
115
+ domain: lineKeys,
116
+ padding: 0.1,
117
+ range: [0, xScale.bandwidth()]
118
+ }),
119
+ [...lineKeys, xScale.bandwidth()]
120
+ );
121
+
122
+ const barComponentBaseProps = useMemo(
123
+ () =>
124
+ isHorizontal
125
+ ? {
126
+ x0: getTime,
127
+ x0Scale: xScale,
128
+ x1Scale: metricScale,
129
+ yScale: leftScale
130
+ }
131
+ : {
132
+ xScale: leftScale,
133
+ y0: getTime,
134
+ y0Scale: xScale,
135
+ y1Scale: metricScale
136
+ },
137
+ [isHorizontal, leftScale, rightScale, xScale, metricScale]
138
+ );
139
+
140
+ return (
141
+ <BarComponent<TimeValue>
142
+ color={colorScale}
143
+ data={normalizedTimeSeries}
144
+ height={size}
145
+ keys={lineKeys}
146
+ {...barComponentBaseProps}
147
+ >
148
+ {(barGroups) =>
149
+ barGroups.map((barGroup) => (
150
+ <Group
151
+ key={`bar-group-${barGroup.index}-${barGroup.x0}`}
152
+ left={barGroup.x0}
153
+ top={barGroup.y0}
154
+ >
155
+ {barGroup.bars.map((bar) => (
156
+ <>
157
+ <SingleBar
158
+ bar={bar}
159
+ barStyle={barStyle}
160
+ isCenteredZero={isCenteredZero}
161
+ isHorizontal={isHorizontal}
162
+ isTooltipHidden={isTooltipHidden}
163
+ key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
164
+ leftScale={leftScale}
165
+ lines={lines}
166
+ rightScale={rightScale}
167
+ secondUnit={secondUnit}
168
+ size={size}
169
+ />
170
+ {equals(bar.key, 'stackedRight') && (
171
+ <BarStack
172
+ barIndex={barGroup.index}
173
+ barPadding={isHorizontal ? bar.x : bar.y}
174
+ barWidth={isHorizontal ? bar.width : bar.height}
175
+ isHorizontal={isHorizontal}
176
+ isTooltipHidden={isTooltipHidden}
177
+ lines={stackLinesRight}
178
+ timeSeries={stackedTimeSeriesRight}
179
+ yScale={rightScale}
180
+ />
181
+ )}
182
+ {equals(bar.key, 'stackedLeft') && (
183
+ <BarStack
184
+ barIndex={barGroup.index}
185
+ barPadding={isHorizontal ? bar.x : bar.y}
186
+ barWidth={isHorizontal ? bar.width : bar.height}
187
+ isHorizontal={isHorizontal}
188
+ isTooltipHidden={isTooltipHidden}
189
+ lines={stackLinesLeft}
190
+ timeSeries={stackedTimeSeriesLeft}
191
+ yScale={leftScale}
192
+ />
193
+ )}
194
+ </>
195
+ ))}
196
+ </Group>
197
+ ))
198
+ }
199
+ </BarComponent>
200
+ );
201
+ };
202
+
203
+ const propsToMemoize = [
204
+ 'orientation',
205
+ 'timeSeries',
206
+ 'size',
207
+ 'lines',
208
+ 'secondUnit',
209
+ 'isCenteredZero',
210
+ 'barStyle'
211
+ ];
212
+
213
+ export default memo(BarGroup, (prevProps, nextProps) => {
214
+ const prevLeftScale = [
215
+ ...prevProps.leftScale.domain(),
216
+ ...prevProps.leftScale.range()
217
+ ];
218
+ const prevRightScale = [
219
+ ...prevProps.rightScale.domain(),
220
+ ...prevProps.rightScale.range()
221
+ ];
222
+ const prevXScale = [
223
+ ...prevProps.xScale.domain(),
224
+ ...prevProps.xScale.range()
225
+ ];
226
+
227
+ const nextLeftScale = [
228
+ ...nextProps.leftScale.domain(),
229
+ ...nextProps.leftScale.range()
230
+ ];
231
+ const nextRightScale = [
232
+ ...nextProps.rightScale.domain(),
233
+ ...nextProps.rightScale.range()
234
+ ];
235
+ const nextXScale = [
236
+ ...nextProps.xScale.domain(),
237
+ ...nextProps.xScale.range()
238
+ ];
239
+
240
+ return (
241
+ equals(pick(propsToMemoize, prevProps), pick(propsToMemoize, nextProps)) &&
242
+ equals(prevLeftScale, nextLeftScale) &&
243
+ equals(prevRightScale, nextRightScale) &&
244
+ equals(prevXScale, nextXScale)
245
+ );
246
+ });
@@ -0,0 +1,126 @@
1
+ import { memo } from 'react';
2
+
3
+ import { scaleBand } from '@visx/scale';
4
+ import { equals, gt, pick } from 'ramda';
5
+
6
+ import { useBarStack, UseBarStackProps } from './useBarStack';
7
+
8
+ const xScale = scaleBand<number>({
9
+ domain: [0, 0],
10
+ padding: 0,
11
+ range: [0, 0]
12
+ });
13
+
14
+ interface Props extends Omit<UseBarStackProps, 'xScale'> {
15
+ barIndex: number;
16
+ barPadding: number;
17
+ barWidth: number;
18
+ isTooltipHidden: boolean;
19
+ }
20
+
21
+ const getPadding = ({ padding, size, isNegativeValue }): number => {
22
+ if (!isNegativeValue) {
23
+ return padding;
24
+ }
25
+
26
+ return padding + size;
27
+ };
28
+
29
+ const BarStack = ({
30
+ timeSeries,
31
+ isHorizontal,
32
+ yScale,
33
+ lines,
34
+ barWidth,
35
+ barPadding,
36
+ barIndex,
37
+ isTooltipHidden
38
+ }: Props): JSX.Element => {
39
+ const {
40
+ BarStackComponent,
41
+ commonBarStackProps,
42
+ colorScale,
43
+ lineKeys,
44
+ exitBar,
45
+ hoverBar
46
+ } = useBarStack({ isHorizontal, lines, timeSeries, xScale, yScale });
47
+
48
+ return (
49
+ <BarStackComponent
50
+ color={colorScale}
51
+ data={[timeSeries[barIndex]]}
52
+ keys={lineKeys}
53
+ {...commonBarStackProps}
54
+ >
55
+ {(barStacks) => {
56
+ return barStacks.map((barStack) =>
57
+ barStack.bars.map((bar) => {
58
+ const isNegativeValue = gt(0, bar.bar[1]);
59
+
60
+ return (
61
+ <rect
62
+ data-testid={`stacked-bar-${bar.key}-${bar.index}-${bar.bar[1]}`}
63
+ fill={bar.color}
64
+ height={isHorizontal ? Math.abs(bar.height) : barWidth}
65
+ key={`bar-stack-${barStack.index}-${bar.index}`}
66
+ width={isHorizontal ? barWidth : Math.abs(bar.width)}
67
+ x={
68
+ isHorizontal
69
+ ? barPadding
70
+ : getPadding({
71
+ isNegativeValue,
72
+ padding: bar.x,
73
+ size: bar.width
74
+ })
75
+ }
76
+ y={
77
+ isHorizontal
78
+ ? getPadding({
79
+ isNegativeValue,
80
+ padding: bar.y,
81
+ size: bar.height
82
+ })
83
+ : barPadding
84
+ }
85
+ onMouseEnter={
86
+ isTooltipHidden
87
+ ? undefined
88
+ : hoverBar({
89
+ barIndex,
90
+ highlightedMetric: Number(bar.key)
91
+ })
92
+ }
93
+ onMouseLeave={isTooltipHidden ? undefined : exitBar}
94
+ />
95
+ );
96
+ })
97
+ );
98
+ }}
99
+ </BarStackComponent>
100
+ );
101
+ };
102
+
103
+ const propsToMemoize = [
104
+ 'timeSeries',
105
+ 'isHorizontal',
106
+ 'barWidth',
107
+ 'lines',
108
+ 'barPadding',
109
+ 'barIndex',
110
+ 'isTooltipHidden'
111
+ ];
112
+
113
+ export default memo(BarStack, (prevProps, nextProps) => {
114
+ const prevYScaleDomain = prevProps.yScale.domain();
115
+ const prevYScaleRange = prevProps.yScale.range();
116
+ const nextYScaleDomain = nextProps.yScale.domain();
117
+ const nextYScaleRange = nextProps.yScale.range();
118
+
119
+ return (
120
+ equals(
121
+ [...prevYScaleDomain, ...prevYScaleRange],
122
+ [...nextYScaleDomain, ...nextYScaleRange]
123
+ ) &&
124
+ equals(pick(propsToMemoize, prevProps), pick(propsToMemoize, nextProps))
125
+ );
126
+ });
@@ -0,0 +1,263 @@
1
+ import { MutableRefObject, useMemo, useRef, useState } from 'react';
2
+
3
+ import { equals, flatten, has, isNil, pluck } from 'ramda';
4
+ import { useAtom } from 'jotai';
5
+
6
+ import { Skeleton } from '@mui/material';
7
+
8
+ import { Data, LineChartProps } from '../LineChart/models';
9
+ import { Thresholds as ThresholdsModel } from '../common/models';
10
+ import { useIntersection } from '../LineChart/useLineChartIntersection';
11
+ import { Line } from '../common/timeSeries/models';
12
+ import { useComputeBaseChartDimensions } from '../common/BaseChart/useComputeBaseChartDimensions';
13
+ import {
14
+ getLeftScale,
15
+ getRightScale,
16
+ getUnits,
17
+ getXScaleBand
18
+ } from '../common/timeSeries';
19
+ import BaseChart from '../common/BaseChart/BaseChart';
20
+ import ChartSvgWrapper from '../common/BaseChart/ChartSvgWrapper';
21
+ import { useTooltipStyles } from '../common/useTooltipStyles';
22
+ import { margin } from '../LineChart/common';
23
+ import { Tooltip } from '../../components';
24
+ import Thresholds from '../common/Thresholds/Thresholds';
25
+
26
+ import BarGroup from './BarGroup';
27
+ import { tooltipDataAtom } from './atoms';
28
+ import BarChartTooltip from './Tooltip/BarChartTooltip';
29
+ import { BarStyle } from './models';
30
+
31
+ interface Props
32
+ extends Pick<LineChartProps, 'tooltip' | 'legend' | 'axis' | 'header'> {
33
+ barStyle: BarStyle;
34
+ graphData: Data;
35
+ graphRef: MutableRefObject<HTMLDivElement | null>;
36
+ height: number;
37
+ limitLegend?: false | number;
38
+ orientation: 'vertical' | 'horizontal';
39
+ thresholdUnit?: string;
40
+ thresholds?: ThresholdsModel;
41
+ width: number;
42
+ }
43
+
44
+ const ResponsiveBarChart = ({
45
+ graphRef,
46
+ graphData,
47
+ legend,
48
+ height,
49
+ width,
50
+ axis,
51
+ thresholdUnit,
52
+ thresholds,
53
+ header,
54
+ limitLegend,
55
+ orientation,
56
+ tooltip,
57
+ barStyle
58
+ }: Props): JSX.Element => {
59
+ const { title, timeSeries, baseAxis, lines } = graphData;
60
+
61
+ const { classes, cx } = useTooltipStyles();
62
+
63
+ const [linesGraph, setLinesGraph] = useState<Array<Line>>(lines);
64
+ const graphSvgRef = useRef<SVGSVGElement | null>(null);
65
+
66
+ const [tooltipData, setTooltipData] = useAtom(tooltipDataAtom);
67
+
68
+ const { isInViewport } = useIntersection({ element: graphRef?.current });
69
+
70
+ const [, secondUnit] = getUnits(linesGraph);
71
+
72
+ const { legendRef, graphWidth, graphHeight } = useComputeBaseChartDimensions({
73
+ hasSecondUnit: Boolean(secondUnit),
74
+ height,
75
+ legendDisplay: legend?.display,
76
+ legendPlacement: legend?.placement,
77
+ width
78
+ });
79
+
80
+ const thresholdValues = flatten([
81
+ pluck('value', thresholds?.warning || []),
82
+ pluck('value', thresholds?.critical || [])
83
+ ]);
84
+
85
+ const isHorizontal = equals(orientation, 'horizontal');
86
+
87
+ const xScale = useMemo(
88
+ () =>
89
+ getXScaleBand({
90
+ dataTime: timeSeries,
91
+ valueWidth: isHorizontal ? graphWidth : graphHeight - 30
92
+ }),
93
+ [timeSeries, graphWidth, isHorizontal, graphHeight]
94
+ );
95
+
96
+ const leftScale = useMemo(
97
+ () =>
98
+ getLeftScale({
99
+ dataLines: linesGraph,
100
+ dataTimeSeries: timeSeries,
101
+ isCenteredZero: axis?.isCenteredZero,
102
+ isHorizontal,
103
+ scale: axis?.scale,
104
+ scaleLogarithmicBase: axis?.scaleLogarithmicBase,
105
+ thresholdUnit,
106
+ thresholds: (thresholds?.enabled && thresholdValues) || [],
107
+ valueGraphHeight: (isHorizontal ? graphHeight : graphWidth) - 35
108
+ }),
109
+ [
110
+ linesGraph,
111
+ timeSeries,
112
+ graphHeight,
113
+ thresholdValues,
114
+ axis?.isCenteredZero,
115
+ axis?.scale,
116
+ axis?.scaleLogarithmicBase,
117
+ graphWidth,
118
+ isHorizontal
119
+ ]
120
+ );
121
+
122
+ const rightScale = useMemo(
123
+ () =>
124
+ getRightScale({
125
+ dataLines: linesGraph,
126
+ dataTimeSeries: timeSeries,
127
+ isCenteredZero: axis?.isCenteredZero,
128
+ isHorizontal,
129
+ scale: axis?.scale,
130
+ scaleLogarithmicBase: axis?.scaleLogarithmicBase,
131
+ thresholdUnit,
132
+ thresholds: (thresholds?.enabled && thresholdValues) || [],
133
+ valueGraphHeight: (isHorizontal ? graphHeight : graphWidth) - 35
134
+ }),
135
+ [
136
+ timeSeries,
137
+ linesGraph,
138
+ graphHeight,
139
+ axis?.isCenteredZero,
140
+ axis?.scale,
141
+ axis?.scaleLogarithmicBase,
142
+ graphWidth,
143
+ isHorizontal
144
+ ]
145
+ );
146
+
147
+ const displayLegend = legend?.display ?? true;
148
+
149
+ const displayedLines = useMemo(
150
+ () => linesGraph.filter(({ display }) => display),
151
+ [linesGraph]
152
+ );
153
+
154
+ const showGridLines = useMemo(
155
+ () => isNil(axis?.showGridLines) || axis?.showGridLines,
156
+ [axis?.showGridLines]
157
+ );
158
+
159
+ if (!isInViewport) {
160
+ return (
161
+ <Skeleton
162
+ height={graphSvgRef?.current?.clientHeight ?? graphHeight}
163
+ variant="rectangular"
164
+ width="100%"
165
+ />
166
+ );
167
+ }
168
+
169
+ const isTooltipHidden = equals(tooltip?.mode, 'hidden');
170
+
171
+ return (
172
+ <BaseChart
173
+ base={baseAxis}
174
+ graphWidth={graphWidth}
175
+ header={header}
176
+ height={height}
177
+ isHorizontal={isHorizontal}
178
+ legend={{
179
+ displayLegend,
180
+ mode: legend?.mode,
181
+ placement: legend?.placement,
182
+ renderExtraComponent: legend?.renderExtraComponent
183
+ }}
184
+ legendRef={legendRef}
185
+ limitLegend={limitLegend}
186
+ lines={linesGraph}
187
+ setLines={setLinesGraph}
188
+ title={title}
189
+ >
190
+ <Tooltip
191
+ classes={{
192
+ tooltip: cx(
193
+ classes.tooltip,
194
+ has('data', tooltipData) && classes.tooltipDisablePadding
195
+ )
196
+ }}
197
+ label={
198
+ <BarChartTooltip
199
+ base={baseAxis}
200
+ mode={tooltip?.mode}
201
+ sortOrder={tooltip?.sortOrder}
202
+ timeSeries={timeSeries}
203
+ />
204
+ }
205
+ open={!equals(tooltip?.mode, 'hidden') && Boolean(tooltipData)}
206
+ placement="top"
207
+ >
208
+ <div className={classes.tooltipChildren}>
209
+ <ChartSvgWrapper
210
+ axis={axis}
211
+ base={baseAxis}
212
+ displayedLines={displayedLines}
213
+ graphHeight={graphHeight}
214
+ graphWidth={graphWidth - (isHorizontal ? 0 : margin.left - 15)}
215
+ gridLinesType={axis?.gridLinesType}
216
+ leftScale={leftScale}
217
+ orientation={orientation}
218
+ rightScale={rightScale}
219
+ showGridLines={showGridLines}
220
+ svgRef={graphSvgRef}
221
+ timeSeries={timeSeries}
222
+ xScale={xScale}
223
+ >
224
+ <>
225
+ <BarGroup
226
+ barStyle={barStyle}
227
+ isCenteredZero={axis?.isCenteredZero}
228
+ isTooltipHidden={isTooltipHidden}
229
+ leftScale={leftScale}
230
+ lines={displayedLines}
231
+ orientation={orientation}
232
+ rightScale={rightScale}
233
+ secondUnit={secondUnit}
234
+ size={isHorizontal ? graphHeight - margin.top - 5 : graphWidth}
235
+ timeSeries={timeSeries}
236
+ xScale={xScale}
237
+ />
238
+ {thresholds?.enabled && (
239
+ <Thresholds
240
+ displayedLines={displayedLines}
241
+ hideTooltip={() => setTooltipData(null)}
242
+ isHorizontal={isHorizontal}
243
+ leftScale={leftScale}
244
+ rightScale={rightScale}
245
+ showTooltip={({ tooltipData: thresholdLabel }) =>
246
+ setTooltipData({
247
+ thresholdLabel
248
+ })
249
+ }
250
+ thresholdUnit={thresholdUnit}
251
+ thresholds={thresholds as ThresholdsModel}
252
+ width={isHorizontal ? graphWidth : graphHeight - margin.top}
253
+ />
254
+ )}
255
+ </>
256
+ </ChartSvgWrapper>
257
+ </div>
258
+ </Tooltip>
259
+ </BaseChart>
260
+ );
261
+ };
262
+
263
+ export default ResponsiveBarChart;
@@ -0,0 +1,62 @@
1
+ import { memo } from 'react';
2
+
3
+ import { equals, pick } from 'ramda';
4
+
5
+ import { useSingleBar, UseSingleBarProps } from './useSingleBar';
6
+ import { BarStyle } from './models';
7
+
8
+ const SingleBar = ({
9
+ lines,
10
+ secondUnit,
11
+ bar,
12
+ leftScale,
13
+ rightScale,
14
+ size,
15
+ isCenteredZero,
16
+ isHorizontal,
17
+ isTooltipHidden,
18
+ barStyle
19
+ }: UseSingleBarProps & {
20
+ barStyle: BarStyle;
21
+ }): JSX.Element => {
22
+ const { barLength, barPadding, listeners } = useSingleBar({
23
+ bar,
24
+ isCenteredZero,
25
+ isHorizontal,
26
+ isTooltipHidden,
27
+ leftScale,
28
+ lines,
29
+ rightScale,
30
+ secondUnit,
31
+ size
32
+ });
33
+
34
+ return (
35
+ <rect
36
+ data-testid={`single-bar-${bar.key}-${bar.index}-${bar.value}`}
37
+ fill={bar.color}
38
+ height={isHorizontal ? barLength : bar.height}
39
+ opacity={barStyle.opacity}
40
+ rx={(isHorizontal ? bar.width : bar.height) * barStyle.radius}
41
+ width={isHorizontal ? bar.width : barLength}
42
+ x={isHorizontal ? bar.x : barPadding}
43
+ y={isHorizontal ? barPadding : bar.y}
44
+ {...listeners}
45
+ />
46
+ );
47
+ };
48
+
49
+ const propsToMemoize = [
50
+ 'bar',
51
+ 'lines',
52
+ 'secondUnit',
53
+ 'size',
54
+ 'isCenteredZero',
55
+ 'isHorizontal',
56
+ 'isTooltipHidden',
57
+ 'barStyle'
58
+ ];
59
+
60
+ export default memo(SingleBar, (prevProps, nextProps) =>
61
+ equals(pick(propsToMemoize, prevProps), pick(propsToMemoize, nextProps))
62
+ );