@centreon/ui 25.10.21 → 25.10.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "25.10.21",
3
+ "version": "25.10.22",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -4,11 +4,12 @@ import { useAtomValue } from 'jotai';
4
4
 
5
5
  import { userAtom } from '@centreon/ui-context';
6
6
 
7
+ import dataMissingPoint from '../mockedData/dataWithMissingPoint.json';
7
8
  import dataLastWeek from '../mockedData/lastWeek.json';
8
9
  import dataPingService from '../mockedData/pingService.json';
9
10
  import dataPingServiceMixedStacked from '../mockedData/pingServiceMixedStacked.json';
10
11
  import dataPingServiceStacked from '../mockedData/pingServiceStacked.json';
11
- import dataMissingPoint from '../mockedData/dataWithMissingPoint.json';
12
+ import dataPingServiceLinesStackKeys from '../mockedData/pingServiceWithStackedKeys.json';
12
13
 
13
14
  import BarChart, { BarChartProps } from './BarChart';
14
15
 
@@ -321,4 +322,13 @@ describe('Bar chart', () => {
321
322
 
322
323
  cy.makeSnapshot();
323
324
  });
325
+
326
+ it('displays the stacked bar chart with bars stacked together', () => {
327
+ initialize({ data: dataPingServiceLinesStackKeys });
328
+
329
+ cy.findByTestId('stacked-bar-3-0-0.05336').should('be.visible');
330
+ cy.findByTestId('stacked-bar-4-0-0.06684').should('be.visible');
331
+
332
+ cy.makeSnapshot();
333
+ });
324
334
  });
@@ -5,6 +5,7 @@ import { LineChartData } from '../common/models';
5
5
  import dataPingService from '../mockedData/pingService.json';
6
6
  import dataPingServiceMixedStacked from '../mockedData/pingServiceMixedStacked.json';
7
7
  import dataPingServiceStacked from '../mockedData/pingServiceStacked.json';
8
+ import dataPingServiceStackeKey from '../mockedData/pingServiceWithStackedKeys.json';
8
9
 
9
10
  import { ClickAwayListener } from '@mui/material';
10
11
  import { useState } from 'react';
@@ -301,3 +302,11 @@ export const withLegendSecondaryClick: Story = {
301
302
  />
302
303
  )
303
304
  };
305
+
306
+ export const stackKey: Story = {
307
+ args: {
308
+ ...defaultArgs,
309
+ data: dataPingServiceStackeKey
310
+ },
311
+ render: Template
312
+ };
@@ -1,12 +1,13 @@
1
1
  import { scaleBand, scaleOrdinal } from '@visx/scale';
2
2
  import { BarGroupHorizontal, BarGroup as VisxBarGroup } from '@visx/shape';
3
3
  import { ScaleLinear } from 'd3-scale';
4
- import { difference, equals, keys, omit, pick, pluck, uniq } from 'ramda';
4
+ import { difference, equals, keys, omit, pick } from 'ramda';
5
5
  import { memo, useMemo } from 'react';
6
6
 
7
7
  import { useDeepMemo } from '../../utils';
