@centreon/ui 25.10.9 → 25.10.10

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.
Files changed (40) hide show
  1. package/package.json +1 -1
  2. package/public/mockServiceWorker.js +8 -31
  3. package/src/Form/Inputs/ConnectedAutocomplete.tsx +2 -0
  4. package/src/Form/Inputs/Grid.tsx +2 -3
  5. package/src/Form/Inputs/models.ts +2 -0
  6. package/src/Form/Section/navigateToSection.ts +6 -6
  7. package/src/Graph/BarChart/BarChart.cypress.spec.tsx +55 -92
  8. package/src/Graph/BarChart/BarChart.stories.tsx +1 -42
  9. package/src/Graph/BarChart/BarChart.tsx +1 -1
  10. package/src/Graph/BarChart/BarStack.tsx +26 -15
  11. package/src/Graph/BarChart/MemoizedGroup.tsx +8 -7
  12. package/src/Graph/BarChart/ResponsiveBarChart.tsx +1 -2
  13. package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +5 -4
  14. package/src/Graph/Chart/BasicComponents/Lines/index.tsx +94 -94
  15. package/src/Graph/Chart/Chart.cypress.spec.tsx +6 -25
  16. package/src/Graph/Chart/Chart.stories.tsx +1 -34
  17. package/src/Graph/Chart/Chart.tsx +6 -5
  18. package/src/Graph/Chart/Legend/index.tsx +2 -26
  19. package/src/Graph/Chart/models.ts +1 -6
  20. package/src/Graph/Chart/useChartData.ts +1 -1
  21. package/src/Graph/common/BaseChart/BaseChart.tsx +1 -6
  22. package/src/Graph/common/BaseChart/Header/index.tsx +3 -1
  23. package/src/Graph/common/timeSeries/index.test.ts +4 -4
  24. package/src/Graph/common/timeSeries/index.ts +77 -73
  25. package/src/Graph/common/utils.ts +4 -10
  26. package/src/Graph/index.ts +1 -0
  27. package/src/InputField/Select/Autocomplete/Connected/index.tsx +7 -7
  28. package/src/InputField/Select/Autocomplete/Multi/Multi.tsx +1 -1
  29. package/src/InputField/Select/Autocomplete/index.tsx +28 -17
  30. package/src/InputField/Select/Option.tsx +3 -3
  31. package/src/InputField/Select/index.tsx +2 -1
  32. package/src/Module/index.tsx +2 -8
  33. package/src/ThemeProvider/index.tsx +21 -30
  34. package/src/ThemeProvider/tailwindcss.css +10 -10
  35. package/src/components/Form/AccessRights/ShareInput/ShareInput.tsx +4 -3
  36. package/src/components/Form/AccessRights/ShareInput/useShareInput.tsx +15 -10
  37. package/src/components/Menu/Button/MenuButton.tsx +1 -2
  38. package/src/components/Modal/Modal.styles.ts +2 -1
  39. package/src/components/Modal/ModalHeader.tsx +1 -5
  40. package/src/Graph/mockedData/dataWithMissingPoint.json +0 -74
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "25.10.9",
3
+ "version": "25.10.10",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -8,8 +8,8 @@
8
8
  * - Please do NOT serve this file on production.
9
9
  */
10
10
 
11
- const PACKAGE_VERSION = '2.7.3'
12
- const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f'
11
+ const PACKAGE_VERSION = '2.2.14'
12
+ const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
13
13
  const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
14
14
  const activeClientIds = new Set()
15
15
 
