@centreon/ui 25.6.12 → 25.7.0

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.6.12",
3
+ "version": "25.7.0",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -1,5 +1,3 @@
1
- import { useRef } from 'react';
2
-
3
1
  import dayjs from 'dayjs';
4
2
  import 'dayjs/locale/en';
5
3
  import 'dayjs/locale/es';
@@ -12,12 +10,13 @@ import { Provider } from 'jotai';
12
10
 
13
11
  import { Box } from '@mui/material';
14
12
 
15
- import { ParentSize } from '../../ParentSize';
16
13
  import LoadingSkeleton from '../Chart/LoadingSkeleton';
17
14
  import { LineChartProps } from '../Chart/models';
18
15
  import useChartData from '../Chart/useChartData';
19
16
  import { LineChartData, Thresholds } from '../common/models';
17
+ import Loading from '../../LoadingSkeleton';
20
18
 
19
+ import useResizeObserver from 'use-resize-observer';
21
20
  import ResponsiveBarChart from './ResponsiveBarChart';
22
21
  import { BarStyle } from './models';
23
22
 
@@ -62,7 +61,7 @@ const BarChart = ({
62
61
  skipIntersectionObserver
63
62
  }: BarChartProps): JSX.Element => {
64
63
  const { adjustedData } = useChartData({ data, end, start });
65
- const lineChartRef = useRef<HTMLDivElement | null>(null);
64
+ const { ref, width, height: responsiveHeight } = useResizeObserver();
66
65
 
67
66
  if (loading && !adjustedData) {
68
67
  return (
@@ -75,30 +74,27 @@ const BarChart = ({
75
74
 
76
75
  return (
77
76
  <Provider>
78
- <Box
79
- ref={lineChartRef}
80
- sx={{ height: '100%', overflow: 'hidden', width: '100%' }}
81
- >
82
- <ParentSize>
83
- {({ height: responsiveHeight, width }) => (
84
- <ResponsiveBarChart
85
- axis={axis}
86
- barStyle={barStyle}
87
- graphData={adjustedData}
88
- graphRef={lineChartRef}
89
- header={header}
90
- height={height || responsiveHeight}
91
- legend={legend}
92
- limitLegend={limitLegend}
93
- orientation={orientation}
94
- thresholdUnit={thresholdUnit}
95
- thresholds={thresholds}
96
- tooltip={tooltip}
97
- width={width}
98
- skipIntersectionObserver={skipIntersectionObserver}
99
- />
100
- )}
101
- </ParentSize>
77
+ <Box ref={ref} sx={{ height: '100%', overflow: 'hidden', width: '100%' }}>
78
+ {!responsiveHeight ? (
79
+ <Loading height={height || '100%'} width={width} />
80
+ ) : (
81
+ <ResponsiveBarChart
82
+ axis={axis}
83
+ barStyle={barStyle}
84
+ graphData={adjustedData}
85
+ graphRef={ref}
86
+ header={header}
87
+ height={height || responsiveHeight || 0}
88
+ legend={legend}
89
+ limitLegend={limitLegend}
90
+ orientation={orientation}
91
+ thresholdUnit={thresholdUnit}
92
+ thresholds={thresholds}
93
+ tooltip={tooltip}
94
+ width={width || 0}
95
+ skipIntersectionObserver={skipIntersectionObserver}
96
+ />
97
+ )}
102
98
  </Box>
103
99
  </Provider>
104
100
  );
@@ -139,7 +139,7 @@ const initializeCustomUnits = ({
139
139
  const checkGraphWidth = (): void => {
140
140
  cy.findByTestId('graph-interaction-zone')
141
141
  .should('have.attr', 'height')
142
- .and('equal', '376.203125');
142
+ .and('equal', '376');
143
143
 
144
144
  cy.findByTestId('graph-interaction-zone').then((graph) => {
145
145
  expect(Number(graph[0].attributes.width.value)).to.be.greaterThan(1170);
@@ -437,7 +437,7 @@ describe('Line chart', () => {
437
437
 
438
438
  cy.contains(':00 AM').should('be.visible');
439
439
 
440
- cy.get('text[transform="rotate(-35, -2, 145.04834208635688)"]').should(
440
+ cy.get('text[transform="rotate(-35, -2, 241.23251487506278)"]').should(
441
441
  'be.visible'
442
442
  );
443
443
 
@@ -519,7 +519,7 @@ describe('Line chart', () => {
519
519
  checkGraphWidth();
520
520
  cy.contains(':00 AM').should('be.visible');
521
521
  cy.get('circle[cx="250.83333333333334"]').should('be.visible');
522
- cy.get('circle[cy="52.93597418085514"]').should('be.visible');
522
+ cy.get('circle[cy="52.90739222860398"]').should('be.visible');
523
523
 
524
524
  cy.makeSnapshot();
525
525
  });
@@ -733,10 +733,10 @@ describe('Lines and bars', () => {
733
733
  checkGraphWidth();
734
734
 
735
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"]'
736
+ 'path[d="M7.501377410468319,273.1948717814711 h56.51239669421488 h1v1 v100.80512821852892 a1,1 0 0 1 -1,1 h-56.51239669421488 a1,1 0 0 1 -1,-1 v-100.80512821852892 v-1h1z"]'
737
737
  ).should('be.visible');
738
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"]'
739
+ 'path[d="M24.05509641873278,218.2484747081302 h23.404958677685954 a17.553719008264462,17.553719008264462 0 0 1 17.553719008264462,17.553719008264462 v19.83895905681195 v17.553719008264462h-17.553719008264462 h-23.404958677685954 h-17.553719008264462v-17.553719008264462 v-19.83895905681195 a17.553719008264462,17.553719008264462 0 0 1 17.553719008264462,-17.553719008264462z"]'
740
740
  ).should('be.visible');
741
741
 
742
742
  cy.makeSnapshot();
@@ -1,4 +1,4 @@
1
- import { type MutableRefObject, memo, useEffect, useRef } from 'react';
1
+ import { RefCallback, memo, useEffect } from 'react';
2
2
 
3
3
  import dayjs from 'dayjs';
4
4
  import 'dayjs/locale/en';
@@ -8,11 +8,10 @@ import 'dayjs/locale/pt';
8
8
  import localizedFormat from 'dayjs/plugin/localizedFormat';
9
9
  import timezonePlugin from 'dayjs/plugin/timezone';
10
10
  import utcPlugin from 'dayjs/plugin/utc';
11
-
12
- import { ParentSize } from '../..';
13
11
  import Loading from '../../LoadingSkeleton';
14
12
  import type { LineChartData, Thresholds } from '../common/models';
15
13
 
14
+ import useResizeObserver from 'use-resize-observer';
16
15
  import Chart from './Chart';
17
16
  import { useChartStyles } from './Chart.styles';
18
17
  import LoadingSkeleton from './LoadingSkeleton';
@@ -32,7 +31,7 @@ interface Props extends Partial<LineChartProps> {
32
31
  start: string;
33
32
  thresholdUnit?: string;
34
33
  thresholds?: Thresholds;
35
- getRef?: (ref: MutableRefObject<HTMLDivElement | null>) => void;
34
+ getRef?: (ref: RefCallback<Element>) => void;
36
35
  containerStyle?: string;
37
36
  transformMatrix?: {
38
37
  fx?: (pointX: number) => number;
@@ -76,11 +75,15 @@ const WrapperChart = ({
76
75
  const { classes, cx } = useChartStyles();
77
76
 
78
77
  const { adjustedData } = useChartData({ data, end, start });
79
- const lineChartRef = useRef<HTMLDivElement | null>(null);
78
+ const {
79
+ ref,
80
+ width: responsiveWidth,
81
+ height: responsiveHeight
82
+ } = useResizeObserver();
80
83
 
81
84
  useEffect(() => {
82
- getRef?.(lineChartRef);
83
- }, [lineChartRef?.current]);
85
+ getRef?.(ref);
86
+ }, [ref?.current]);
84
87
 
85
88
  if (loading && !adjustedData) {
86
89
  return (
@@ -91,48 +94,39 @@ const WrapperChart = ({
91
94
  );
92
95
  }
93
96
 
94
- if (!adjustedData) {
95
- return <Loading height={height} width={width} />;
96
- }
97
-
98
97
  return (
99
98
  <div
100
- ref={lineChartRef as MutableRefObject<HTMLDivElement>}
99
+ ref={ref}
101
100
  className={cx(classes.wrapperContainer, rest?.containerStyle)}
102
101
  >
103
- <ParentSize>
104
- {({
105
- height: responsiveHeight,
106
- width: responsiveWidth
107
- }): JSX.Element => {
108
- return (
109
- <Chart
110
- annotationEvent={annotationEvent}
111
- axis={axis}
112
- barStyle={barStyle}
113
- displayAnchor={displayAnchor}
114
- graphData={adjustedData}
115
- graphInterval={{ end, start }}
116
- graphRef={lineChartRef}
117
- header={header}
118
- height={height || responsiveHeight}
119
- legend={legend}
120
- limitLegend={limitLegend}
121
- lineStyle={lineStyle}
122
- shapeLines={shapeLines}
123
- thresholdUnit={thresholdUnit}
124
- thresholds={thresholds}
125
- timeShiftZones={timeShiftZones}
126
- tooltip={tooltip}
127
- width={width ?? responsiveWidth}
128
- zoomPreview={zoomPreview}
129
- skipIntersectionObserver={rest.skipIntersectionObserver}
130
- additionalLines={additionalLines}
131
- transformMatrix={transformMatrix}
132
- />
133
- );
134
- }}
135
- </ParentSize>
102
+ {!responsiveHeight ? (
103
+ <Loading height={height || '100%'} width={width} />
104
+ ) : (
105
+ <Chart
106
+ annotationEvent={annotationEvent}
107
+ axis={axis}
108
+ barStyle={barStyle}
109
+ displayAnchor={displayAnchor}
110
+ graphData={adjustedData}
111
+ graphInterval={{ end, start }}
112
+ graphRef={ref}
113
+ header={header}
114
+ height={height || responsiveHeight || 0}
115
+ legend={legend}
116
+ limitLegend={limitLegend}
117
+ lineStyle={lineStyle}
118
+ shapeLines={shapeLines}
119
+ thresholdUnit={thresholdUnit}
120
+ thresholds={thresholds}
121
+ timeShiftZones={timeShiftZones}
122
+ tooltip={tooltip}
123
+ width={width || responsiveWidth || 0}
124
+ zoomPreview={zoomPreview}
125
+ skipIntersectionObserver={rest.skipIntersectionObserver}
126
+ additionalLines={additionalLines}
127
+ transformMatrix={transformMatrix}
128
+ />
129
+ )}
136
130
  </div>
137
131
  );
138
132
  };
@@ -1,7 +1,8 @@
1
- import { MutableRefObject, useRef } from 'react';
1
+ import { RefCallback } from 'react';
2
2
 
3
3
  import { equals, isNil } from 'ramda';
4
4
 
5
+ import useResizeObserver from 'use-resize-observer';
5
6
  import { margin } from '../../Chart/common';
6
7
  import { margins } from '../margins';
7
8
 
@@ -20,8 +21,8 @@ interface UseComputeBaseChartDimensionsProps {
20
21
  interface UseComputeBaseChartDimensionsState {
21
22
  graphHeight: number;
22
23
  graphWidth: number;
23
- legendRef: MutableRefObject<HTMLDivElement | null>;
24
- titleRef: MutableRefObject<HTMLDivElement | null>;
24
+ legendRef: RefCallback<Element>;
25
+ titleRef: RefCallback<Element>;
25
26
  }
26
27
 
27
28
  export const useComputeBaseChartDimensions = ({
@@ -33,11 +34,14 @@ export const useComputeBaseChartDimensions = ({
33
34
  legendHeight,
34
35
  maxAxisCharacters
35
36
  }: UseComputeBaseChartDimensionsProps): UseComputeBaseChartDimensionsState => {
36
- const legendRef = useRef<HTMLDivElement | null>(null);
37
- const titleRef = useRef<HTMLDivElement | null>(null);
37
+ const {
38
+ ref: legendRef,
39
+ width: legendRefWidth,
40
+ height: legendRefHeight
41
+ } = useResizeObserver();
42
+ const { ref: titleRef, height: titleRefHeight } = useResizeObserver();
38
43
 
39
- const currentLegendHeight =
40
- legendHeight ?? (legendRef.current?.getBoundingClientRect().height || 0);
44
+ const currentLegendHeight = legendHeight ?? (legendRefHeight || 0);
41
45
 
42
46
  const legendBoundingHeight =
43
47
  !equals(legendDisplay, false) &&
@@ -47,7 +51,7 @@ export const useComputeBaseChartDimensions = ({
47
51
  const legendBoundingWidth =
48
52
  !equals(legendDisplay, false) &&
49
53
  (equals(legendPlacement, 'left') || equals(legendPlacement, 'right'))
50
- ? legendRef.current?.getBoundingClientRect().width || 0
54
+ ? legendRefWidth || 0
51
55
  : 0;
52
56
 
53
57
  const graphWidth =
@@ -62,7 +66,7 @@ export const useComputeBaseChartDimensions = ({
62
66
  ? (height || 0) -
63
67
  margin.top -
64
68
  legendBoundingHeight -
65
- (titleRef.current?.getBoundingClientRect().height || 0) -
69
+ (titleRefHeight || 0) -
66
70
  5
67
71
  : 0;
68
72
 
@@ -1,4 +1,4 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useCallback, useEffect, useState } from 'react';
2
2
 
3
3
  import {
4
4
  equals,
@@ -17,7 +17,7 @@ import {
17
17
  import { CircularProgress, useTheme } from '@mui/material';
18
18
 
19
19
  import { Props as AutocompleteFieldProps } from '..';
20
- import { ListingModel, SelectEntry } from '../../../..';
20
+ import { ListingModel, ListingMapModel, SelectEntry } from '../../../..';
21
21
  import {
22
22
  ConditionsSearchParameter,
23
23
  SearchParameter
@@ -30,6 +30,12 @@ import {
30
30
  } from '../../../../utils';
31
31
  import Option from '../../Option';
32
32
 
33
+ interface OptionResult<T> {
34
+ result: Array<T>;
35
+ limit: number;
36
+ total: number;
37
+ }
38
+
33
39
  export interface ConnectedAutoCompleteFieldProps<TData> {
34
40
  allowUniqOption?: boolean;
35
41
  baseEndpoint?: string;
@@ -91,7 +97,7 @@ const ConnectedAutocompleteField = (
91
97
  const theme = useTheme();
92
98
 
93
99
  const { fetchQuery, isFetching, prefetchNextPage, data } = useFetchQuery<
94
- ListingModel<TData>
100
+ ListingModel<TData> | ListingMapModel<TData>
95
101
  >({
96
102
  decoder,
97
103
  baseEndpoint,
@@ -116,6 +122,27 @@ const ConnectedAutocompleteField = (
116
122
  }
117
123
  });
118
124
 
125
+ const getOptionResult = useCallback((
126
+ newOptions: ListingModel<TData> | ListingMapModel<TData>
127
+ ): OptionResult<TData> => {
128
+ if ('result' in newOptions) return {
129
+ result: newOptions.result || [],
130
+ total: newOptions.meta.total || 1,
131
+ limit: newOptions.meta.limit || 1,
132
+ };
133
+ if ('content' in newOptions) return {
134
+ result: newOptions.content || [],
135
+ total: newOptions.totalElements || 1,
136
+ limit: newOptions.size || 1,
137
+ };
138
+
139
+ return {
140
+ result: [],
141
+ total: 1,
142
+ limit: 1,
143
+ }
144
+ }, []);
145
+
119
146
  const lastOptionRef = useIntersectionObserver({
120
147
  action: () => setPage(page + 1),
121
148
  loading: isFetching,
@@ -245,12 +272,14 @@ const ConnectedAutocompleteField = (
245
272
 
246
273
  const moreOptions = page > 1 ? options : [];
247
274
 
275
+ const { result, limit, total } = getOptionResult(newOptions);
276
+
248
277
  const formattedList = changeIdValue
249
- ? newOptions.result.map((item) => ({
278
+ ? result.map((item) => ({
250
279
  ...item,
251
280
  id: changeIdValue(item)
252
281
  }))
253
- : newOptions.result;
282
+ : result;
254
283
 
255
284
  if (!isEmpty(labelKey) && !isNil(labelKey)) {
256
285
  const list = formattedList.map((item) =>
@@ -264,9 +293,6 @@ const ConnectedAutocompleteField = (
264
293
 
265
294
  setOptions(moreOptions.concat(formattedList as Array<TData>));
266
295
 
267
- const total = prop('total', newOptions.meta) || 1;
268
- const limit = prop('limit', newOptions.meta) || 1;
269
-
270
296
  const newMaxPage = Math.ceil(total / limit);
271
297
 
272
298
  setMaxPage(newMaxPage);
@@ -325,7 +351,7 @@ const ConnectedAutocompleteField = (
325
351
 
326
352
  return (
327
353
  <AutocompleteField
328
- total={data?.meta.total}
354
+ total={data?.meta?.total || data?.totalElements || 1}
329
355
  filterOptions={(opt): SelectEntry => opt}
330
356
  loading={isFetching}
331
357
  options={
@@ -516,7 +516,7 @@ const Listing = <
516
516
  <div className="w-full h-[3px]" />
517
517
  )}
518
518
  <div
519
- className="bg-[none] flex-column h-full w-full"
519
+ className="bg-[none] flex flex-col h-full w-full"
520
520
  ref={containerRef as RefObject<HTMLDivElement>}
521
521
  >
522
522
  {isActionBarVisible && (
package/src/api/models.ts CHANGED
@@ -8,3 +8,12 @@ export interface Listing<TEntity> {
8
8
  meta: ListingMeta;
9
9
  result: Array<TEntity>;
10
10
  }
11
+
12
+ export interface ListingMap<TEntity> {
13
+ content: Array<TEntity>;
14
+ totalPages: number;
15
+ totalElements: number;
16
+ size: number;
17
+ number: number;
18
+ numberOfElements: number;
19
+ }
@@ -6,6 +6,7 @@ const useStyles = makeStyles()((theme) => ({
6
6
  flexDirection: 'row'
7
7
  },
8
8
  dataTableEmptyState: {
9
+ marginTop: theme.spacing(3),
9
10
  alignItems: 'center',
10
11
  display: 'flex',
11
12
  flexDirection: 'column',
@@ -21,7 +22,8 @@ const useStyles = makeStyles()((theme) => ({
21
22
  width: '100%'
22
23
  },
23
24
  description: {
24
- maxWidth: '65%'
25
+ maxWidth: '65%',
26
+ textAlign: 'center'
25
27
  }
26
28
  }));
27
29
 
@@ -90,6 +90,10 @@ const useStyles = makeStyles<{
90
90
  gap: theme.spacing(2),
91
91
 
92
92
  justifyContent: 'space-between'
93
+ },
94
+ modalTitle: {
95
+ fontSize: theme.typography.h5.fontSize,
96
+ fontWeight: theme.typography.fontWeightBold
93
97
  }
94
98
  }));
95
99
 
@@ -16,7 +16,7 @@ const ModalHeader = ({
16
16
 
17
17
  return (
18
18
  <div className={classes.modalHeader}>
19
- <MuiDialogTitle color="primary" {...rest}>
19
+ <MuiDialogTitle color="primary" className={classes.modalTitle} {...rest}>
20
20
  {children}
21
21
  </MuiDialogTitle>
22
22
  </div>
package/src/index.ts CHANGED
@@ -72,6 +72,7 @@ export { default as StatusChip } from './StatusChip';
72
72
  export type { Props as StatusChipProps } from './StatusChip';
73
73
 
74
74
  export type { Listing as ListingModel } from './api/models';
75
+ export type { ListingMap as ListingMapModel } from './api/models';
75
76
 
76
77
  export { default as useCancelTokenSource } from './api/useCancelTokenSource';
77
78
  export { getData, patchData, postData, putData, deleteData } from './api';