@centreon/ui 25.3.1 → 25.3.3

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 (41) hide show
  1. package/package.json +49 -46
  2. package/public/mockServiceWorker.js +1 -1
  3. package/src/Button/Save/index.tsx +17 -35
  4. package/src/Button/Save/useSave.tsx +89 -0
  5. package/src/Form/Inputs/LoadingSkeleton.tsx +1 -1
  6. package/src/Form/Inputs/Radio.tsx +7 -5
  7. package/src/Form/Inputs/Switch.tsx +4 -2
  8. package/src/Graph/BarChart/BarChart.cypress.spec.tsx +2 -2
  9. package/src/Graph/BarChart/BarChart.stories.tsx +39 -0
  10. package/src/Graph/BarChart/BarStack.tsx +8 -2
  11. package/src/Graph/BarChart/ResponsiveBarChart.tsx +10 -8
  12. package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +41 -24
  13. package/src/Graph/Chart/BasicComponents/Lines/index.tsx +22 -37
  14. package/src/Graph/Chart/Chart.cypress.spec.tsx +104 -31
  15. package/src/Graph/Chart/Chart.stories.tsx +24 -2
  16. package/src/Graph/Chart/Chart.tsx +23 -18
  17. package/src/Graph/Chart/index.tsx +2 -0
  18. package/src/Graph/Chart/models.ts +4 -3
  19. package/src/Graph/SingleBar/ThresholdLine.tsx +2 -2
  20. package/src/Graph/Tree/Tree.stories.tsx +4 -1
  21. package/src/Graph/common/Axes/index.tsx +1 -1
  22. package/src/Graph/common/BaseChart/AdditionalLine.tsx +37 -0
  23. package/src/Graph/common/BaseChart/BaseChart.tsx +5 -1
  24. package/src/Graph/common/BaseChart/Header/index.tsx +5 -7
  25. package/src/Graph/common/BaseChart/Header/useHeaderStyles.ts +5 -1
  26. package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +9 -2
  27. package/src/Graph/common/Thresholds/ThresholdLine.tsx +2 -2
  28. package/src/Graph/common/models.ts +7 -0
  29. package/src/Graph/common/timeSeries/index.ts +1 -1
  30. package/src/Graph/common/utils.ts +22 -1
  31. package/src/Graph/mockedData/lastDayWithNullValues.json +6 -40
  32. package/src/Graph/mockedData/pingService.json +3 -3
  33. package/src/InputField/Select/index.tsx +11 -9
  34. package/src/Listing/Listing.cypress.spec.tsx +9 -11
  35. package/src/RichTextEditor/RichTextEditor.tsx +1 -1
  36. package/src/api/useMutationQuery/useMutationQuery.cypress.spec.tsx +0 -18
  37. package/src/components/Button/Button.tsx +19 -15
  38. package/src/components/CollapsibleItem/CollapsibleItem.cypress.spec.tsx +8 -8
  39. package/src/components/CopyCommand/CopyCommand.cypress.spec.tsx +11 -10
  40. package/src/Button/Save/Content.tsx +0 -34
  41. package/src/Button/Save/StartIcon.tsx +0 -24
@@ -9,13 +9,13 @@ import {
9
9
  getYScale
10
10
  } from '../../../common/timeSeries';
11
11
  import type { Line, TimeValue } from '../../../common/timeSeries/models';
12
- import { getPointRadius } from '../../../common/utils';
12
+ import { getPointRadius, getStyle } from '../../../common/utils';
13
13
  import GuidingLines from '../../InteractiveComponents/AnchorPoint/GuidingLines';
14
14
  import RegularAnchorPoint, {
15
15
  getYAnchorPoint
16
16
  } from '../../InteractiveComponents/AnchorPoint/RegularAnchorPoint';
17
17
  import { displayArea } from '../../helpers/index';
18
- import type { DisplayAnchor, GlobalAreaLines } from '../../models';
18
+ import type { DisplayAnchor, GlobalAreaLines, LineStyle } from '../../models';
19
19
 
20
20
  import Point from './Point';