8
8
  import {
9
9
  getSortedStackedLines,
10
+ getStackedLinesTimeSeriesPerStackAndUnit,
10
11
  getTime,
11
12
  getTimeSeriesForLines,
12
13
  getUnits
@@ -54,41 +55,18 @@ const BarGroup = ({
54
55
  );
55
56
 
56
57
  const stackedLines = getSortedStackedLines(lines);
57
- const stackedUnits = uniq(pluck('unit', stackedLines));
58
58
  const notStackedLines = difference(lines, stackedLines);
59
-
60
- const stackedKeys = stackedUnits.reduce(
61
- (acc, unit) => ({
62
- ...acc,
63
- [`stacked-${unit}`]: null
64
- }),
65
- {}
66
- );
67
- const stackedLinesTimeSeriesPerUnit = stackedUnits.reduce(
68
- (acc, stackedUnit) => {
69
- const relatedLines = stackedLines.filter(({ unit }) =>
70
- equals(unit, stackedUnit)
71
- );
72
-
73
- return {
74
- ...acc,
75
- [stackedUnit]: {
76
- lines: relatedLines,
77
- timeSeries: getTimeSeriesForLines({
78
- lines: relatedLines,
79
- timeSeries
80
- })
81
- }
82
- };
83
- },
84
- {}
85
- );
86
-
87
59
  const notStackedTimeSeries = getTimeSeriesForLines({
88
60
  lines: notStackedLines,
89
61
  timeSeries
90
62
  });
91
63
 
64
+ const { stackedLinesTimeSeriesPerStackKeyAndUnit, stackedKeys } = useMemo(
65
+ () =>
66
+ getStackedLinesTimeSeriesPerStackAndUnit({ stackedLines, timeSeries }),
67
+ [stackedLines, timeSeries]
68
+ );
69
+
92
70
  const normalizedTimeSeries = notStackedTimeSeries.map((timeSerie) => ({
93
71
  ...timeSerie,
94
72
  ...stackedKeys
@@ -98,6 +76,16 @@ const BarGroup = ({
98
76
  deps: [normalizedTimeSeries],
99
77
  variable: keys(omit(['timeTick'], normalizedTimeSeries[0]))
100
78
  });
79
+ const sortedLineKeys = lineKeys.sort((lineKeyA: string, lineKeyB: string) => {
80
+ if (lineKeyA.startsWith('stacked-') && !lineKeyB.startsWith('stacked-')) {
81
+ return true;
82
+ }
83
+
84
+ const lineKeysA = lineKeyA.split('-');
85
+ const lineKeysB = lineKeyB.split('-');
86
+
87
+ return lineKeysA[2] === '' && lineKeysB[2] !== '';
88
+ });
101
89
  const colors = useDeepMemo({
102
90
  deps: [lineKeys, lines],
103
91
  variable: lineKeys.map((key) => {
@@ -154,7 +142,7 @@ const BarGroup = ({
154
142
  color={colorScale}
155
143
  data={normalizedTimeSeries}
156
144
  height={size}
157
- keys={lineKeys}
145
+ keys={sortedLineKeys}
158
146
  {...barComponentBaseProps}
159
147
  >
160
148
  {(barGroups) =>
@@ -164,7 +152,9 @@ const BarGroup = ({
164
152
  key={`bar-group-${barGroup.index}-${barGroup.x0}`}
165
153
  barGroup={barGroup}
166
154
  barStyle={barStyle}
167
- stackedLinesTimeSeriesPerUnit={stackedLinesTimeSeriesPerUnit}
155
+ stackedLinesTimeSeriesPerStackKeyAndUnit={
156
+ stackedLinesTimeSeriesPerStackKeyAndUnit
157
+ }
168
158
  notStackedTimeSeries={notStackedTimeSeries}
169
159
  notStackedLines={notStackedLines}
170
160
  isTooltipHidden={isTooltipHidden}
@@ -12,7 +12,7 @@ interface Props {
12
12
  isTooltipHidden: boolean;
13
13
  barStyle: BarStyle;
14
14
  yScalesPerUnit: Record<string, ScaleLinear<number, number>>;
15
- stackedLinesTimeSeriesPerUnit: Record<
15
+ stackedLinesTimeSeriesPerStackKeyAndUnit: Record<
16
16
  string,
17
17
  { lines: Array<Line>; timeSeries: Array<TimeValue> }
18
18
  >;
@@ -25,7 +25,7 @@ interface Props {
25
25
 
26
26
  const MemoizedGroup = ({
27
27
  barGroup,
28
- stackedLinesTimeSeriesPerUnit,
28
+ stackedLinesTimeSeriesPerStackKeyAndUnit,
29
29
  notStackedLines,
30
30
  notStackedTimeSeries,
31
31
  isHorizontal,
@@ -38,9 +38,7 @@ const MemoizedGroup = ({
38
38
  const hasEmptyValues = barGroup.bars.every(({ key, value }) => {
39
39
  if (key.startsWith('stacked-')) {
40
40
  const timeValueBar =
41
- stackedLinesTimeSeriesPerUnit[key.replace('stacked-', '')].timeSeries[
42
- barIndex
43
- ];
41
+ stackedLinesTimeSeriesPerStackKeyAndUnit[key].timeSeries[barIndex];
44
42
 
45
43
  return Object.values(omit(['timeTick'], timeValueBar)).every(
46
44
  (value) => !value
@@ -59,13 +57,12 @@ const MemoizedGroup = ({
59
57
  {barGroup.bars.map((bar) => {
60
58
  const isStackedBar = bar.key.startsWith('stacked-');
61
59
  const linesBar = isStackedBar
62
- ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')].lines
60
+ ? stackedLinesTimeSeriesPerStackKeyAndUnit[bar.key].lines
63
61
  : (notStackedLines.find(({ metric_id }) =>
64
62
  equals(metric_id, Number(bar.key))
65
63
  ) as Line);
66
64
  const timeSeriesBar = isStackedBar
67
- ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')]
68
- .timeSeries
65
+ ? stackedLinesTimeSeriesPerStackKeyAndUnit[bar.key].timeSeries
69
66
  : notStackedTimeSeries.map((timeSerie) => ({
70
67
  timeTick: timeSerie.timeTick,
71
68
  [bar.key]: timeSerie[Number(bar.key)]
@@ -82,7 +79,7 @@ const MemoizedGroup = ({
82
79
  isTooltipHidden={isTooltipHidden}
83
80
  lines={linesBar as Array<Line>}
84
81
  timeSeries={timeSeriesBar}
85
- yScale={yScalesPerUnit[bar.key.replace('stacked-', '')]}
82
+ yScale={yScalesPerUnit[bar.key.split('-')[1] || undefined]}
86
83
  neutralValue={neutralValue}
87
84
  />
88
85
  ) : (
@@ -110,8 +107,8 @@ export default memo(
110
107
  (prevProps, nextProps) =>
111
108
  equals(prevProps.barGroup, nextProps.barGroup) &&
112
109
  equals(
113
- prevProps.stackedLinesTimeSeriesPerUnit,
114
- nextProps.stackedLinesTimeSeriesPerUnit
110
+ prevProps.stackedLinesTimeSeriesPerStackKeyAndUnit,
111
+ nextProps.stackedLinesTimeSeriesPerStackKeyAndUnit
115
112
  ) &&
116
113
  equals(prevProps.notStackedLines, nextProps.notStackedLines) &&
117
114
  equals(prevProps.notStackedTimeSeries, nextProps.notStackedTimeSeries) &&
@@ -1,9 +1,7 @@
1
- import { equals, pluck, uniq } from 'ramda';
2
-
3
1
  import {
4
2
  getInvertedStackedLines,
5
3
  getNotInvertedStackedLines,
6
- getTimeSeriesForLines
4
+ getStackedLinesTimeSeriesPerStackAndUnit
7
5
  } from '../../../../common/timeSeries';
8
6
  import { LinesData } from '../models';
9
7
 
@@ -14,53 +12,28 @@ interface StackedLinesState {
14
12
 
15
13
  const useStackedLines = ({ lines, timeSeries }): StackedLinesState => {
16
14
  const regularStackedLines = getNotInvertedStackedLines(lines);
17
- const regularStackedUnits = uniq(pluck('unit', regularStackedLines));
18
- const regularStackedLinesTimeSeriesPerUnit = regularStackedUnits.reduce(
19
- (acc, stackedUnit) => {
20
- const relatedLines = regularStackedLines.filter(({ unit }) =>
21
- equals(unit, stackedUnit)
22
- );
23
-
24
- return {
25
- ...acc,
26
- [stackedUnit]: {
27
- lines: relatedLines,
28
- timeSeries: getTimeSeriesForLines({
29
- lines: relatedLines,
30
- timeSeries
31
- })
32
- }
33
- };
34
- },
35
- {}
36
- );
15
+ const {
16
+ stackedLinesTimeSeriesPerStackKeyAndUnit:
17
+ regularStackedLinesTimeSeriesPerStackKeyAndUnit
18
+ } = getStackedLinesTimeSeriesPerStackAndUnit({
19
+ stackedLines: regularStackedLines,
20
+ timeSeries
21
+ });
37
22
 
38
23
  const invertedStackedLines = getInvertedStackedLines(lines);
39
- const invertedStackedUnits = uniq(pluck('unit', invertedStackedLines));
40
- const invertedStackedLinesTimeSeriesPerUnit = invertedStackedUnits.reduce(
41
- (acc, stackedUnit) => {
42
- const relatedLines = invertedStackedLines.filter(({ unit }) =>
43
- equals(unit, stackedUnit)
44
- );
45
24
 
46
- return {
47
- ...acc,
48
- [stackedUnit]: {
49
- lines: relatedLines,
50
- timeSeries: getTimeSeriesForLines({
51
- invert: true,
52
- lines: relatedLines,
53
- timeSeries
54
- })
55
- }
56
- };
57
- },
58
- {}
59
- );
25
+ const {
26
+ stackedLinesTimeSeriesPerStackKeyAndUnit:
27
+ invertedStackedLinesTimeSeriesPerStackKeyAndUnit
28
+ } = getStackedLinesTimeSeriesPerStackAndUnit({
29
+ stackedLines: invertedStackedLines,
30
+ timeSeries,
31
+ invert: true
32
+ });
60
33
 
61
34
  return {
62
- invertedStackedLinesData: invertedStackedLinesTimeSeriesPerUnit,
63
- stackedLinesData: regularStackedLinesTimeSeriesPerUnit
35
+ invertedStackedLinesData: invertedStackedLinesTimeSeriesPerStackKeyAndUnit,
36
+ stackedLinesData: regularStackedLinesTimeSeriesPerStackKeyAndUnit
64
37
  };
65
38
  };
66
39
 
@@ -101,34 +101,40 @@ const Lines = ({
101
101
  {(areaStackedLines?.display ?? true) && (
102
102
  <>
103
103
  {Object.entries(stackedLinesData).map(
104
- ([unit, { lines, timeSeries: stackedTimeSeries }]) => (
105
- <StackedLines
106
- lineStyle={lineStyle}
107
- key={`stacked-${unit}`}
108
- lines={lines}
109
- timeSeries={stackedTimeSeries}
110
- yScale={yScalesPerUnit[unit]}
111
- {...commonStackedLinesProps}
112
- />
113
- )
104
+ ([stackedKey, { lines, timeSeries: stackedTimeSeries }]) => {
105
+ const [, unit] = stackedKey.split('-');
106
+ return (
107
+ <StackedLines
108
+ lineStyle={lineStyle}
109
+ key={`stacked-${unit}`}
110
+ lines={lines}
111
+ timeSeries={stackedTimeSeries}
112
+ yScale={yScalesPerUnit[unit || undefined]}
113
+ {...commonStackedLinesProps}
114
+ />
115
+ );
116
+ }
114
117
  )}
115
118
  {Object.entries(invertedStackedLinesData).map(
116
- ([unit, { lines, timeSeries: stackedTimeSeries }]) => (
117
- <StackedLines
118
- lineStyle={lineStyle}
119
- key={`invert-stacked-${unit}`}
120
- lines={lines}
121
- timeSeries={stackedTimeSeries}
122
- yScale={getYScale({
123
- invert: '1',
124
- scale,
125
- scaleLogarithmicBase,
126
- unit,
127
- yScalesPerUnit
128
- })}
129
- {...commonStackedLinesProps}
130
- />
131
- )
119
+ ([stackedKey, { lines, timeSeries: stackedTimeSeries }]) => {
120
+ const [, unit] = stackedKey.split('-');
121
+ return (
122
+ <StackedLines
123
+ lineStyle={lineStyle}
124
+ key={`invert-stacked-${unit}`}
125
+ lines={lines}
126
+ timeSeries={stackedTimeSeries}
127
+ yScale={getYScale({
128
+ invert: '1',
129
+ scale,
130
+ scaleLogarithmicBase,
131
+ unit: unit || undefined,
132
+ yScalesPerUnit
133
+ })}
134
+ {...commonStackedLinesProps}
135
+ />
136
+ );
137
+ }
132
138
  )}
133
139
  </>
134
140
  )}
@@ -26,6 +26,7 @@ import dataPingService from '../mockedData/pingService.json';
26
26
  import dataPingServiceLinesBars from '../mockedData/pingServiceLinesBars.json';
27
27
  import dataPingServiceLinesBarsMixed from '../mockedData/pingServiceLinesBarsMixed.json';
28
28
  import dataPingServiceLinesBarsStacked from '../mockedData/pingServiceLinesBarsStacked.json';
29
+ import dataPingServiceLinesStackKeys from '../mockedData/pingServiceWithStackedKeys.json';
29
30
  import dataZoomPreview from '../mockedData/zoomPreview.json';
30
31
 
31
32
  import { dateTimeFormat } from './common';
@@ -791,3 +792,11 @@ export const withLegendSecondaryClick: Story = {
791
792
  />
792
793
  )
793
794
  };
795
+
796
+ export const stackedKey: Story = {
797
+ argTypes,
798
+ args: {
799
+ ...argumentsData,
800
+ data: dataPingServiceLinesStackKeys
801
+ }
802
+ };
@@ -185,6 +185,7 @@ describe('timeSeries', () => {
185
185
  average_value: 1,
186
186
  color: 'black',
187
187
  display: true,
188
+ displayAs: undefined,
188
189
  filled: false,
189
190
  highlight: undefined,
190
191
  invert: null,
@@ -195,6 +196,7 @@ describe('timeSeries', () => {
195
196
  metric_id: 1,
196
197
  minimum_value: 0.5,
197
198
  name: 'Round-Trip-Time Average (ms)',
199
+ stackKey: null,
198
200
  stackOrder: null,
199
201
  transparency: 80,
200
202
  unit: 'ms'
@@ -204,6 +206,7 @@ describe('timeSeries', () => {
204
206
  average_value: 1,
205
207
  color: 'blue',
206
208
  display: true,
209
+ displayAs: undefined,
207
210
  filled: true,
208
211
  highlight: undefined,
209
212
  invert: null,
@@ -214,6 +217,7 @@ describe('timeSeries', () => {
214
217
  metric_id: 2,
215
218
  minimum_value: 0.5,
216
219
  name: 'Time (ms)',
220
+ stackKey: null,
217
221
  stackOrder: null,
218
222
  transparency: 80,
219
223
  unit: 'ms'
@@ -223,6 +227,7 @@ describe('timeSeries', () => {
223
227
  average_value: 1,
224
228
  color: 'red',
225
229
  display: true,
230
+ displayAs: undefined,
226
231
  filled: true,
227
232
  highlight: undefined,
228
233
  invert: null,
@@ -233,6 +238,7 @@ describe('timeSeries', () => {
233
238
  metric_id: 3,
234
239
  minimum_value: 0.5,
235
240
  name: 'Average duration (ms)',
241
+ stackKey: null,
236
242
  stackOrder: 2,
237
243
  transparency: 80,
238
244
  unit: 'ms'
@@ -242,6 +248,7 @@ describe('timeSeries', () => {
242
248
  average_value: 1,
243
249
  color: 'yellow',
244
250
  display: true,
251
+ displayAs: undefined,
245
252
  filled: true,
246
253
  highlight: undefined,
247
254
  invert: '1',
@@ -252,6 +259,7 @@ describe('timeSeries', () => {
252
259
  metric_id: 4,
253
260
  minimum_value: 0.5,
254
261
  name: 'Duration (ms)',
262
+ stackKey: null,
255
263
  stackOrder: 1,
256
264
  transparency: 80,
257
265
  unit: 'ms'
@@ -261,6 +269,7 @@ describe('timeSeries', () => {
261
269
  average_value: 1,
262
270
  color: 'yellow',
263
271
  display: true,
272
+ displayAs: undefined,
264
273
  filled: true,
265
274
  highlight: undefined,
266
275
  invert: null,
@@ -271,6 +280,7 @@ describe('timeSeries', () => {
271
280
  metric_id: 5,
272
281
  minimum_value: 0.5,
273
282
  name: 'Packet Loss (%)',
283
+ stackKey: null,
274
284
  stackOrder: null,
275
285
  transparency: 80,
276
286
  unit: '%'
@@ -331,6 +341,7 @@ describe('timeSeries', () => {
331
341
  average_value: 1,
332
342
  color: 'black',
333
343
  display: true,
344
+ displayAs: undefined,
334
345
  filled: false,
335
346
  highlight: undefined,
336
347
  invert: null,
@@ -341,6 +352,7 @@ describe('timeSeries', () => {
341
352
  metric_id: 1,
342
353
  minimum_value: 0.5,
343
354
  name: 'Round-Trip-Time Average (ms)',
355
+ stackKey: null,
344
356
  stackOrder: null,
345
357
  transparency: 80,
346
358
  unit: 'ms'
@@ -389,6 +401,7 @@ describe('timeSeries', () => {
389
401
  average_value: 1,
390
402
  color: 'yellow',
391
403
  display: true,
404
+ displayAs: undefined,
392
405
  filled: true,
393
406
  highlight: undefined,
394
407
  invert: '1',
@@ -399,6 +412,7 @@ describe('timeSeries', () => {
399
412
  metric_id: 4,
400
413
  minimum_value: 0.5,
401
414
  name: 'Duration (ms)',
415
+ stackKey: null,
402
416
  stackOrder: 1,
403
417
  transparency: 80,
404
418
  unit: 'ms'
@@ -408,6 +422,7 @@ describe('timeSeries', () => {
408
422
  average_value: 1,
409
423
  color: 'red',
410
424
  display: true,
425
+ displayAs: undefined,
411
426
  filled: true,
412
427
  highlight: undefined,
413
428
  invert: null,
@@ -418,6 +433,7 @@ describe('timeSeries', () => {
418
433
  metric_id: 3,
419
434
  minimum_value: 0.5,
420
435
  name: 'Average duration (ms)',
436
+ stackKey: null,
421
437
  stackOrder: 2,
422
438
  transparency: 80,
423
439
  unit: 'ms'
@@ -475,6 +491,7 @@ describe('timeSeries', () => {
475
491
  average_value: 1,
476
492
  color: 'yellow',
477
493
  display: true,
494
+ displayAs: undefined,
478
495
  filled: true,
479
496
  highlight: undefined,
480
497
  invert: '1',
@@ -485,6 +502,7 @@ describe('timeSeries', () => {
485
502
  metric_id: 4,
486
503
  minimum_value: 0.5,
487
504
  name: 'Duration (ms)',
505
+ stackKey: null,
488
506
  stackOrder: 1,
489
507
  transparency: 80,
490
508
  unit: 'ms'
@@ -503,6 +521,7 @@ describe('timeSeries', () => {
503
521
  average_value: 1,
504
522
  color: 'red',
505
523
  display: true,
524
+ displayAs: undefined,
506
525
  filled: true,
507
526
  highlight: undefined,
508
527
  invert: null,
@@ -513,6 +532,7 @@ describe('timeSeries', () => {
513
532
  metric_id: 3,
514
533
  minimum_value: 0.5,
515
534
  name: 'Average duration (ms)',
535
+ stackKey: null,
516
536
  stackOrder: 2,
517
537
  transparency: 80,
518
538
  unit: 'ms'
@@ -26,6 +26,7 @@ import {
26
26
  map,
27
27
  negate,
28
28
  pipe,
29
+ pluck,
29
30
  prop,
30
31
  propEq,
31
32
  reduce,
@@ -139,6 +140,7 @@ const toLine = ({
139
140
  equals(ds_data.ds_stack, '1') || equals(ds_data.ds_stack, true)
140
141
  ? Number.parseInt(ds_data.ds_order || '0', 10)
141
142
  : null,
143
+ stackKey: ds_data.ds_stack_key || null,
142
144
  transparency: ds_data.ds_transparency,
143
145
  unit
144
146
  });
@@ -758,6 +760,93 @@ export const formatMetricName = ({
758
760
  return metricName;
759
761
  };
760
762
 
763
+ export const getStackedLinesTimeSeriesPerStackAndUnit = ({
764
+ stackedLines,
765
+ timeSeries,
766
+ invert
767
+ }: {
768
+ stackedLines: Array<Line>;
769
+ timeSeries: Array<TimeValue>;
770
+ invert?: boolean;
771
+ }): {
772
+ stackedLinesTimeSeriesPerStackKeyAndUnit: Record<
773
+ string,
774
+ { lines: Array<Line>; timeSeries: Array<TimeValue> }
775
+ >;
776
+ stackedKeys: Record<string, null>;
777
+ } => {
778
+ const stackedKeys = stackedLines.reduce(
779
+ (acc, { unit, stackKey }) => ({
780
+ ...acc,
781
+ [`stacked-${unit || ''}-${stackKey ? stackKey : ''}`]: null
782
+ }),
783
+ {}
784
+ );
785
+ const stackedKeysWithOnlyStackKey = Object.keys(stackedKeys).filter(
786
+ (stackKey: string) => stackKey.split('-')[2]
787
+ );
788
+ const stackedKeysWithOnlyUnit = Object.keys(stackedKeys).filter(
789
+ (stackKey: string) => !stackKey.split('-')[2]
790
+ );
791
+
792
+ const stackedLinesTimeSeriesPerStackKey = stackedKeysWithOnlyStackKey.reduce(
793
+ (acc, stackedKey: string) => {
794
+ const [, stackUnit, stackKey] = stackedKey.split('-');
795
+ const relatedLines = stackedLines.filter(({ unit, stackKey: key }) => {
796
+ return stackUnit === (unit || '') && stackKey === key;
797
+ });
798
+
799
+ return {
800
+ ...acc,
801
+ [stackedKey]: {
802
+ lines: relatedLines,
803
+ timeSeries: getTimeSeriesForLines({
804
+ invert,
805
+ lines: relatedLines,
806
+ timeSeries
807
+ })
808
+ }
809
+ };
810
+ },
811
+ {}
812
+ );
813
+ const affectedLinesPerStackKey = flatten(
814
+ pluck('lines', Object.values(stackedLinesTimeSeriesPerStackKey))
815
+ );
816
+ const stackedLinesTimeSeriesPerUnit = stackedKeysWithOnlyUnit.reduce(
817
+ (acc, stackedKey: string) => {
818
+ const [, stackUnit] = stackedKey.split('-');
819
+ const relatedLines = stackedLines.filter(
820
+ (line) =>
821
+ !affectedLinesPerStackKey.some(
822
+ (affectedLine) => line.metric_id === affectedLine.metric_id
823
+ ) && stackUnit === (line.unit || '')
824
+ );
825
+
826
+ return {
827
+ ...acc,
828
+ [stackedKey]: {
829
+ lines: relatedLines,
830
+ timeSeries: getTimeSeriesForLines({
831
+ lines: relatedLines,
832
+ timeSeries,
833
+ invert
834
+ })
835
+ }
836
+ };
837
+ },
838
+ {}
839
+ );
840
+
841
+ return {
842
+ stackedLinesTimeSeriesPerStackKeyAndUnit: {
843
+ ...stackedLinesTimeSeriesPerStackKey,
844
+ ...stackedLinesTimeSeriesPerUnit
845
+ },
846
+ stackedKeys
847
+ };
848
+ };
849
+
761
850
  export {
762
851
  getTimeSeries,
763
852
  getLineData,
@@ -9,7 +9,8 @@ interface DsData {
9
9
  ds_invert: string | null;
10
10
  ds_legend: string | null;
11
11
  ds_order: string | null;
12
- ds_stack: string | null;
12
+ ds_stack: string | boolean | null;
13
+ ds_stack_key?: string | null;
13
14
  ds_transparency: number;
14
15
  }
15
16
 
@@ -20,7 +21,7 @@ export interface Metric {
20
21
  critical_low_threshold: number | null;
21
22
  data: Array<number | null>;
22
23
  displayAs?: 'line' | 'bar';
23
- ds_data?: DsData;
24
+ ds_data: DsData;
24
25
  legend: string;
25
26
  maximum_value: number | null;
26
27
  metric: string;
@@ -56,6 +57,7 @@ export interface Line {
56
57
  minimum_value: number | null;
57
58
  name: string;
58
59
  stackOrder: number | null;
60
+ stackKey: string | null;
59
61
  transparency: number;
60
62
  unit: string;
61
63
  }
@@ -0,0 +1,205 @@
1
+ {
2
+ "global": {
3
+ "base": 1000,
4
+ "title": "Ping service"
5
+ },
6
+ "metrics": [
7
+ {
8
+ "metric_id": 2,
9
+ "metric": "Centreon-Server: pl",
10
+ "metric_legend": "Centreon-Server: pl",
11
+ "unit": "%",
12
+ "min": 0.0,
13
+ "max": 100.0,
14
+ "ds_data": {
15
+ "ds_color_line": "#F30B23",
16
+ "ds_color_area": "#F30B23",
17
+ "ds_filled": true,
18
+ "ds_invert": false,
19
+ "ds_legend": null,
20
+ "ds_stack": false,
21
+ "ds_order": 1,
22
+ "ds_transparency": 80.0,
23
+ "ds_color_line_mode": 0
24
+ },
25
+ "legend": "Centreon-Server: Packet Loss",
26
+ "stack": 0,
27
+ "warning_high_threshold": 20.0,
28
+ "critical_high_threshold": 50.0,
29
+ "warning_low_threshold": 0.0,
30
+ "critical_low_threshold": 0.0,
31
+ "ds_order": 1,
32
+ "data": [
33
+ 0.0,
34
+ 0.0,
35
+ 0.0,
36
+ 0.0,
37
+ 0.0,
38
+ 0.0,
39
+ 0.0,
40
+ 0.0,
41
+ 0.0,
42
+ 10.0,
43
+ 20.0,
44
+ null,
45
+ null
46
+ ],
47
+ "last_value": 0.0,
48
+ "minimum_value": null,
49
+ "maximum_value": 0.0,
50
+ "average_value": 0.0
51
+ },
52
+ {
53
+ "metric_id": 1,
54
+ "metric": "Centreon-Server: rta",
55
+ "metric_legend": "Centreon-Server: rta",
56
+ "unit": "ms",
57
+ "min": 0.0,
58
+ "max": null,
59
+ "ds_data": {
60
+ "ds_color_line": "#29AFEE",
61
+ "ds_color_area": "#29AFEE",
62
+ "ds_filled": true,
63
+ "ds_invert": false,
64
+ "ds_legend": null,
65
+ "ds_stack": true,
66
+ "ds_order": 1,
67
+ "ds_transparency": 80.0,
68
+ "ds_color_line_mode": 0
69
+ },
70
+ "legend": "Centreon-Server: Round-Trip Average Time",
71
+ "stack": 0,
72
+ "warning_high_threshold": 200.0,
73
+ "critical_high_threshold": 400.0,
74
+ "warning_low_threshold": 0.0,
75
+ "critical_low_threshold": 0.0,
76
+ "ds_order": 1,
77
+ "data": [
78
+ 0.04508,
79
+ 0.0242,
80
+ 0.03592,
81
+ 0.01304,
82
+ 0.025,
83
+ 0.02748,
84
+ 0.05296,
85
+ 0.01864,
86
+ 0.02688,
87
+ 0.03676,
88
+ 0.03696,
89
+ null,
90
+ null
91
+ ],
92
+ "last_value": 0.04,
93
+ "minimum_value": null,
94
+ "maximum_value": null,
95
+ "average_value": 0.03
96
+ },
97
+ {
98
+ "metric_id": 3,
99
+ "metric": "Centreon-Server: rtmax",
100
+ "metric_legend": "Centreon-Server: rtmax",
101
+ "unit": "ms",
102
+ "min": null,
103
+ "max": null,
104
+ "ds_data": {
105
+ "ds_color_line": "#525256",
106
+ "ds_color_area": "#525256",
107
+ "ds_filled": false,
108
+ "ds_invert": false,
109
+ "ds_legend": null,
110
+ "ds_stack": true,
111
+ "ds_stack_key": "test",
112
+ "ds_order": 2,
113
+ "ds_transparency": 80.0,
114
+ "ds_color_line_mode": 0
115
+ },
116
+ "legend": "Centreon-Server: Round-Trip Maximum Time",
117
+ "stack": 0,
118
+ "warning_high_threshold": null,
119
+ "critical_high_threshold": null,
120
+ "warning_low_threshold": null,
121
+ "critical_low_threshold": null,
122
+ "ds_order": 2,
123
+ "data": [
124
+ 0.11372,
125
+ 0.05604,
126
+ 0.08556,
127
+ 0.02548,
128
+ 0.05352,
129
+ 0.05336,
130
+ 0.109,
131
+ 0.04112,
132
+ 0.05504,
133
+ 0.06812,
134
+ 0.08644,
135
+ null,
136
+ null
137
+ ],
138
+ "last_value": 0.09,
139
+ "minimum_value": null,
140
+ "maximum_value": 0.11,
141
+ "average_value": null
142
+ },
143
+ {
144
+ "metric_id": 4,
145
+ "metric": "Centreon-Server: rtmin",
146
+ "metric_legend": "Centreon-Server: rtmin",
147
+ "unit": "ms",
148
+ "min": null,
149
+ "max": null,
150
+ "ds_data": {
151
+ "ds_color_line": "#191777",
152
+ "ds_color_area": "#191777",
153
+ "ds_filled": false,
154
+ "ds_invert": false,
155
+ "ds_legend": null,
156
+ "ds_stack": true,
157
+ "ds_stack_key": "test",
158
+ "ds_order": 2,
159
+ "ds_transparency": 80.0,
160
+ "ds_color_line_mode": 0
161
+ },
162
+ "legend": "Centreon-Server: Round-Trip Minimum Time",
163
+ "stack": 0,
164
+ "warning_high_threshold": null,
165
+ "critical_high_threshold": null,
166
+ "warning_low_threshold": null,
167
+ "critical_low_threshold": null,
168
+ "ds_order": 2,
169
+ "data": [
170
+ 0.00984,
171
+ 0.008,
172
+ 0.00784,
173
+ 0.00624,
174
+ 0.00932,
175
+ 0.01348,
176
+ 0.01796,
177
+ 0.0064,
178
+ 0.01148,
179
+ 0.01644,
180
+ 0.01168,
181
+ null,
182
+ null
183
+ ],
184
+ "last_value": 0.01,
185
+ "minimum_value": 0.01,
186
+ "maximum_value": null,
187
+ "average_value": null
188
+ }
189
+ ],
190
+ "times": [
191
+ "2024-06-19T10:50:00+02:00",
192
+ "2024-06-19T10:55:00+02:00",
193
+ "2024-06-19T11:00:00+02:00",
194
+ "2024-06-19T11:05:00+02:00",
195
+ "2024-06-19T11:10:00+02:00",
196
+ "2024-06-19T11:15:00+02:00",
197
+ "2024-06-19T11:20:00+02:00",
198
+ "2024-06-19T11:25:00+02:00",
199
+ "2024-06-19T11:30:00+02:00",
200
+ "2024-06-19T11:35:00+02:00",
201
+ "2024-06-19T11:40:00+02:00",
202
+ "2024-06-19T11:45:00+02:00",
203
+ "2024-06-19T11:50:00+02:00"
204
+ ]
205
+ }