@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 +1 -1
- package/src/Graph/BarChart/BarChart.cypress.spec.tsx +11 -1
- package/src/Graph/BarChart/BarChart.stories.tsx +9 -0
- package/src/Graph/BarChart/BarGroup.tsx +22 -32
- package/src/Graph/BarChart/MemoizedGroup.tsx +8 -11
- package/src/Graph/Chart/BasicComponents/Lines/StackedLines/useStackedLines.ts +18 -45
- package/src/Graph/Chart/BasicComponents/Lines/index.tsx +32 -26
- package/src/Graph/Chart/Chart.stories.tsx +9 -0
- package/src/Graph/common/timeSeries/index.test.ts +20 -0
- package/src/Graph/common/timeSeries/index.ts +89 -0
- package/src/Graph/common/timeSeries/models.ts +4 -2
- package/src/Graph/mockedData/pingServiceWithStackedKeys.json +205 -0
package/package.json
CHANGED
|
@@ -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
|
|
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
|
|
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={
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
?
|
|
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
|
-
?
|
|
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.
|
|
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.
|
|
114
|
-
nextProps.
|
|
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
|
-
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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:
|
|
63
|
-
stackedLinesData:
|
|
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
|
-
([
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
([
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
|
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
|
+
}
|