@centreon/ui 24.5.7 → 24.5.8

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": "24.5.7",
3
+ "version": "24.5.8",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -1,11 +1,11 @@
1
1
  import { lt } from 'ramda';
2
2
  import { Layout } from 'react-grid-layout';
3
3
 
4
- export const maxColumns = 12;
5
4
  const minColumns = 1;
6
5
  const breakpoint = 768;
7
6
 
8
7
  export const rowHeight = 64;
8
+ export const maxColumns = 12;
9
9
 
10
10
  export const getIsSmallScreenSize = (): boolean =>
11
11
  lt(window.innerWidth, breakpoint);
@@ -55,6 +55,7 @@ const RegularLine = ({
55
55
  if (filled) {
56
56
  return (
57
57
  <Shape.AreaClosed<TimeValue>
58
+ data-metric={metric_id}
58
59
  fill={getFillColor({ areaColor, transparency })}
59
60
  fillRule="nonzero"
60
61
  key={metric_id}
@@ -65,7 +66,7 @@ const RegularLine = ({
65
66
  );
66
67
  }
67
68
 
68
- return <Shape.LinePath<TimeValue> {...props} />;
69
+ return <Shape.LinePath<TimeValue> data-metric={metric_id} {...props} />;
69
70
  };
70
71
 
71
72
  export default memo(RegularLine, (prevProps, nextProps) => {
@@ -46,10 +46,8 @@ const StackLines = ({
46
46
  >
47
47
  {({ stacks, path: linePath }): Array<JSX.Element> => {
48
48
  return stacks.map((stack, index) => {
49
- const { areaColor, transparency, lineColor, highlight } = nth(
50
- index,
51
- lines
52
- ) as Line;
49
+ const { areaColor, transparency, lineColor, highlight, metric_id } =
50
+ nth(index, lines) as Line;
53
51
 
54
52
  return (
55
53
  <g key={`stack-${prop('key', stack)}`}>
@@ -66,6 +64,7 @@ const StackLines = ({
66
64
  )}
67
65
  <path
68
66
  d={linePath(stack) || ''}
67
+ data-metric={metric_id}
69
68
  fill={getFillColor({ areaColor, transparency })}
70
69
  opacity={highlight === false ? 0.3 : 1}
71
70
  stroke={lineColor}
@@ -63,7 +63,10 @@ const LegendHeader = ({
63
63
  placement="top"
64
64
  >
65
65
  <div className={classes.markerAndLegendName}>
66
- <div className={cx(classes.icon, { [classes.disabled]: disabled })} />
66
+ <div
67
+ data-icon
68
+ className={cx(classes.icon, { [classes.disabled]: disabled })}
69
+ />
67
70
  <EllipsisTypography
68
71
  className={cx(classes.text, classes.legendName)}
69
72
  data-mode={
@@ -3,6 +3,7 @@ import { LineChartData } from '../common/models';
3
3
  import dataLastDay from './mockedData/lastDay.json';
4
4
  import dataLastDayWithNullValues from './mockedData/lastDayWithNullValues.json';
5
5
  import dataLastDayWithIncompleteValues from './mockedData/lastDayWithIncompleteValues.json';
6
+ import dataCurvesWithSameColor from './mockedData/curvesWithSameColor.json';
6
7
  import { args as argumentsData } from './helpers/doc';
7
8
 
8
9
  import WrapperLineChart from '.';
@@ -88,4 +89,56 @@ describe('Line chart', () => {
88
89
  cy.makeSnapshot();
89
90
  });
90
91
  });
92
+
93
+ it('displays the curves with different shades when curves have same color', () => {
94
+ initialize(dataCurvesWithSameColor);
95
+
96
+ cy.findByLabelText('Centreon-Server: Round-Trip Average Time')
97
+ .find('[data-icon="true"]')
98
+ .should('have.css', 'background-color', 'rgb(41, 175, 238)');
99
+ cy.findByLabelText('Centreon-Server_5: Round-Trip Average Time')
100
+ .find('[data-icon="true"]')
101
+ .should('have.css', 'background-color', 'rgb(83, 191, 241)');
102
+ cy.findByLabelText('Centreon-Server_4: Round-Trip Average Time')
103
+ .find('[data-icon="true"]')
104
+ .should('have.css', 'background-color', 'rgb(8, 34, 47)');
105
+ cy.findByLabelText('Centreon-Server_3: Round-Trip Average Time')
106
+ .find('[data-icon="true"]')
107
+ .should('have.css', 'background-color', 'rgb(16, 70, 95)');
108
+ cy.findByLabelText('Centreon-Server_2: Round-Trip Average Time')
109
+ .find('[data-icon="true"]')
110
+ .should('have.css', 'background-color', 'rgb(24, 105, 142)');
111
+ cy.findByLabelText('Centreon-Server_1: Round-Trip Average Time')
112
+ .find('[data-icon="true"]')
113
+ .should('have.css', 'background-color', 'rgb(32, 140, 190)');
114
+
115
+ cy.get('[data-metric="1"]').should(
116
+ 'have.attr',
117
+ 'stroke',
118
+ 'rgb(41, 175, 238)'
119
+ );
120
+ cy.get('[data-metric="21"]').should(
121
+ 'have.attr',
122
+ 'stroke',
123
+ 'rgb(32, 140, 190)'
124
+ );
125
+ cy.get('[data-metric="17"]').should(
126
+ 'have.attr',
127
+ 'stroke',
128
+ 'rgb(24, 105, 142)'
129
+ );
130
+ cy.get('[data-metric="13"]').should(
131
+ 'have.attr',
132
+ 'stroke',
133
+ 'rgb(16, 70, 95)'
134
+ );
135
+ cy.get('[data-metric="9"]').should('have.attr', 'stroke', 'rgb(8, 34, 47)');
136
+ cy.get('[data-metric="5"]').should(
137
+ 'have.attr',
138
+ 'stroke',
139
+ 'rgb(83, 191, 241)'
140
+ );
141
+
142
+ cy.makeSnapshot();
143
+ });
91
144
  });
@@ -33,6 +33,7 @@ import dataLastMonth from './mockedData/lastMonth.json';
33
33
  import dataLastWeek from './mockedData/lastWeek.json';
34
34
  import dataZoomPreview from './mockedData/zoomPreview.json';
35
35
  import dataLastDay from './mockedData/lastDay.json';
36
+ import dataCurvesSameColor from './mockedData/curvesWithSameColor.json';
36
37
  import { Interval, ThresholdType, TooltipData } from './models';
37
38
 
38
39
  import WrapperLineChart from './index';
@@ -477,3 +478,15 @@ export const thresholdsRange: Story = {
477
478
  />
478
479
  )
479
480
  };
481
+
482
+ export const LineChartWithSameColorCurves: Story = {
483
+ ...Template,
484
+ argTypes,
485
+ args: argumentsData,
486
+ render: (args) => (
487
+ <WrapperLineChart
488
+ {...args}
489
+ data={dataCurvesSameColor as unknown as LineChartData}
490
+ />
491
+ )
492
+ };
@@ -0,0 +1,252 @@
1
+ {
2
+ "global": {
3
+ "title": "oracle-buffer-hit-ratio graph on srv-oracle-users",
4
+ "start": "2023-06-18T17:04:46+02:00",
5
+ "end": "2023-06-19T17:04:46+02:00",
6
+ "vertical-label": "Value",
7
+ "base": 1000,
8
+ "width": 550,
9
+ "height": 140,
10
+ "scaled": 0,
11
+ "multiple_services": false
12
+ },
13
+ "metrics": [
14
+ {
15
+ "metric_id": 1,
16
+ "metric": "Centreon-Server: rta",
17
+ "metric_legend": "Centreon-Server: rta",
18
+ "unit": "ms",
19
+ "min": 0.0,
20
+ "max": null,
21
+ "ds_data": {
22
+ "ds_color_line": "#29AFEE"
23
+ },
24
+ "legend": "Centreon-Server: Round-Trip Average Time",
25
+ "stack": 0,
26
+ "warning_high_threshold": 200.0,
27
+ "critical_high_threshold": 400.0,
28
+ "warning_low_threshold": 0.0,
29
+ "critical_low_threshold": 0.0,
30
+ "ds_order": 1,
31
+ "data": [
32
+ null,
33
+ null,
34
+ null,
35
+ null,
36
+ null,
37
+ null,
38
+ null,
39
+ null,
40
+ null,
41
+ 0.040219730942,
42
+ 0.03038,
43
+ 0.02108,
44
+ null
45
+ ],
46
+ "last_value": 0.02,
47
+ "minimum_value": null,
48
+ "maximum_value": null,
49
+ "average_value": 0.03
50
+ },
51
+ {
52
+ "metric_id": 21,
53
+ "metric": "Centreon-Server_1: rta",
54
+ "metric_legend": "Centreon-Server_1: rta",
55
+ "unit": "ms",
56
+ "min": 0.0,
57
+ "max": null,
58
+ "ds_data": {
59
+ "ds_color_line": "#29AFEE"
60
+ },
61
+ "legend": "Centreon-Server_1: Round-Trip Average Time",
62
+ "stack": 0,
63
+ "warning_high_threshold": 200.0,
64
+ "critical_high_threshold": 400.0,
65
+ "warning_low_threshold": 0.0,
66
+ "critical_low_threshold": 0.0,
67
+ "ds_order": 1,
68
+ "data": [
69
+ null,
70
+ null,
71
+ null,
72
+ null,
73
+ null,
74
+ null,
75
+ null,
76
+ null,
77
+ null,
78
+ null,
79
+ 0.046261744966,
80
+ 0.033813333333,
81
+ null
82
+ ],
83
+ "last_value": 0.03,
84
+ "minimum_value": null,
85
+ "maximum_value": null,
86
+ "average_value": 0.04
87
+ },
88
+ {
89
+ "metric_id": 17,
90
+ "metric": "Centreon-Server_2: rta",
91
+ "metric_legend": "Centreon-Server_2: rta",
92
+ "unit": "ms",
93
+ "min": 0.0,
94
+ "max": null,
95
+ "ds_data": {
96
+ "ds_color_line": "#29AFEE"
97
+ },
98
+ "legend": "Centreon-Server_2: Round-Trip Average Time",
99
+ "stack": 0,
100
+ "warning_high_threshold": 200.0,
101
+ "critical_high_threshold": 400.0,
102
+ "warning_low_threshold": 0.0,
103
+ "critical_low_threshold": 0.0,
104
+ "ds_order": 1,
105
+ "data": [
106
+ null,
107
+ null,
108
+ null,
109
+ null,
110
+ null,
111
+ null,
112
+ null,
113
+ null,
114
+ null,
115
+ null,
116
+ 0.035661073826,
117
+ 0.03853,
118
+ null
119
+ ],
120
+ "last_value": 0.04,
121
+ "minimum_value": null,
122
+ "maximum_value": null,
123
+ "average_value": 0.04
124
+ },
125
+ {
126
+ "metric_id": 13,
127
+ "metric": "Centreon-Server_3: rta",
128
+ "metric_legend": "Centreon-Server_3: rta",
129
+ "unit": "ms",
130
+ "min": 0.0,
131
+ "max": null,
132
+ "ds_data": {
133
+ "ds_color_line": "#29AFEE"
134
+ },
135
+ "legend": "Centreon-Server_3: Round-Trip Average Time",
136
+ "stack": 0,
137
+ "warning_high_threshold": 200.0,
138
+ "critical_high_threshold": 400.0,
139
+ "warning_low_threshold": 0.0,
140
+ "critical_low_threshold": 0.0,
141
+ "ds_order": 1,
142
+ "data": [
143
+ null,
144
+ null,
145
+ null,
146
+ null,
147
+ null,
148
+ null,
149
+ null,
150
+ null,
151
+ null,
152
+ null,
153
+ 0.055875838926,
154
+ 0.03161,
155
+ null
156
+ ],
157
+ "last_value": 0.03,
158
+ "minimum_value": null,
159
+ "maximum_value": null,
160
+ "average_value": 0.04
161
+ },
162
+ {
163
+ "metric_id": 9,
164
+ "metric": "Centreon-Server_4: rta",
165
+ "metric_legend": "Centreon-Server_4: rta",
166
+ "unit": "ms",
167
+ "min": 0.0,
168
+ "max": null,
169
+ "ds_data": {
170
+ "ds_color_line": "#29AFEE"
171
+ },
172
+ "legend": "Centreon-Server_4: Round-Trip Average Time",
173
+ "stack": 0,
174
+ "warning_high_threshold": 200.0,
175
+ "critical_high_threshold": 400.0,
176
+ "warning_low_threshold": 0.0,
177
+ "critical_low_threshold": 0.0,
178
+ "ds_order": 1,
179
+ "data": [
180
+ null,
181
+ null,
182
+ null,
183
+ null,
184
+ null,
185
+ null,
186
+ null,
187
+ null,
188
+ null,
189
+ null,
190
+ 0.02077852349,
191
+ 0.03634,
192
+ null
193
+ ],
194
+ "last_value": 0.04,
195
+ "minimum_value": null,
196
+ "maximum_value": null,
197
+ "average_value": 0.03
198
+ },
199
+ {
200
+ "metric_id": 5,
201
+ "metric": "Centreon-Server_5: rta",
202
+ "metric_legend": "Centreon-Server_5: rta",
203
+ "unit": "ms",
204
+ "min": 0.0,
205
+ "max": null,
206
+ "ds_data": {
207
+ "ds_color_line": "#29AFEE"
208
+ },
209
+ "legend": "Centreon-Server_5: Round-Trip Average Time",
210
+ "stack": 0,
211
+ "warning_high_threshold": 200.0,
212
+ "critical_high_threshold": 400.0,
213
+ "warning_low_threshold": 0.0,
214
+ "critical_low_threshold": 0.0,
215
+ "ds_order": 1,
216
+ "data": [
217
+ null,
218
+ null,
219
+ null,
220
+ null,
221
+ null,
222
+ null,
223
+ null,
224
+ null,
225
+ null,
226
+ null,
227
+ 0.042899328859,
228
+ 0.051873333333,
229
+ null
230
+ ],
231
+ "last_value": 0.05,
232
+ "minimum_value": null,
233
+ "maximum_value": null,
234
+ "average_value": 0.05
235
+ }
236
+ ],
237
+ "times": [
238
+ "2024-05-10T09:20:00+02:00",
239
+ "2024-05-10T09:25:00+02:00",
240
+ "2024-05-10T09:30:00+02:00",
241
+ "2024-05-10T09:35:00+02:00",
242
+ "2024-05-10T09:40:00+02:00",
243
+ "2024-05-10T09:45:00+02:00",
244
+ "2024-05-10T09:50:00+02:00",
245
+ "2024-05-10T09:55:00+02:00",
246
+ "2024-05-10T10:00:00+02:00",
247
+ "2024-05-10T10:05:00+02:00",
248
+ "2024-05-10T10:10:00+02:00",
249
+ "2024-05-10T10:15:00+02:00",
250
+ "2024-05-10T10:20:00+02:00"
251
+ ]
252
+ }
@@ -1,8 +1,20 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useCallback, useMemo, useRef } from 'react';
2
2
 
3
- import { compose, prop, sortBy, toLower } from 'ramda';
3
+ import {
4
+ compose,
5
+ flatten,
6
+ groupBy,
7
+ isNil,
8
+ lensPath,
9
+ pipe,
10
+ prop,
11
+ set,
12
+ sortBy,
13
+ toLower
14
+ } from 'ramda';
4
15
 
5
16
  import { LineChartData } from '../common/models';
17
+ import { emphasizeCurveColor } from '../common/utils';
6
18
 
7
19
  import { adjustGraphData } from './helpers';
8
20
  import { Data } from './models';
@@ -18,32 +30,59 @@ interface Props {
18
30
  }
19
31
 
20
32
  const useGraphData = ({ data, end, start }: Props): GraphDataResult => {
21
- const [adjustedData, setAdjustedData] = useState<Data>();
33
+ const adjustedDataRef = useRef<Data>();
22
34
 
23
- const prepareData = (dataToAdjust: LineChartData): void => {
24
- const { timeSeries } = adjustGraphData(dataToAdjust);
25
- const baseAxis = dataToAdjust.global.base;
26
- const { title } = dataToAdjust.global;
35
+ const dataWithAdjustedMetricsColor = useMemo(() => {
36
+ if (isNil(data)) {
37
+ return data;
38
+ }
39
+ const metricsGroupedByColor = groupBy(
40
+ (metric) => metric.ds_data.ds_color_line
41
+ )(data?.metrics || []);
42
+
43
+ const newMetrics = Object.entries(metricsGroupedByColor).map(
44
+ ([color, value]) => {
45
+ return value?.map((metric, index) =>
46
+ set(
47
+ lensPath(['ds_data', 'ds_color_line']),
48
+ emphasizeCurveColor({ color, index }),
49
+ metric
50
+ )
51
+ );
52
+ }
53
+ );
54
+
55
+ const sortedMetrics = pipe(flatten, sortBy(prop('metric')))(newMetrics);
56
+
57
+ return {
58
+ ...data,
59
+ metrics: sortedMetrics
60
+ };
61
+ }, [data]);
62
+
63
+ const prepareData = useCallback((): void => {
64
+ if (isNil(dataWithAdjustedMetricsColor)) {
65
+ return;
66
+ }
67
+
68
+ const { timeSeries } = adjustGraphData(dataWithAdjustedMetricsColor);
69
+ const baseAxis = dataWithAdjustedMetricsColor.global.base;
70
+ const { title } = dataWithAdjustedMetricsColor.global;
27
71
 
28
- const newLineData = adjustGraphData(dataToAdjust).lines;
72
+ const newLineData = adjustGraphData(dataWithAdjustedMetricsColor).lines;
29
73
  const sortedLines = sortBy(compose(toLower, prop('name')), newLineData);
30
74
 
31
- setAdjustedData({
75
+ adjustedDataRef.current = {
32
76
  baseAxis,
33
77
  lines: sortedLines,
34
78
  timeSeries,
35
79
  title
36
- });
37
- };
80
+ };
81
+ }, [dataWithAdjustedMetricsColor, end, start]);
38
82
 
39
- useEffect(() => {
40
- if (!data) {
41
- return;
42
- }
43
- prepareData(data);
44
- }, [end, start, data]);
83
+ prepareData();
45
84
 
46
- return { adjustedData };
85
+ return { adjustedData: adjustedDataRef.current };
47
86
  };
48
87
 
49
88
  export default useGraphData;
@@ -13,7 +13,7 @@ import {
13
13
  } from 'ramda';
14
14
  import numeral from 'numeral';
15
15
 
16
- import { Theme } from '@mui/material';
16
+ import { darken, getLuminance, lighten, Theme } from '@mui/material';
17
17
 
18
18
  import { Thresholds } from './models';
19
19
 
@@ -92,3 +92,51 @@ export const getValueByUnit = ({
92
92
 
93
93
  return `${((value * 100) / total).toFixed(1)}%`;
94
94
  };
95
+
96
+ interface NormalizeLevelProps {
97
+ factor: number;
98
+ level: number;
99
+ }
100
+
101
+ const normalizeLevel = ({ level, factor }: NormalizeLevelProps): number =>
102
+ (level * factor) / 10;
103
+
104
+ interface EmphasizeCurveColorProps {
105
+ color: string;
106
+ index: number;
107
+ }
108
+
109
+ export const emphasizeCurveColor = ({
110
+ color,
111
+ index
112
+ }: EmphasizeCurveColorProps): string => {
113
+ const totalLevels = 5;
114
+ const levels = [...Array(totalLevels).keys()];
115
+ const factor = 10 / totalLevels;
116
+
117
+ if (gte(getLuminance(color), 0.5)) {
118
+ if (gte(index, totalLevels * 2)) {
119
+ return darken(color, normalizeLevel({ factor, level: last(levels) }));
120
+ }
121
+ if (gte(index, totalLevels)) {
122
+ return darken(
123
+ color,
124
+ normalizeLevel({ factor, level: levels[totalLevels + 1 - index] })
125
+ );
126
+ }
127
+
128
+ return lighten(color, normalizeLevel({ factor, level: levels[index] }));
129
+ }
130
+
131
+ if (gte(index, totalLevels * 2)) {
132
+ return lighten(color, normalizeLevel({ factor, level: last(levels) }));
133
+ }
134
+ if (gte(index, totalLevels)) {
135
+ return lighten(
136
+ color,
137
+ normalizeLevel({ factor, level: levels[totalLevels + 1 - index] })
138
+ );
139
+ }
140
+
141
+ return darken(color, normalizeLevel({ factor, level: levels[index] }));
142
+ };