@centreon/ui 25.11.0 → 25.11.2

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.11.0",
3
+ "version": "25.11.2",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -90,7 +90,7 @@
90
90
  "@vitejs/plugin-react": "^4.3.4",
91
91
  "@vitejs/plugin-react-swc": "^3.8.0",
92
92
  "chai": "^5.2.0",
93
- "cypress": "^14.1.0",
93
+ "cypress": "^15.5.0",
94
94
  "identity-obj-proxy": "^3.0.0",
95
95
  "jest-transform-stub": "^2.0.0",
96
96
  "mochawesome": "^7.1.3",
@@ -55,12 +55,14 @@ interface Props {
55
55
  dataTestId?: string;
56
56
  disabled?: boolean;
57
57
  label: string;
58
+ id: string;
58
59
  labelPlacement?: LabelPlacement;
59
60
  labelProps?: TypographyProps;
60
61
  onChange?: (e) => void;
61
62
  }
62
63
 
63
64
  const Checkbox = ({
65
+ id,
64
66
  Icon,
65
67
  checked,
66
68
  label,
@@ -86,7 +88,7 @@ const Checkbox = ({
86
88
  className={classes.checkbox}
87
89
  color="primary"
88
90
  disabled={disabled}
89
- id={label}
91
+ id={id}
90
92
  size="small"
91
93
  sx={{ padding: 0 }}
92
94
  onChange={onChange}
@@ -6,6 +6,8 @@ import { TypographyProps } from '@mui/material/Typography';
6
6
 
7
7
  import Checkbox, { LabelPlacement } from '../Checkbox';
8
8
 
9
+ import { useTranslation } from 'react-i18next';
10
+
9
11
  interface Props {
10
12
  className?: string;
11
13
  dataTestId?: string;
@@ -45,6 +47,8 @@ const CheckboxGroup = ({
45
47
  }: Props): JSX.Element => {
46
48
  const { classes, cx } = useStyles();
47
49
 
50
+ const { t } = useTranslation();
51
+
48
52
  const row = !equals(direction, 'vertical');
49
53
 
50
54
  return (
@@ -61,10 +65,11 @@ const CheckboxGroup = ({
61
65
  className={cx(classes.checkbox, className)}
62
66
  disabled={disabled}
63
67
  key={value}
64
- label={value}
68
+ label={t(value)}
65
69
  labelPlacement={labelPlacement}
66
70
  labelProps={labelProps}
67
71
  onChange={onChange}
72
+ id={value}
68
73
  />
69
74
  );
70
75
  })}
@@ -15,7 +15,8 @@ const Checkbox = ({
15
15
  fieldName,
16
16
  getDisabled,
17
17
  hideInput,
18
- dataTestId
18
+ dataTestId,
19
+ label
19
20
  }: InputPropsWithoutGroup): JSX.Element => {
20
21
  const { values, setFieldValue } = useFormikContext<FormikValues>();
21
22
 
@@ -45,7 +46,7 @@ const Checkbox = ({
45
46
  checked={value?.checked}
46
47
  dataTestId={dataTestId || ''}
47
48
  disabled={disabled}
48
- label={value?.label}
49
+ label={label}
49
50
  labelPlacement={checkbox?.labelPlacement || 'end'}
50
51
  onChange={handleChange}
51
52
  />
@@ -236,12 +236,12 @@ export const basicFormInputs: Array<InputProps> = [
236
236
  direction: 'horizontal'
237
237
  },
238
238
  fieldName: 'notifications.channels',
239
- label: 'channels',
239
+ label: 'mail',
240
240
  type: InputType.Checkbox
241
241
  },
242
242
  {
243
243
  fieldName: 'notifications.includeServices',
244
- label: 'Iclude services',
244
+ label: 'Include services for this host',
245
245
  type: InputType.Checkbox
246
246
  },
247
247
  {
@@ -16,6 +16,7 @@ import { LineChartProps } from '../Chart/models';
16
16
  import useChartData from '../Chart/useChartData';
17
17
  import { LineChartData, Thresholds } from '../common/models';
18
18
 
19
+ import { ReactElement } from 'react';
19
20
  import useResizeObserver from 'use-resize-observer';
20
21
  import ResponsiveBarChart from './ResponsiveBarChart';
21
22
  import { BarStyle } from './models';
@@ -36,6 +37,9 @@ export interface BarChartProps
36
37
  | 'min'
37
38
  | 'max'
38
39
  | 'boundariesUnit'
40
+ | 'timeShiftZones'
41
+ | 'zoomPreview'
42
+ | 'annotationEvent'
39
43
  >
40
44
  > {
41
45
  barStyle?: BarStyle;
@@ -71,8 +75,11 @@ const BarChart = ({
71
75
  skipIntersectionObserver,
72
76
  min,
73
77
  max,
74
- boundariesUnit
75
- }: BarChartProps): JSX.Element => {
78
+ boundariesUnit,
79
+ zoomPreview,
80
+ timeShiftZones,
81
+ annotationEvent
82
+ }: BarChartProps): ReactElement => {
76
83
  const { adjustedData } = useChartData({ data, end, start, min, max });
77
84
  const { ref, width, height: responsiveHeight } = useResizeObserver();
78
85
 
@@ -109,6 +116,11 @@ const BarChart = ({
109
116
  min={min}
110
117
  max={max}
111
118
  boundariesUnit={boundariesUnit}
119
+ zoomPreview={zoomPreview}
120
+ timeShiftZones={timeShiftZones}
121
+ annotationEvent={annotationEvent}
122
+ start={start}
123
+ end={end}
112
124
  />
113
125
  )}
114
126
  </Box>
@@ -1,12 +1,21 @@
1
- import { MutableRefObject, useEffect, useMemo, useRef, useState } from 'react';
1
+ import {
2
+ MutableRefObject,
3
+ ReactElement,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState
8
+ } from 'react';
2
9
 
3
- import { useAtom } from 'jotai';
10
+ import { useAtom, useAtomValue } from 'jotai';
4
11
  import { equals, flatten, gte, has, isNil, pluck } from 'ramda';
5
12
 
6
13
  import { Skeleton } from '@mui/material';
7
14
 
8
15
  import { Tooltip } from '../../components';
9
16
  import { useDeepCompare } from '../../utils';
17
+ import InteractionWithGraph from '../Chart/InteractiveComponents';
18
+ import { applyingZoomAtomAtom } from '../Chart/InteractiveComponents/ZoomPreview/zoomPreviewAtoms';
10
19
  import { margin } from '../Chart/common';
11
20
  import { Data, LineChartProps } from '../Chart/models';
12
21
  import { useIntersection } from '../Chart/useChartIntersection';
@@ -18,18 +27,29 @@ import Thresholds from '../common/Thresholds/Thresholds';
18
27
  import { Thresholds as ThresholdsModel } from '../common/models';
19
28
  import {
20
29
  getUnits,
30
+ getXScale,
21
31
  getXScaleBand,
22
32
  getYScalePerUnit
23
33
  } from '../common/timeSeries';
24
34
  import { Line } from '../common/timeSeries/models';
25
35
  import { useTooltipStyles } from '../common/useTooltipStyles';
36
+ import { computPixelsToShiftMouse } from '../common/utils';
26
37
  import BarGroup from './BarGroup';
27
38
  import BarChartTooltip from './Tooltip/BarChartTooltip';
28
39
  import { tooltipDataAtom } from './atoms';
29
40
  import { BarStyle } from './models';
30
41
 
31
42
  interface Props
32
- extends Pick<LineChartProps, 'tooltip' | 'legend' | 'axis' | 'header'> {
43
+ extends Pick<
44
+ LineChartProps,
45
+ | 'tooltip'
46
+ | 'legend'
47
+ | 'axis'
48
+ | 'header'
49
+ | 'zoomPreview'
50
+ | 'timeShiftZones'
51
+ | 'annotationEvent'
52
+ > {
33
53
  barStyle: BarStyle;
34
54
  graphData: Data;
35
55
  graphRef: MutableRefObject<HTMLDivElement | null>;
@@ -43,6 +63,8 @@ interface Props
43
63
  min?: number;
44
64
  max?: number;
45
65
  boundariesUnit?: string;
66
+ start: string;
67
+ end: string;
46
68
  }
47
69
 
48
70
  const ResponsiveBarChart = ({
@@ -62,8 +84,13 @@ const ResponsiveBarChart = ({
62
84
  skipIntersectionObserver,
63
85
  min,
64
86
  max,
65
- boundariesUnit
66
- }: Props): JSX.Element => {
87
+ boundariesUnit,
88
+ start,
89
+ end,
90
+ timeShiftZones,
91
+ zoomPreview,
92
+ annotationEvent
93
+ }: Props): ReactElement => {
67
94
  const { title, timeSeries, baseAxis, lines } = graphData || {};
68
95
 
69
96
  const { classes, cx } = useTooltipStyles();
@@ -72,6 +99,7 @@ const ResponsiveBarChart = ({
72
99
  const graphSvgRef = useRef<SVGSVGElement | null>(null);
73
100
 
74
101
  const [tooltipData, setTooltipData] = useAtom(tooltipDataAtom);
102
+ const isApplyingZoom = useAtomValue(applyingZoomAtomAtom);
75
103
 
76
104
  const { isInViewport } = useIntersection({ element: graphRef?.current });
77
105
 
@@ -125,6 +153,15 @@ const ResponsiveBarChart = ({
125
153
  [timeSeries, graphWidth, isHorizontal, graphHeight]
126
154
  );
127
155
 
156
+ const xScaleLinear = useMemo(
157
+ () =>
158
+ getXScale({
159
+ dataTime: timeSeries,
160
+ valueWidth: isHorizontal ? graphWidth : graphHeight - 30
161
+ }),
162
+ [timeSeries, graphWidth, isHorizontal, graphHeight]
163
+ );
164
+
128
165
  const yScalesPerUnit = useMemo(
129
166
  () =>
130
167
  getYScalePerUnit({
@@ -158,6 +195,7 @@ const ResponsiveBarChart = ({
158
195
 
159
196
  const leftScale = yScalesPerUnit[firstUnit];
160
197
  const rightScale = yScalesPerUnit[secondUnit];
198
+ const pixelsToShift = computPixelsToShiftMouse(xScaleLinear);
161
199
 
162
200
  useEffect(
163
201
  () => {
@@ -244,33 +282,97 @@ const ResponsiveBarChart = ({
244
282
  hasSecondUnit={Boolean(secondUnit)}
245
283
  >
246
284
  <>
247
- <BarGroup
248
- barStyle={barStyle}
249
- isTooltipHidden={isTooltipHidden}
250
- lines={displayedLines}
251
- orientation={isHorizontal ? 'horizontal' : 'vertical'}
252
- size={isHorizontal ? graphHeight - margin.top - 5 : graphWidth}
253
- timeSeries={timeSeries}
254
- xScale={xScale}
255
- yScalesPerUnit={yScalesPerUnit}
256
- scaleType={axis?.scale}
257
- />
258
- {thresholds?.enabled && (
259
- <Thresholds
260
- displayedLines={displayedLines}
261
- hideTooltip={() => setTooltipData(null)}
262
- isHorizontal={isHorizontal}
263
- showTooltip={({ tooltipData: thresholdLabel }) =>
264
- setTooltipData({
265
- thresholdLabel
266
- })
267
- }
268
- thresholdUnit={thresholdUnit}
269
- thresholds={thresholds as ThresholdsModel}
270
- width={isHorizontal ? graphWidth : graphHeight - margin.top}
271
- yScalesPerUnit={yScalesPerUnit}
285
+ {isApplyingZoom && (
286
+ <>
287
+ <BarGroup
288
+ barStyle={barStyle}
289
+ isTooltipHidden={isTooltipHidden}
290
+ lines={displayedLines}
291
+ orientation={isHorizontal ? 'horizontal' : 'vertical'}
292
+ size={
293
+ isHorizontal ? graphHeight - margin.top - 5 : graphWidth
294
+ }
295
+ timeSeries={timeSeries}
296
+ xScale={xScale}
297
+ yScalesPerUnit={yScalesPerUnit}
298
+ scaleType={axis?.scale}
299
+ />
300
+ {thresholds?.enabled && (
301
+ <Thresholds
302
+ displayedLines={displayedLines}
303
+ hideTooltip={() => setTooltipData(null)}
304
+ isHorizontal={isHorizontal}
305
+ showTooltip={({ tooltipData: thresholdLabel }) =>
306
+ setTooltipData({
307
+ thresholdLabel
308
+ })
309
+ }
310
+ thresholdUnit={thresholdUnit}
311
+ thresholds={thresholds as ThresholdsModel}
312
+ width={
313
+ isHorizontal ? graphWidth : graphHeight - margin.top
314
+ }
315
+ yScalesPerUnit={yScalesPerUnit}
316
+ />
317
+ )}
318
+ </>
319
+ )}
320
+ {isHorizontal && (
321
+ <InteractionWithGraph
322
+ additionalZoomMargin={pixelsToShift}
323
+ maxLeftAxisCharacters={maxLeftAxisCharacters}
324
+ commonData={{
325
+ graphHeight,
326
+ graphSvgRef,
327
+ graphWidth,
328
+ lines,
329
+ xScale: xScaleLinear,
330
+ timeSeries,
331
+ yScalesPerUnit
332
+ }}
333
+ annotationData={{ ...annotationEvent }}
334
+ zoomData={{ ...zoomPreview }}
335
+ timeShiftZonesData={{
336
+ ...timeShiftZones,
337
+ graphInterval: { start, end }
338
+ }}
272
339
  />
273
340
  )}
341
+ {!isApplyingZoom && (
342
+ <>
343
+ <BarGroup
344
+ barStyle={barStyle}
345
+ isTooltipHidden={isTooltipHidden}
346
+ lines={displayedLines}
347
+ orientation={isHorizontal ? 'horizontal' : 'vertical'}
348
+ size={
349
+ isHorizontal ? graphHeight - margin.top - 5 : graphWidth
350
+ }
351
+ timeSeries={timeSeries}
352
+ xScale={xScale}
353
+ yScalesPerUnit={yScalesPerUnit}
354
+ scaleType={axis?.scale}
355
+ />
356
+ {thresholds?.enabled && (
357
+ <Thresholds
358
+ displayedLines={displayedLines}
359
+ hideTooltip={() => setTooltipData(null)}
360
+ isHorizontal={isHorizontal}
361
+ showTooltip={({ tooltipData: thresholdLabel }) =>
362
+ setTooltipData({
363
+ thresholdLabel
364
+ })
365
+ }
366
+ thresholdUnit={thresholdUnit}
367
+ thresholds={thresholds as ThresholdsModel}
368
+ width={
369
+ isHorizontal ? graphWidth : graphHeight - margin.top
370
+ }
371
+ yScalesPerUnit={yScalesPerUnit}
372
+ />
373
+ )}
374
+ </>
375
+ )}
274
376
  </>
275
377
  </ChartSvgWrapper>
276
378
  </div>
@@ -4,18 +4,29 @@ import { alpha, useTheme } from '@mui/system';
4
4
 
5
5
  import Bar from '../Bar';
6
6
 
7
+ import { margin } from '../../common';
7
8
  import { ZoomPreviewData } from './models';
8
9
  import useZoomPreview from './useZoomPreview';
9
10
 
10
11
  const ZoomPreview = (data: ZoomPreviewData): JSX.Element => {
11
12
  const theme = useTheme();
12
13
 
13
- const { graphHeight, xScale, graphWidth, getInterval, ...rest } = data;
14
+ const {
15
+ graphHeight,
16
+ xScale,
17
+ graphWidth,
18
+ getInterval,
19
+ graphSvgRef,
20
+ graphMarginLeft,
21
+ ...rest
22
+ } = data;
14
23
 
15
24
  const { zoomBarWidth, zoomBoundaries } = useZoomPreview({
16
25
  getInterval,
17
26
  graphWidth,
18
- xScale
27
+ xScale,
28
+ graphSvgRef,
29
+ graphMarginLeft
19
30
  });
20
31
 
21
32
  const restData = omit(['enable'], { ...rest });
@@ -24,7 +35,7 @@ const ZoomPreview = (data: ZoomPreviewData): JSX.Element => {
24
35
  <g>
25
36
  <Bar
26
37
  fill={alpha(theme.palette.primary.main, 0.2)}
27
- height={graphHeight}
38
+ height={graphHeight - margin.bottom}
28
39
  stroke={alpha(theme.palette.primary.main, 0.5)}
29
40
  width={zoomBarWidth}
30
41
  x={zoomBoundaries?.start || 0}
@@ -1,9 +1,12 @@
1
1
  import { ScaleTime } from 'd3-scale';
2
2
 
3
+ import { RefObject } from 'react';
3
4
  import { InteractedZone } from '../../models';
4
5
 
5
6
  export interface ZoomPreviewData extends InteractedZone {
6
7
  graphHeight: number;
7
8
  graphWidth: number;
8
9
  xScale: ScaleTime<number, number>;
10
+ graphSvgRef: RefObject<SVGSVGElement | null>;
11
+ graphMarginLeft: number;
9
12
  }
@@ -1,18 +1,15 @@
1
- import { useEffect, useState } from 'react';
1
+ import { RefObject, useEffect, useState } from 'react';
2
2
 
3
3
  import { Event } from '@visx/visx';
4
4
  import { ScaleTime } from 'd3-scale';
5
5
  import { useAtomValue, useSetAtom } from 'jotai';
6
6
  import { equals, gte, isNil, lt } from 'ramda';
7
-
8
- import { margin } from '../../common';
9
7
  import { Interval } from '../../models';
10
8
  import {
11
9
  eventMouseDownAtom,
12
10
  eventMouseUpAtom,
13
11
  mousePositionAtom
14
12
  } from '../interactionWithGraphAtoms';
15
-
16
13
  import { applyingZoomAtomAtom } from './zoomPreviewAtoms';
17
14
 
18
15
  interface Boundaries {
@@ -28,12 +25,16 @@ interface Props {
28
25
  getInterval?: (args: Interval) => void;
29
26
  graphWidth: number;
30
27
  xScale: ScaleTime<number, number>;
28
+ graphSvgRef: RefObject<SVGSVGElement | null>;
29
+ graphMarginLeft: number;
31
30
  }
32
31
 
33
32
  const useZoomPreview = ({
34
33
  xScale,
35
34
  graphWidth,
36
- getInterval
35
+ getInterval,
36
+ graphSvgRef,
37
+ graphMarginLeft
37
38
  }: Props): ZoomPreview => {
38
39
  const [zoomBoundaries, setZoomBoundaries] = useState<Boundaries | null>(null);
39
40
  const eventMouseDown = useAtomValue(eventMouseDownAtom);
@@ -41,16 +42,17 @@ const useZoomPreview = ({
41
42
  const mousePosition = useAtomValue(mousePositionAtom);
42
43
  const setApplyingZoom = useSetAtom(applyingZoomAtomAtom);
43
44
 
44
- const mousePointDown = eventMouseDown
45
- ? Event.localPoint(eventMouseDown)
46
- : null;
45
+ const mousePointDown =
46
+ eventMouseDown && graphSvgRef.current
47
+ ? Event.localPoint(graphSvgRef.current, eventMouseDown)
48
+ : null;
47
49
 
48
50
  const mouseDownPositionX = mousePointDown
49
- ? mousePointDown.x - margin.left
51
+ ? mousePointDown.x - graphMarginLeft
50
52
  : null;
51
53
 
52
54
  const movingMousePositionX = mousePosition
53
- ? mousePosition[0] - margin.left
55
+ ? mousePosition[0] - graphMarginLeft
54
56
  : null;
55
57
 
56
58
  const applyZoom = (): void => {
@@ -1,4 +1,4 @@
1
- import type { MutableRefObject } from 'react';
1
+ import { type MutableRefObject, ReactElement, useMemo } from 'react';
2
2
 
3
3
  import { Event } from '@visx/visx';
4
4
  import type { ScaleLinear, ScaleTime } from 'd3-scale';
@@ -88,6 +88,7 @@ interface Props {
88
88
  };
89
89
  hasSecondUnit?: boolean;
90
90
  maxLeftAxisCharacters: number;
91
+ additionalZoomMargin?: number;
91
92
  }
92
93
 
93
94
  const InteractionWithGraph = ({
@@ -97,8 +98,9 @@ const InteractionWithGraph = ({
97
98
  timeShiftZonesData,
98
99
  transformMatrix,
99
100
  hasSecondUnit,
100
- maxLeftAxisCharacters
101
- }: Props): JSX.Element => {
101
+ maxLeftAxisCharacters,
102
+ additionalZoomMargin = 0
103
+ }: Props): ReactElement => {
102
104
  const { classes } = useStyles();
103
105
 
104
106
  const setEventMouseDown = useSetAtom(eventMouseDownAtom);
@@ -152,6 +154,15 @@ const InteractionWithGraph = ({
152
154
  setEventMouseDown(event);
153
155
  };
154
156
 
157
+ const graphMarginLeft = useMemo(
158
+ () =>
159
+ computeGElementMarginLeft({
160
+ maxCharacters: maxLeftAxisCharacters,
161
+ hasSecondUnit
162
+ }) + additionalZoomMargin,
163
+ [additionalZoomMargin, maxLeftAxisCharacters, hasSecondUnit]
164
+ );
165
+
155
166
  const updateMousePosition = (pointPosition: MousePosition): void => {
156
167
  if (isNil(pointPosition)) {
157
168
  changeMousePosition({
@@ -166,10 +177,7 @@ const InteractionWithGraph = ({
166
177
  timeSeries,
167
178
  x: pointPosition[0] - pixelToShift,
168
179
  xScale,
169
- marginLeft: computeGElementMarginLeft({
170
- maxCharacters: maxLeftAxisCharacters,
171
- hasSecondUnit
172
- })
180
+ marginLeft: graphMarginLeft
173
181
  });
174
182
 
175
183
  if (isNil(timeValue)) {
@@ -296,6 +304,8 @@ const InteractionWithGraph = ({
296
304
  graphHeight={graphHeight}
297
305
  graphWidth={graphWidth}
298
306
  xScale={xScale}
307
+ graphSvgRef={graphSvgRef}
308
+ graphMarginLeft={graphMarginLeft}
299
309
  />
300
310
  )}
301
311
  {displayEventAnnotations && (