@@ -62,12 +62,7 @@ self.addEventListener('message', async function (event) {
62
62
 
63
63
  sendToClient(client, {
64
64
  type: 'MOCKING_ENABLED',
65
- payload: {
66
- client: {
67
- id: client.id,
68
- frameType: client.frameType,
69
- },
70
- },
65
+ payload: true,
71
66
  })
72
67
  break
73
68
  }
@@ -160,10 +155,6 @@ async function handleRequest(event, requestId) {
160
155
  async function resolveMainClient(event) {
161
156
  const client = await self.clients.get(event.clientId)
162
157
 
163
- if (activeClientIds.has(event.clientId)) {
164
- return client
165
- }
166
-
167
158
  if (client?.frameType === 'top-level') {
168
159
  return client
169
160
  }
@@ -192,26 +183,12 @@ async function getResponse(event, client, requestId) {
192
183
  const requestClone = request.clone()
193
184
 
194
185
  function passthrough() {
195
- // Cast the request headers to a new Headers instance
196
- // so the headers can be manipulated with.
197
- const headers = new Headers(requestClone.headers)
198
-
199
- // Remove the "accept" header value that marked this request as passthrough.
200
- // This prevents request alteration and also keeps it compliant with the
201
- // user-defined CORS policies.
202
- const acceptHeader = headers.get('accept')
203
- if (acceptHeader) {
204
- const values = acceptHeader.split(',').map((value) => value.trim())
205
- const filteredValues = values.filter(
206
- (value) => value !== 'msw/passthrough',
207
- )
186
+ const headers = Object.fromEntries(requestClone.headers.entries())
208
187
 
209
- if (filteredValues.length > 0) {
210
- headers.set('accept', filteredValues.join(', '))
211
- } else {
212
- headers.delete('accept')
213
- }
214
- }
188
+ // Remove internal MSW request header so the passthrough request
189
+ // complies with any potential CORS preflight checks on the server.
190
+ // Some servers forbid unknown request headers.
191
+ delete headers['x-msw-intention']
215
192
 
216
193
  return fetch(requestClone, { headers })
217
194
  }
@@ -137,6 +137,8 @@ const ConnectedAutocomplete = ({
137
137
  getEndpoint={getEndpoint}
138
138
  decoder={connectedAutocomplete?.decoder}
139
139
  getRenderedOptionText={connectedAutocomplete?.getRenderedOptionText}
140
+ getOptionLabel={connectedAutocomplete?.getOptionLabel}
141
+ optionProperty={connectedAutocomplete?.optionProperty}
140
142
  initialPage={1}
141
143
  isOptionEqualToValue={isOptionEqualToValue}
142
144
  label={t(label)}
@@ -21,9 +21,8 @@ const Grid = ({
21
21
  <div
22
22
  className={`${className} grid gap-3`}
23
23
  style={{
24
- gridTemplateColumns: className
25
- ? grid?.gridTemplateColumns || undefined
26
- : grid?.gridTemplateColumns ||
24
+ gridTemplateColumns:
25
+ className ? grid?.gridTemplateColumns || undefined : grid?.gridTemplateColumns ||
27
26
  `repeat(${grid?.columns.length || 1}, 1fr)`,
28
27
  alignItems: grid?.alignItems || 'flex-start'
29
28
  }}
@@ -62,6 +62,8 @@ export interface InputProps {
62
62
  endpoint?: string;
63
63
  filterKey?: string;
64
64
  getRenderedOptionText?: (option) => string | JSX.Element;
65
+ getOptionLabel?: (option) => string;
66
+ optionProperty?: string;
65
67
  disableSelectAll?: boolean;
66
68
  limitTags?: number;
67
69
  decoder?;
@@ -1,9 +1,9 @@
1
1
  export const useNavigateToSection = () => {
2
- return (sectionName: string) => {
3
- const section = document.querySelector(
4
- `[data-section-group-form-id="${sectionName}"]`
5
- );
2
+ return (sectionName: string) => {
3
+ const section = document.querySelector(
4
+ `[data-section-group-form-id="${sectionName}"]`
5
+ );
6
6
 
7
- section?.scrollIntoView({ behavior: 'smooth' });
8
- };
7
+ section?.scrollIntoView({ behavior: 'smooth' });
8
+ };
9
9
  };
@@ -8,7 +8,6 @@ import dataLastWeek from '../mockedData/lastWeek.json';
8
8
  import dataPingService from '../mockedData/pingService.json';
9
9
  import dataPingServiceMixedStacked from '../mockedData/pingServiceMixedStacked.json';
10
10
  import dataPingServiceStacked from '../mockedData/pingServiceStacked.json';
11
- import dataMissingPoint from '../mockedData/dataWithMissingPoint.json';
12
11
 
13
12
  import BarChart, { BarChartProps } from './BarChart';
14
13
 
@@ -85,6 +84,61 @@ const checkWidth = (orientation): void => {
85
84
  };
86
85
 
87
86
  describe('Bar chart', () => {
87
+ it('displays a tooltip when a single bar is hovered', () => {
88
+ initialize({
89
+ orientation: 'horizontal'
90
+ });
91
+
92
+ checkWidth('horizontal');
93
+ cy.contains('0 ms').should('be.visible');
94
+ cy.contains('20').should('be.visible');
95
+ cy.contains(':40 AM').should('be.visible');
96
+
97
+ cy.findByTestId('stacked-bar-10-0-7650.368581547736').realHover();
98
+
99
+ cy.contains('06/19/2024').should('be.visible');
100
+ cy.contains('Centreon-Server: Round-Trip Maximum Time').should(
101
+ 'be.visible'
102
+ );
103
+ cy.contains('7.47 KiB').should('be.visible');
104
+
105
+ cy.makeSnapshot();
106
+ });
107
+
108
+ it('displays a tooltip when a stacked bar is hovered', () => {
109
+ initialize({
110
+ data: dataPingServiceStacked,
111
+ orientation: 'horizontal',
112
+ tooltip: {
113
+ mode: 'all',
114
+ sortOrder: 'ascending'
115
+ }
116
+ });
117
+
118
+ checkWidth('horizontal');
119
+ cy.contains('0 ms').should('be.visible');
120
+ cy.contains('20').should('be.visible');
121
+ cy.contains(':40 AM').should('be.visible');
122
+
123
+ cy.findByTestId('stacked-bar-1-0-0.05296').realHover();
124
+
125
+ cy.contains('06/19/2024').should('be.visible');
126
+ cy.contains('Centreon-Server: Round-Trip Maximum Time').should(
127
+ 'be.visible'
128
+ );
129
+ cy.contains('Centreon-Server: Round-Trip Average Time').should(
130
+ 'be.visible'
131
+ );
132
+ cy.contains('Centreon-Server: Round-Trip Minimum Time').should(
133
+ 'be.visible'
134
+ );
135
+ cy.contains('0.05 ms').should('be.visible');
136
+ cy.contains('0.02 ms').should('be.visible');
137
+ cy.contains('0.11 ms').should('be.visible');
138
+
139
+ cy.findByTestId('stacked-bar-3-0-0.16196').should('be.visible');
140
+ });
141
+
88
142
  ['horizontal', 'vertical'].forEach((orientation) => {
89
143
  it(`displays the bar chart ${orientation}ly`, () => {
90
144
  initialize({ orientation });
@@ -184,27 +238,6 @@ describe('Bar chart', () => {
184
238
  });
185
239
  });
186
240
 
187
- it('displays a tooltip when a single bar is hovered', () => {
188
- initialize({
189
- orientation: 'horizontal'
190
- });
191
-
192
- checkWidth('horizontal');
193
- cy.contains('0 ms').should('be.visible');
194
- cy.contains('20').should('be.visible');
195
- cy.contains(':40 AM').should('be.visible');
196
-
197
- cy.findByTestId('stacked-bar-10-0-7650.368581547736').realHover();
198
-
199
- cy.contains('06/19/2024').should('be.visible');
200
- cy.contains('Centreon-Server: Round-Trip Maximum Time').should(
201
- 'be.visible'
202
- );
203
- cy.contains('7.47 KB').should('be.visible');
204
-
205
- cy.makeSnapshot();
206
- });
207
-
208
241
  it('does not display a tooltip when a bar is hovered and a props is set', () => {
209
242
  initialize({
210
243
  data: dataPingServiceStacked,
@@ -229,68 +262,6 @@ describe('Bar chart', () => {
229
262
  cy.makeSnapshot();
230
263
  });
231
264
 
232
- it('displays a tooltip when a stacked bar is hovered', () => {
233
- initialize({
234
- data: dataPingServiceStacked,
235
- orientation: 'horizontal',
236
- tooltip: {
237
- mode: 'all',
238
- sortOrder: 'ascending'
239
- }
240
- });
241
-
242
- checkWidth('horizontal');
243
- cy.contains('0 ms').should('be.visible');
244
- cy.contains('20').should('be.visible');
245
- cy.contains(':40 AM').should('be.visible');
246
-
247
- cy.findByTestId('stacked-bar-1-0-0.05296').realHover();
248
-
249
- cy.contains('06/19/2024').should('be.visible');
250
- cy.contains('Centreon-Server: Round-Trip Maximum Time').should(
251
- 'be.visible'
252
- );
253
- cy.contains('Centreon-Server: Round-Trip Average Time').should(
254
- 'be.visible'
255
- );
256
- cy.contains('Centreon-Server: Round-Trip Minimum Time').should(
257
- 'be.visible'
258
- );
259
- cy.contains('0.05 ms').should('be.visible');
260
- cy.contains('0.02 ms').should('be.visible');
261
- cy.contains('0.11 ms').should('be.visible');
262
-
263
- cy.findByTestId('stacked-bar-3-0-0.16196').should('be.visible');
264
- });
265
-
266
- it('displays a tooltip with a single metric when a stacked bar is hovered and a prop is set', () => {
267
- initialize({
268
- data: dataPingServiceStacked,
269
- orientation: 'horizontal',
270
- tooltip: {
271
- mode: 'single',
272
- sortOrder: 'descending'
273
- }
274
- });
275
-
276
- checkWidth('horizontal');
277
- cy.contains('0 ms').should('be.visible');
278
- cy.contains('20').should('be.visible');
279
- cy.contains(':40 AM').should('be.visible');
280
-
281
- cy.findByTestId('stacked-bar-1-0-0.05296').realHover();
282
-
283
- cy.contains('06/19/2024').should('be.visible');
284
- cy.contains('Centreon-Server: Round-Trip Average Time').should(
285
- 'be.visible'
286
- );
287
- cy.contains('0.05 ms').should('be.visible');
288
-
289
- cy.findByTestId('stacked-bar-3-0-0.16196').should('be.visible');
290
-
291
- cy.makeSnapshot();
292
- });
293
-
294
265
  it('displays the bottom axis correctly when data starts from several days ago', () => {
295
266
  initialize({
296
267
  data: dataLastWeek,
@@ -313,12 +284,4 @@ describe('Bar chart', () => {
313
284
  cy.contains('1 s').should('be.visible');
314
285
  cy.contains('1%').should('be.visible');
315
286
  });
316
-
317
- it('displays the stacked bar chart correctly when a point is missing compare to the time serie', () => {
318
- initialize({ data: dataMissingPoint });
319
-
320
- cy.findByTestId('stacked-bar-2-0-139').should('be.visible');
321
-
322
- cy.makeSnapshot();
323
- });
324
287
  });
@@ -6,8 +6,6 @@ import dataPingService from '../mockedData/pingService.json';
6
6
  import dataPingServiceMixedStacked from '../mockedData/pingServiceMixedStacked.json';
7
7
  import dataPingServiceStacked from '../mockedData/pingServiceStacked.json';
8
8
 
9
- import { ClickAwayListener } from '@mui/material';
10
- import { useState } from 'react';
11
9
  import BarChart from './BarChart';
12
10
 
13
11
  const meta: Meta<typeof BarChart> = {
@@ -261,43 +259,4 @@ export const mixedStackedMinMax: Story = {
261
259
  max: 20
262
260
  },
263
261
  render: Template
264
- };
265
-
266
- const LegendSecondaryClick = (args) => {
267
- const [position, setPosition] = useState<Array<[number, number]> | null>(
268
- null
269
- );
270
-
271
- return (
272
- <>
273
- <Template
274
- {...args}
275
- legend={{
276
- secondaryClick: ({ position }) => setPosition(position)
277
- }}
278
- />
279
- {position && (
280
- <ClickAwayListener onClickAway={() => setPosition(null)}>
281
- <div
282
- className="absolute py-1 px-2 rounded-sm bg-background-widget shadow-md"
283
- style={{ left: position?.[0], top: position?.[1] }}
284
- open={Boolean(position)}
285
- onClose={() => setPosition(null)}
286
- >
287
- menu
288
- </div>
289
- </ClickAwayListener>
290
- )}
291
- </>
292
- );
293
- };
294
-
295
- export const withLegendSecondaryClick: Story = {
296
- args: defaultArgs,
297
- render: (args) => (
298
- <LegendSecondaryClick
299
- {...args}
300
- data={dataPingService as unknown as LineChartData}
301
- />
302
- )
303
- };
262
+ };
@@ -116,4 +116,4 @@ const BarChart = ({
116
116
  );
117
117
  };
118
118
 
119
- export default BarChart;
119
+ export default BarChart;
@@ -1,4 +1,4 @@
1
- import { memo } from 'react';
1
+ import { memo, ReactElement } from 'react';
2
2
 
3
3
  import { ScaleType, scaleBand } from '@visx/scale';
4
4
  import { BarRounded } from '@visx/shape';
@@ -22,6 +22,7 @@ interface Props extends Omit<UseBarStackProps, 'xScale'> {
22
22
  barWidth: number;
23
23
  isTooltipHidden: boolean;
24
24
  neutralValue: number;
25
+ isStacked?: boolean;
25
26
  }
26
27
 
27
28
  const getPadding = ({ padding, size, isNegativeValue }): number => {
@@ -83,8 +84,9 @@ const BarStack = ({
83
84
  barIndex,
84
85
  isTooltipHidden,
85
86
  barStyle = { opacity: 1, radius: 0.2 },
86
- neutralValue
87
- }: Props): JSX.Element => {
87
+ neutralValue,
88
+ isStacked
89
+ }: Props): ReactElement => {
88
90
  const {
89
91
  BarStackComponent,
90
92
  commonBarStackProps,
@@ -118,6 +120,15 @@ const BarStack = ({
118
120
  metricId: Number(bar.key)
119
121
  }) as BarStyle;
120
122
 
123
+ const barY =
124
+ isNegativeValue && isStacked && !shouldApplyRadiusOnBottom
125
+ ? getPadding({
126
+ isNegativeValue,
127
+ padding: bar.y,
128
+ size: bar.height
129
+ })
130
+ : bar.y;
131
+
121
132
  return (
122
133
  <BarRounded
123
134
  {...barRoundedProps}
@@ -128,10 +139,10 @@ const BarStack = ({
128
139
  barWidth,
129
140
  y: isHorizontal
130
141
  ? getPadding({
131
- isNegativeValue,
132
- padding: bar.y,
133
- size: bar.height
134
- })
142
+ isNegativeValue,
143
+ padding: bar.y,
144
+ size: bar.height
145
+ })
135
146
  : barPadding,
136
147
  isFirstBar: shouldApplyRadiusOnBottom,
137
148
  isHorizontal,
@@ -146,19 +157,19 @@ const BarStack = ({
146
157
  isHorizontal
147
158
  ? barPadding
148
159
  : getPadding({
149
- isNegativeValue,
150
- padding: bar.x,
151
- size: bar.width
152
- })
160
+ isNegativeValue,
161
+ padding: bar.x,
162
+ size: bar.width
163
+ })
153
164
  }
154
- y={isHorizontal ? bar.y : barPadding}
165
+ y={isHorizontal ? barY : barPadding}
155
166
  onMouseEnter={
156
167
  isTooltipHidden
157
168
  ? undefined
158
169
  : hoverBar({
159
- barIndex,
160
- highlightedMetric: Number(bar.key)
161
- })
170
+ barIndex,
171
+ highlightedMetric: Number(bar.key)
172
+ })
162
173
  }
163
174
  onMouseLeave={isTooltipHidden ? undefined : exitBar}
164
175
  />
@@ -61,18 +61,19 @@ const MemoizedGroup = ({
61
61
  const linesBar = isStackedBar
62
62
  ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')].lines
63
63
  : (notStackedLines.find(({ metric_id }) =>
64
- equals(metric_id, Number(bar.key))
65
- ) as Line);
64
+ equals(metric_id, Number(bar.key))
65
+ ) as Line);
66
66
  const timeSeriesBar = isStackedBar
67
67
  ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')]
68
68
  .timeSeries
69
69
  : notStackedTimeSeries.map((timeSerie) => ({
70
- timeTick: timeSerie.timeTick,
71
- [bar.key]: timeSerie[Number(bar.key)]
72
- }));
70
+ timeTick: timeSerie.timeTick,
71
+ [bar.key]: timeSerie[Number(bar.key)]
72
+ }));
73
73
 
74
74
  return isStackedBar ? (
75
75
  <BarStack
76
+ isStacked
76
77
  key={`bar-${barGroup.index}-${bar.width}-${bar.y}-${bar.height}-${bar.x}`}
77
78
  barIndex={barGroup.index}
78
79
  barPadding={isHorizontal ? bar.x : bar.y}
@@ -82,7 +83,7 @@ const MemoizedGroup = ({
82
83
  isTooltipHidden={isTooltipHidden}
83
84
  lines={linesBar as Array<Line>}
84
85
  timeSeries={timeSeriesBar}
85
- yScale={yScalesPerUnit[bar.key.replace('stacked-', '')]}
86
+ yScale={yScalesPerUnit[bar.key.replace('stacked-', '')] ?? undefined}
86
87
  neutralValue={neutralValue}
87
88
  />
88
89
  ) : (
@@ -96,7 +97,7 @@ const MemoizedGroup = ({
96
97
  isTooltipHidden={isTooltipHidden}
97
98
  lines={[linesBar as Line]}
98
99
  timeSeries={timeSeriesBar}
99
- yScale={yScalesPerUnit[(linesBar as Line).unit]}
100
+ yScale={yScalesPerUnit[(linesBar as Line).unit ?? undefined]}
100
101
  neutralValue={neutralValue}
101
102
  />
102
103
  );
@@ -196,8 +196,7 @@ const ResponsiveBarChart = ({
196
196
  displayLegend,
197
197
  mode: legend?.mode,
198
198
  placement: legend?.placement,
199
- renderExtraComponent: legend?.renderExtraComponent,
200
- secondaryClick: legend?.secondaryClick
199
+ renderExtraComponent: legend?.renderExtraComponent
201
200
  }}
202
201
  legendRef={legendRef}
203
202
  limitLegend={limitLegend}
@@ -27,6 +27,7 @@ import { StackValue } from '../../../InteractiveComponents/AnchorPoint/models';
27
27
  import { getCurveFactory, getFillColor } from '../../../common';
28
28
  import { LineStyle } from '../../../models';
29
29
  import Point from '../Point';
30
+ import { ReactElement } from 'react';
30
31
 
31
32
  interface Props {
32
33
  areaTransparency?: number;
@@ -56,7 +57,7 @@ const StackLines = ({
56
57
  lineStyle,
57
58
  hasSecondUnit,
58
59
  maxLeftAxisCharacters
59
- }: Props): JSX.Element => {
60
+ }: Props): ReactElement => {
60
61
  const curveType = getCurveFactory(
61
62
  (equals(type(lineStyle), 'Array')
62
63
  ? lineStyle?.[0].curve
@@ -134,9 +135,9 @@ const StackLines = ({
134
135
  equals(style?.showArea, false)
135
136
  ? 'transparent'
136
137
  : getFillColor({
137
- areaColor: areaColor || lineColor,
138
- transparency: formattedTransparency
139
- })
138
+ areaColor: areaColor || lineColor,
139
+ transparency: formattedTransparency
140
+ })
140
141
  }
141
142
  opacity={highlight === false ? 0.3 : 1}
142
143
  stroke={lineColor}