21
21
  import RegularLine from './RegularLines';
@@ -29,33 +29,24 @@ import {
29
29
  } from './Threshold/models';
30
30
 
31
31
  interface Props extends GlobalAreaLines {
32
- areaTransparency?: number;
33
- curve: 'linear' | 'step' | 'natural';
34
- dashLength?: number;
35
- dashOffset?: number;
36
32
  displayAnchor?: DisplayAnchor;
37
33
  displayedLines: Array<Line>;
38
- dotOffset?: number;
39
34
  graphSvgRef: MutableRefObject<SVGSVGElement | null>;
40
35
  height: number;
41
- lineWidth?: number;
42
36
  scale?: 'linear' | 'logarithmic';
43
37
  scaleLogarithmicBase?: number;
44
- showArea?: boolean;
45
- showPoints?: boolean;
46
38
  timeSeries: Array<TimeValue>;
47
39
  width: number;
48
40
  xScale: ScaleLinear<number, number>;
49
41
  yScalesPerUnit: Record<string, ScaleLinear<number, number>>;
42
+ lineStyle: LineStyle | Array<LineStyle>;
50
43
  }
51
44
 
52
45
  const Lines = ({
53
- areaTransparency,
54
46
  height,
55
47
  graphSvgRef,
56
48
  width,
57
49
  displayAnchor,
58
- curve,
59
50
  yScalesPerUnit,
60
51
  xScale,
61
52
  timeSeries,
@@ -63,14 +54,9 @@ const Lines = ({
63
54
  areaThresholdLines,
64
55
  areaStackedLines,
65
56
  areaRegularLines,
66
- showArea,
67
- showPoints,
68
- lineWidth,
69
- dotOffset,
70
- dashLength,
71
- dashOffset,
72
57
  scale,
73
- scaleLogarithmicBase
58
+ scaleLogarithmicBase,
59
+ lineStyle
74
60
  }: Props): JSX.Element => {
75
61
  const { stackedLinesData, invertedStackedLinesData } = useStackedLines({
76
62
  lines: displayedLines,
@@ -88,18 +74,10 @@ const Lines = ({
88
74
 
89
75
  const displayGuidingLines = displayAnchor?.displayGuidingLines ?? true;
90
76
  const commonStackedLinesProps = {
91
- areaTransparency,
92
- curve,
93
- dashLength,
94
- dashOffset,
95
77
  displayAnchor: displayGuidingLines,
96
- dotOffset,
97
78
  graphHeight: height,
98
79
  graphSvgRef,
99
80
  graphWidth: width,
100
- lineWidth,
101
- showArea,
102
- showPoints,
103
81
  xScale
104
82
  };
105
83
 
@@ -119,6 +97,7 @@ const Lines = ({
119
97
  {Object.entries(stackedLinesData).map(
120
98
  ([unit, { lines, timeSeries: stackedTimeSeries }]) => (
121
99
  <StackedLines
100
+ lineStyle={lineStyle}
122
101
  key={`stacked-${unit}`}
123
102
  lines={lines}
124
103
  timeSeries={stackedTimeSeries}
@@ -130,6 +109,7 @@ const Lines = ({
130
109
  {Object.entries(invertedStackedLinesData).map(
131
110
  ([unit, { lines, timeSeries: stackedTimeSeries }]) => (
132
111
  <StackedLines
112
+ lineStyle={lineStyle}
133
113
  key={`invert-stacked-${unit}`}
134
114
  lines={lines}
135
115
  timeSeries={stackedTimeSeries}
@@ -196,6 +176,11 @@ const Lines = ({
196
176
  timeSeries
197
177
  });
198
178
 
179
+ const style = getStyle({
180
+ style: lineStyle,
181
+ metricId: metric_id
182
+ }) as LineStyle;
183
+
199
184
  return (
200
185
  <g key={metric_id}>
201
186
  {displayGuidingLines && (
@@ -209,13 +194,13 @@ const Lines = ({
209
194
  yScale={yScale}
210
195
  />
211
196
  )}
212
- {showPoints &&
197
+ {style?.showPoints &&
213
198
  getDates(relatedTimeSeries).map((timeTick) => (
214
199
  <Point
215
200
  key={timeTick.toString()}
216
201
  lineColor={lineColor}
217
202
  metric_id={metric_id}
218
- radius={getPointRadius(lineWidth)}
203
+ radius={getPointRadius(style?.lineWidth)}
219
204
  timeSeries={relatedTimeSeries}
220
205
  timeTick={timeTick}
221
206
  xScale={xScale}
@@ -230,21 +215,21 @@ const Lines = ({
230
215
  ))}
231
216
  <RegularLine
232
217
  areaColor={areaColor || lineColor}
233
- curve={curve}
234
- dashLength={dashLength}
235
- dashOffset={dashOffset}
236
- dotOffset={dotOffset}
237
- filled={isNil(showArea) ? filled : showArea}
218
+ curve={style?.curve || 'linear'}
219
+ dashLength={style?.dashLength}
220
+ dashOffset={style?.dashOffset}
221
+ dotOffset={style?.dotOffset}
222
+ filled={isNil(style?.showArea) ? filled : style.showArea}
238
223
  graphHeight={height}
239
224
  highlight={highlight}
240
225
  lineColor={lineColor}
241
- lineWidth={lineWidth}
226
+ lineWidth={style?.lineWidth || 2}
242
227
  metric_id={metric_id}
243
228
  timeSeries={relatedTimeSeries}
244
229
  transparency={
245
- isNil(areaTransparency)
230
+ isNil(style?.areaTransparency)
246
231
  ? transparency || 80
247
- : areaTransparency
232
+ : style.areaTransparency
248
233
  }
249
234
  unit={unit}
250
235
  xScale={xScale}
@@ -9,6 +9,7 @@ import dataCurvesWithSameColor from '../mockedData/curvesWithSameColor.json';
9
9
  import dataLastDay from '../mockedData/lastDay.json';
10
10
  import dataLastDayWithIncompleteValues from '../mockedData/lastDayWithIncompleteValues.json';
11
11
  import dataLastDayWithNullValues from '../mockedData/lastDayWithNullValues.json';
12
+ import dataPingServiceLines from '../mockedData/pingService.json';
12
13
  import dataPingServiceLinesBars from '../mockedData/pingServiceLinesBars.json';
13
14
  import dataPingServiceLinesBarsMixed from '../mockedData/pingServiceLinesBarsMixed.json';
14
15
  import dataPingServiceLinesBarsStacked from '../mockedData/pingServiceLinesBarsStacked.json';
@@ -19,7 +20,10 @@ import { LineChartProps } from './models';
19
20
  import WrapperChart from '.';
20
21
 
21
22
  interface Props
22
- extends Pick<LineChartProps, 'legend' | 'tooltip' | 'axis' | 'lineStyle'> {
23
+ extends Pick<
24
+ LineChartProps,
25
+ 'legend' | 'tooltip' | 'axis' | 'lineStyle' | 'barStyle' | 'additionalLines'
26
+ > {
23
27
  data?: LineChartData;
24
28
  }
25
29
 
@@ -63,7 +67,9 @@ const initialize = ({
63
67
  tooltip,
64
68
  legend,
65
69
  axis,
66
- lineStyle
70
+ lineStyle,
71
+ barStyle,
72
+ additionalLines
67
73
  }: Props): void => {
68
74
  cy.adjustViewport();
69
75
 
@@ -84,7 +90,9 @@ const initialize = ({
84
90
  data={data as unknown as LineChartData}
85
91
  legend={legend}
86
92
  lineStyle={lineStyle}
93
+ barStyle={barStyle}
87
94
  tooltip={tooltip}
95
+ additionalLines={additionalLines}
88
96
  />
89
97
  </Provider>
90
98
  )
@@ -131,7 +139,7 @@ const initializeCustomUnits = ({
131
139
  const checkGraphWidth = (): void => {
132
140
  cy.findByTestId('graph-interaction-zone')
133
141
  .should('have.attr', 'height')
134
- .and('equal', '393');
142
+ .and('equal', '376.203125');
135
143
 
136
144
  cy.findByTestId('graph-interaction-zone').then((graph) => {
137
145
  expect(Number(graph[0].attributes.width.value)).to.be.greaterThan(1170);
@@ -170,7 +178,7 @@ describe('Line chart', () => {
170
178
 
171
179
  cy.contains('Min: 70.31').should('be.visible');
172
180
 
173
- cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26);
181
+ cy.findByTestId('graph-interaction-zone').realMouseMove(230, 26);
174
182
 
175
183
  cy.get('[data-metric="querytime"]').should(
176
184
  'have.attr',
@@ -182,6 +190,11 @@ describe('Line chart', () => {
182
190
  'data-highlight',
183
191
  'false'
184
192
  );
193
+ cy.get('[data-metric="hitratio"]').should(
194
+ 'have.attr',
195
+ 'data-highlight',
196
+ 'true'
197
+ );
185
198
 
186
199
  cy.makeSnapshot();
187
200
  });
@@ -215,25 +228,6 @@ describe('Line chart', () => {
215
228
  cy.makeSnapshot();
216
229
  });
217
230
 
218
- it('displays the tooltip a single metric when the corresponding prop is set', () => {
219
- initialize({ tooltip: { mode: 'single', sortOrder: 'name' } });
220
-
221
- checkGraphWidth();
222
-
223
- cy.contains('Min: 70.31').should('be.visible');
224
-
225
- cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26);
226
-
227
- cy.get('[data-metric="hitratio"]').should(
228
- 'have.attr',
229
- 'data-highlight',
230
- 'true'
231
- );
232
- cy.get('[data-metric="querytime"]').should('not.exist');
233
-
234
- cy.makeSnapshot();
235
- });
236
-
237
231
  it('does not display the tooltip when the corresponding prop is set', () => {
238
232
  initialize({ tooltip: { mode: 'hidden', sortOrder: 'name' } });
239
233
 
@@ -443,7 +437,7 @@ describe('Line chart', () => {
443
437
 
444
438
  cy.contains(':00 AM').should('be.visible');
445
439
 
446
- cy.get('text[transform="rotate(-35, -2, 312.508173777963)"]').should(
440
+ cy.get('text[transform="rotate(-35, -2, 145.04834208635688)"]').should(
447
441
  'be.visible'
448
442
  );
449
443
 
@@ -479,15 +473,14 @@ describe('Line chart', () => {
479
473
  });
480
474
 
481
475
  it('displays the curve in a step style when the prop is set', () => {
482
- initialize({ lineStyle: { curve: 'step' } });
476
+ initialize({ lineStyle: { curve: 'step' }, data: dataPingServiceLines });
483
477
 
484
478
  checkGraphWidth();
485
479
 
486
480
  cy.contains(':00 AM').should('be.visible');
487
- cy.get('[data-metric="13536"]').should('be.visible');
488
- cy.get('[data-metric="13534"]').should('be.visible');
489
- cy.get('[data-metric="13535"]').should('be.visible');
490
- checkLegendInformation();
481
+ cy.get('[data-metric="1"]').should('be.visible');
482
+ cy.get('[data-metric="2"]').should('be.visible');
483
+ cy.get('[data-metric="3"]').should('be.visible');
491
484
 
492
485
  cy.makeSnapshot();
493
486
  });
@@ -525,7 +518,8 @@ describe('Line chart', () => {
525
518
 
526
519
  checkGraphWidth();
527
520
  cy.contains(':00 AM').should('be.visible');
528
- cy.get('circle[cx="37.625"]').should('be.visible');
521
+ cy.get('circle[cx="250.83333333333334"]').should('be.visible');
522
+ cy.get('circle[cy="52.93597418085514"]').should('be.visible');
529
523
 
530
524
  cy.makeSnapshot();
531
525
  });
@@ -552,7 +546,7 @@ describe('Line chart', () => {
552
546
  .and('equals', '4 10');
553
547
  });
554
548
 
555
- it('displays lines with dots width when the prop is set', () => {
549
+ it('displays lines with dashes width when props are set', () => {
556
550
  initialize({ lineStyle: { dashLength: 5, dashOffset: 8 } });
557
551
 
558
552
  checkGraphWidth();
@@ -562,6 +556,31 @@ describe('Line chart', () => {
562
556
  .should('have.attr', 'stroke-dasharray')
563
557
  .and('equals', '5 8');
564
558
  });
559
+
560
+ it('displays only one line with custom style when props are set', () => {
561
+ initialize({
562
+ lineStyle: [
563
+ {
564
+ dashLength: 5,
565
+ dashOffset: 4,
566
+ lineWidth: 1,
567
+ showPoints: true,
568
+ showArea: true,
569
+ metricId: 13534
570
+ }
571
+ ]
572
+ });
573
+
574
+ checkGraphWidth();
575
+
576
+ cy.contains(':00 AM').should('be.visible');
577
+ cy.get('path.visx-area-closed')
578
+ .should('have.attr', 'stroke-dasharray')
579
+ .and('equals', '5 4');
580
+ cy.get('circle[cx="33.44444444444444"]').should('be.visible');
581
+
582
+ cy.makeSnapshot();
583
+ });
565
584
  });
566
585
  });
567
586
 
@@ -690,4 +709,58 @@ describe('Lines and bars', () => {
690
709
 
691
710
  cy.makeSnapshot();
692
711
  });
712
+
713
+ it('displays stacked lines and bars when a line and a bar are customized', () => {
714
+ initialize({
715
+ data: dataPingServiceLinesBarsStacked,
716
+ lineStyle: [
717
+ {
718
+ metricId: 1,
719
+ showArea: false,
720
+ dotOffset: 4,
721
+ lineWidth: 3
722
+ }
723
+ ],
724
+ barStyle: [
725
+ {
726
+ metricId: 10,
727
+ opacity: 0.5,
728
+ radius: 0.3
729
+ }
730
+ ]
731
+ });
732
+
733
+ checkGraphWidth();
734
+
735
+ cy.get(
736
+ 'path[d="M7.501377410468319,273.3424587717121 h56.51239669421488 h1v1 v100.86066622828793 a1,1 0 0 1 -1,1 h-56.51239669421488 a1,1 0 0 1 -1,-1 v-100.86066622828793 v-1h1z"]'
737
+ ).should('be.visible');
738
+ cy.get(
739
+ 'path[d="M24.05509641873278,218.3663782225586 h23.404958677685954 a17.553719008264462,17.553719008264462 0 0 1 17.553719008264462,17.553719008264462 v19.86864253262454 v17.553719008264462h-17.553719008264462 h-23.404958677685954 h-17.553719008264462v-17.553719008264462 v-19.86864253262454 a17.553719008264462,17.553719008264462 0 0 1 17.553719008264462,-17.553719008264462z"]'
740
+ ).should('be.visible');
741
+
742
+ cy.makeSnapshot();
743
+ });
744
+
745
+ it('displays additional lines when props are set', () => {
746
+ initialize({
747
+ data: dataPingServiceLines,
748
+ additionalLines: [
749
+ { color: 'pink', unit: '%', yValue: 3 },
750
+ { color: 'red', unit: 'ms', yValue: 0.15, text: 'some text' }
751
+ ]
752
+ });
753
+
754
+ checkGraphWidth();
755
+
756
+ cy.get('path[data-metric="1"]').should('be.visible');
757
+ cy.get('path[data-metric="3"]').should('be.visible');
758
+ cy.get('path[data-metric="3"]').should('be.visible');
759
+
760
+ cy.contains('some text').should('be.visible');
761
+ cy.findByTestId('pink-3').should('exist');
762
+ cy.findByTestId('red-0.15').should('exist');
763
+
764
+ cy.makeSnapshot();
765
+ });
693
766
  });
@@ -22,6 +22,7 @@ import dataLastDayThreshold from '../mockedData/lastDayThreshold.json';
22
22
  import dataLastDayWithLotOfUnits from '../mockedData/lastDayWithLotOfUnits.json';
23
23
  import dataLastMonth from '../mockedData/lastMonth.json';
24
24
  import dataLastWeek from '../mockedData/lastWeek.json';
25
+ import dataPingService from '../mockedData/pingService.json';
25
26
  import dataPingServiceLinesBars from '../mockedData/pingServiceLinesBars.json';
26
27
  import dataPingServiceLinesBarsMixed from '../mockedData/pingServiceLinesBarsMixed.json';
27
28
  import dataPingServiceLinesBarsStacked from '../mockedData/pingServiceLinesBarsStacked.json';
@@ -536,7 +537,7 @@ export const customLinesAndBars: Story = {
536
537
  render: (args) => (
537
538
  <WrapperChart
538
539
  {...args}
539
- data={dataPingServiceLinesBars as unknown as LineChartData}
540
+ data={dataPingService as unknown as LineChartData}
540
541
  />
541
542
  )
542
543
  };
@@ -565,7 +566,7 @@ export const linesAndBars: Story = {
565
566
  render: (args) => (
566
567
  <WrapperChart
567
568
  {...args}
568
- data={dataPingServiceLinesBars as unknown as LineChartData}
569
+ data={dataPingServiceLinesBarsMixed as unknown as LineChartData}
569
570
  />
570
571
  )
571
572
  };
@@ -695,3 +696,24 @@ export const customYUnits: Story = {
695
696
  args: argumentsData,
696
697
  render: (args) => <CustomYUnits {...args} />
697
698
  };
699
+
700
+ export const WithAdditionalLines: Story = {
701
+ argTypes,
702
+ args: {
703
+ ...argumentsData,
704
+ additionalLines: [
705
+ {
706
+ yValue: 3,
707
+ text: 'my text',
708
+ color: 'grey',
709
+ unit: '%'
710
+ }
711
+ ]
712
+ },
713
+ render: (args) => (
714
+ <WrapperChart
715
+ {...args}
716
+ data={dataPingService as unknown as LineChartData}
717
+ />
718
+ )
719
+ };
@@ -13,6 +13,7 @@ import { ClickAwayListener, Skeleton } from '@mui/material';
13
13
 
14
14
  import { useDeepCompare } from '../../utils';
15
15
  import BarGroup from '../BarChart/BarGroup';
16
+ import AdditionalLine from '../common/BaseChart/AdditionalLine';
16
17
  import BaseChart from '../common/BaseChart/BaseChart';
17
18
  import ChartSvgWrapper from '../common/BaseChart/ChartSvgWrapper';
18
19
  import { useComputeBaseChartDimensions } from '../common/BaseChart/useComputeBaseChartDimensions';
@@ -110,7 +111,8 @@ const Chart = ({
110
111
  thresholdUnit,
111
112
  limitLegend,
112
113
  skipIntersectionObserver,
113
- transformMatrix
114
+ transformMatrix,
115
+ additionalLines
114
116
  }: Props): JSX.Element => {
115
117
  const { classes } = useChartStyles();
116
118
 
@@ -150,15 +152,16 @@ const Chart = ({
150
152
  secondUnit
151
153
  });
152
154
 
153
- const { legendRef, graphWidth, graphHeight } = useComputeBaseChartDimensions({
154
- hasSecondUnit: Boolean(secondUnit),
155
- height,
156
- legendDisplay: legend?.display,
157
- legendHeight: legend?.height,
158
- legendPlacement: legend?.placement,
159
- width,
160
- maxAxisCharacters: maxRightAxisCharacters || maxLeftAxisCharacters
161
- });
155
+ const { legendRef, graphWidth, graphHeight, titleRef } =
156
+ useComputeBaseChartDimensions({
157
+ hasSecondUnit: Boolean(secondUnit),
158
+ height,
159
+ legendDisplay: legend?.display,
160
+ legendHeight: legend?.height,
161
+ legendPlacement: legend?.placement,
162
+ width,
163
+ maxAxisCharacters: maxRightAxisCharacters || maxLeftAxisCharacters
164
+ });
162
165
 
163
166
  const xScale = useMemo(
164
167
  () =>
@@ -273,6 +276,7 @@ const Chart = ({
273
276
  lines={linesGraph}
274
277
  setLines={setLinesGraph}
275
278
  title={title}
279
+ titleRef={titleRef}
276
280
  >
277
281
  <GraphValueTooltip
278
282
  baseAxis={baseAxis}
@@ -312,20 +316,13 @@ const Chart = ({
312
316
  )}
313
317
  {!isEmpty(linesDisplayedAsLine) && (
314
318
  <Lines
315
- areaTransparency={lineStyle?.areaTransparency}
316
- curve={lineStyle?.curve || 'linear'}
317
- dashLength={lineStyle?.dashLength}
318
- dashOffset={lineStyle?.dashOffset}
319
+ lineStyle={lineStyle}
319
320
  displayAnchor={displayAnchor}
320
321
  displayedLines={linesDisplayedAsLine}
321
- dotOffset={lineStyle?.dotOffset}
322
322
  graphSvgRef={graphSvgRef}
323
323
  height={graphHeight - margin.top}
324
- lineWidth={lineStyle?.lineWidth}
325
324
  scale={axis?.scale}
326
325
  scaleLogarithmicBase={axis?.scaleLogarithmicBase}
327
- showArea={lineStyle?.showArea}
328
- showPoints={lineStyle?.showPoints}
329
326
  timeSeries={timeSeries}
330
327
  width={graphWidth}
331
328
  xScale={xScale}
@@ -333,6 +330,14 @@ const Chart = ({
333
330
  {...shapeLines}
334
331
  />
335
332
  )}
333
+ {additionalLines?.map((additionalLine) => (
334
+ <AdditionalLine
335
+ key={additionalLine.yValue}
336
+ {...additionalLine}
337
+ graphWidth={graphWidth}
338
+ yScale={yScalesPerUnit[additionalLine.unit]}
339
+ />
340
+ ))}
336
341
  <InteractionWithGraph
337
342
  annotationData={{ ...annotationEvent }}
338
343
  commonData={{
@@ -70,6 +70,7 @@ const WrapperChart = ({
70
70
  limitLegend,
71
71
  getRef,
72
72
  transformMatrix,
73
+ additionalLines,
73
74
  ...rest
74
75
  }: Props): JSX.Element | null => {
75
76
  const { classes, cx } = useChartStyles();
@@ -126,6 +127,7 @@ const WrapperChart = ({
126
127
  width={width ?? responsiveWidth}
127
128
  zoomPreview={zoomPreview}
128
129
  skipIntersectionObserver={rest.skipIntersectionObserver}
130
+ additionalLines={additionalLines}
129
131
  transformMatrix={transformMatrix}
130
132
  />
131
133
  );
@@ -8,7 +8,7 @@ import type {
8
8
  Axis as AxisYLeft,
9
9
  AxisYRight
10
10
  } from '../common/Axes/models';
11
- import type { LineChartData } from '../common/models';
11
+ import type { AdditionalLineProps, LineChartData } from '../common/models';
12
12
  import type { Line, TimeValue } from '../common/timeSeries/models';
13
13
 
14
14
  import type { FactorsVariation } from './BasicComponents/Lines/Threshold/models';
@@ -110,17 +110,18 @@ export interface LineStyle {
110
110
  export interface LineChartProps {
111
111
  annotationEvent?: AnnotationEvent;
112
112
  axis?: ChartAxis;
113
- barStyle?: BarStyle;
113
+ barStyle?: BarStyle | Array<BarStyle & { metricId: number }>;
114
114
  displayAnchor?: DisplayAnchor;
115
115
  header?: LineChartHeader;
116
116
  height?: number | null;
117
117
  legend?: LegendModel;
118
- lineStyle?: LineStyle;
118
+ lineStyle?: LineStyle | Array<LineStyle & { metricId: number }>;
119
119
  timeShiftZones?: InteractedZone;
120
120
  tooltip?: Tooltip;
121
121
  width: number;
122
122
  zoomPreview?: InteractedZone;
123
123
  skipIntersectionObserver?: boolean;
124
+ additionalLines?: Array<AdditionalLineProps>;
124
125
  }
125
126
 
126
127
  export interface Area {
@@ -63,7 +63,7 @@ export const ThresholdLine = ({
63
63
  strokeDasharray="6, 6"
64
64
  strokeWidth={2}
65
65
  x1={scaledValue}
66
- x2={scaledValue}
66
+ x2={scaledValue + 1}
67
67
  y1={
68
68
  isSmall
69
69
  ? groupMargin - lineMargin + 6
@@ -80,7 +80,7 @@ export const ThresholdLine = ({
80
80
  stroke="transparent"
81
81
  strokeWidth={5}
82
82
  x1={scaledValue}
83
- x2={scaledValue}
83
+ x2={scaledValue + 1}
84
84
  y1={
85
85
  isSmall
86
86
  ? groupMargin - lineMargin + 5
@@ -156,5 +156,8 @@ export const treeWithZoom: Story = {
156
156
  getStrokeWidth: ({ target }) => (target.status === 'ok' ? 1 : 2)
157
157
  }
158
158
  },
159
- render: TreeWithZoom
159
+ render: TreeWithZoom,
160
+ parameters: {
161
+ chromatic: { disableSnapshot: true }
162
+ }
160
163
  };
@@ -46,7 +46,7 @@ const Axes = ({
46
46
 
47
47
  const [, secondUnit] = getUnits(lines);
48
48
 
49
- const xTickCount = Math.min(Math.ceil(width / 82), 12);
49
+ const xTickCount = Math.floor(Math.min(width / 100, 12));
50
50
 
51
51
  const domain = xScale.domain();
52
52
 
@@ -0,0 +1,37 @@
1
+ import { useMemo } from 'react';
2
+ import { AdditionalLineProps } from '../models';
3
+
4
+ interface Props extends AdditionalLineProps {
5
+ graphWidth: number;
6
+ yScale;
7
+ }
8
+
9
+ const AdditionalLine = ({
10
+ yValue,
11
+ color,
12
+ text,
13
+ graphWidth,
14
+ yScale
15
+ }: Props): JSX.Element => {
16
+ const positionY = useMemo(() => yScale(yValue), [yValue, yScale]);
17
+
18
+ return (
19
+ <g>
20
+ {text && (
21
+ <text x={8} y={positionY - 8} fill={color} style={{ fontSize: '10px' }}>
22
+ {text}
23
+ </text>
24
+ )}
25
+ <line
26
+ x1={0}
27
+ x2={graphWidth}
28
+ y1={positionY}
29
+ y2={positionY}
30
+ stroke={color}
31
+ data-testid={`${color}-${yValue}`}
32
+ />
33
+ </g>
34
+ );
35
+ };
36
+
37
+ export default AdditionalLine;
@@ -23,6 +23,7 @@ interface Props {
23
23
  displayLegend: boolean;
24
24
  legendHeight?: number;
25
25
  };
26
+ titleRef: MutableRefObject<HTMLDivElement | null>;
26
27
  legendRef: MutableRefObject<HTMLDivElement | null>;
27
28
  limitLegend?: number | false;
28
29
  lines: Array<Line>;
@@ -42,6 +43,7 @@ const BaseChart = ({
42
43
  setLines,
43
44
  children,
44
45
  legendRef,
46
+ titleRef,
45
47
  title,
46
48
  header,
47
49
  isHorizontal = true
@@ -68,7 +70,9 @@ const BaseChart = ({
68
70
 
69
71
  return (
70
72
  <>
71
- <Header header={header} title={title} />
73
+ <div ref={titleRef}>
74
+ <Header header={header} title={title} ref={titleRef} />
75
+ </div>
72
76
  <div className={classes.container}>
73
77
  <Stack
74
78
  direction={equals(legend?.placement, 'left') ? 'row' : 'row-reverse'}