@scality/core-ui 0.162.0 → 0.164.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/dist/components/barchartv2/Barchart.component.d.ts +9 -3
- package/dist/components/barchartv2/Barchart.component.d.ts.map +1 -1
- package/dist/components/barchartv2/Barchart.component.js +22 -5
- package/dist/components/barchartv2/utils.d.ts +26 -3
- package/dist/components/barchartv2/utils.d.ts.map +1 -1
- package/dist/components/barchartv2/utils.js +76 -22
- package/dist/components/chartlegend/ChartLegend.d.ts +8 -0
- package/dist/components/chartlegend/ChartLegend.d.ts.map +1 -0
- package/dist/components/chartlegend/ChartLegend.js +65 -0
- package/dist/components/chartlegend/ChartLegendWrapper.d.ts +17 -0
- package/dist/components/chartlegend/ChartLegendWrapper.d.ts.map +1 -0
- package/dist/components/chartlegend/ChartLegendWrapper.js +50 -0
- package/dist/components/date/FormattedDateTime.d.ts +3 -1
- package/dist/components/date/FormattedDateTime.d.ts.map +1 -1
- package/dist/components/date/FormattedDateTime.js +19 -1
- package/dist/components/date/FormattedDateTime.spec.js +12 -0
- package/dist/components/icon/Icon.component.d.ts +5 -5
- package/dist/components/icon/Icon.component.d.ts.map +1 -1
- package/dist/components/icon/Icon.component.js +33 -31
- package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts +33 -0
- package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts.map +1 -0
- package/dist/components/linetimeseriechart/linetimeseriechart.component.js +249 -0
- package/dist/components/selectv2/Selectv2.component.d.ts.map +1 -1
- package/dist/components/selectv2/Selectv2.component.js +11 -6
- package/dist/components/steppers/Stepper.component.d.ts.map +1 -1
- package/dist/components/steppers/Stepper.component.js +9 -8
- package/dist/components/toast/ToastProvider.d.ts.map +1 -1
- package/dist/components/toast/ToastProvider.js +4 -5
- package/dist/components/vegachartv2/SyncedCursorCharts.d.ts.map +1 -1
- package/dist/components/vegachartv2/SyncedCursorCharts.js +3 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/next.d.ts +2 -0
- package/dist/next.d.ts.map +1 -1
- package/dist/next.js +2 -0
- package/dist/style/theme.d.ts +1 -0
- package/dist/style/theme.d.ts.map +1 -1
- package/dist/style/theme.js +28 -0
- package/package.json +2 -2
- package/src/lib/components/accordion/Accordion.test.tsx +8 -16
- package/src/lib/components/barchartv2/Barchart.component.test.tsx +117 -111
- package/src/lib/components/barchartv2/Barchart.component.tsx +54 -7
- package/src/lib/components/barchartv2/utils.test.ts +127 -2
- package/src/lib/components/barchartv2/utils.ts +103 -19
- package/src/lib/components/chartlegend/ChartLegend.tsx +113 -0
- package/src/lib/components/chartlegend/ChartLegendWrapper.tsx +85 -0
- package/src/lib/components/date/FormattedDateTime.spec.tsx +24 -0
- package/src/lib/components/date/FormattedDateTime.tsx +36 -2
- package/src/lib/components/healthselectorv2/HealthSelector.component.test.tsx +10 -10
- package/src/lib/components/icon/Icon.component.tsx +48 -60
- package/src/lib/components/infomessage/InfoMessageUtils.test.tsx +0 -1
- package/src/lib/components/inlineinput/InlineInput.test.tsx +28 -22
- package/src/lib/components/inputlist/InputList.test.tsx +22 -21
- package/src/lib/components/linetemporalchart/ChartUtil.test.ts +5 -4
- package/src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx +502 -0
- package/src/lib/components/searchinput/SearchInput.test.tsx +3 -7
- package/src/lib/components/selectv2/Selectv2.component.tsx +13 -5
- package/src/lib/components/selectv2/selectv2.test.tsx +70 -61
- package/src/lib/components/steppers/Stepper.component.tsx +10 -8
- package/src/lib/components/tablev2/TableSync.test.tsx +8 -12
- package/src/lib/components/tablev2/TableUtils.test.ts +6 -3
- package/src/lib/components/tablev2/Tablev2.test.tsx +38 -40
- package/src/lib/components/toast/ToastProvider.tsx +14 -6
- package/src/lib/components/toggle/Toggle.test.tsx +1 -1
- package/src/lib/components/vegachartv2/SyncedCursorCharts.tsx +5 -7
- package/src/lib/index.ts +1 -0
- package/src/lib/next.ts +2 -0
- package/src/lib/style/theme.ts +29 -0
- package/stories/BarChart/barchart.stories.tsx +387 -129
- package/stories/format.mdx +4 -2
- package/stories/linetimeseriechart.stories.tsx +485 -0
- package/tsconfig.json +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scality/core-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.164.0",
|
|
4
4
|
"description": "Scality common React component library",
|
|
5
5
|
"author": "Scality Engineering",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
|
109
109
|
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
|
110
110
|
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
|
111
|
-
"@fortawesome/react-fontawesome": "^0.
|
|
111
|
+
"@fortawesome/react-fontawesome": "^0.2.3",
|
|
112
112
|
"@js-temporal/polyfill": "^0.4.4",
|
|
113
113
|
"@storybook/preview-api": "^8.3.6",
|
|
114
114
|
"downshift": "^7.0.5",
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import
|
|
1
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
3
|
import { Accordion } from './Accordion.component';
|
|
4
4
|
import userEvent from '@testing-library/user-event';
|
|
5
|
-
import { QueryClient, QueryClientProvider } from 'react-query';
|
|
6
5
|
|
|
7
6
|
describe('Accordion', () => {
|
|
8
7
|
const selectors = {
|
|
@@ -11,20 +10,18 @@ describe('Accordion', () => {
|
|
|
11
10
|
accordionContent: () => screen.queryByText(/Test content/i),
|
|
12
11
|
};
|
|
13
12
|
const SUT = ({ open = false }) => {
|
|
14
|
-
const queryClient = new QueryClient();
|
|
15
13
|
return (
|
|
16
|
-
<
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
</Accordion>
|
|
20
|
-
</QueryClientProvider>
|
|
14
|
+
<Accordion title="Advanced Testings" id="test-accordion" open={open}>
|
|
15
|
+
<div>Test content</div>
|
|
16
|
+
</Accordion>
|
|
21
17
|
);
|
|
22
18
|
};
|
|
23
19
|
const renderAccordion = (open = false) => {
|
|
24
20
|
render(<SUT open={open} />);
|
|
25
21
|
};
|
|
26
|
-
it('should render the Accordion component with title and content', () => {
|
|
22
|
+
it('should render the Accordion component with title and content', async () => {
|
|
27
23
|
renderAccordion();
|
|
24
|
+
await waitFor(() => screen.findByRole('img', { hidden: true }));
|
|
28
25
|
|
|
29
26
|
const accordionToggle = selectors.accordionToggle();
|
|
30
27
|
expect(accordionToggle).toBeInTheDocument();
|
|
@@ -54,7 +51,6 @@ describe('Accordion', () => {
|
|
|
54
51
|
});
|
|
55
52
|
|
|
56
53
|
it('should toggle the content when open prop changes', () => {
|
|
57
|
-
const queryClient = new QueryClient();
|
|
58
54
|
const TestWrapper = () => {
|
|
59
55
|
const [isOpen, setisOpen] = useState(false);
|
|
60
56
|
return (
|
|
@@ -65,11 +61,7 @@ describe('Accordion', () => {
|
|
|
65
61
|
);
|
|
66
62
|
};
|
|
67
63
|
|
|
68
|
-
render(
|
|
69
|
-
<QueryClientProvider client={queryClient}>
|
|
70
|
-
<TestWrapper />
|
|
71
|
-
</QueryClientProvider>,
|
|
72
|
-
);
|
|
64
|
+
render(<TestWrapper />);
|
|
73
65
|
|
|
74
66
|
userEvent.click(screen.getByRole('button', { name: /Test button/i }));
|
|
75
67
|
expect(selectors.accordionContent()).toBeInTheDocument();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
-
import React from 'react';
|
|
3
2
|
import { getWrapper } from '../../testUtils';
|
|
4
3
|
import { Barchart } from './Barchart.component';
|
|
4
|
+
import { ChartLegendWrapper } from '../chartlegend/ChartLegendWrapper';
|
|
5
5
|
|
|
6
6
|
const ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
|
|
7
7
|
const ONE_HOUR_IN_MILLISECONDS = 60 * 60 * 1000;
|
|
@@ -14,7 +14,7 @@ jest.mock('recharts', () => {
|
|
|
14
14
|
...OriginalResponsiveContainerModule,
|
|
15
15
|
ResponsiveContainer: ({ height, children }) => (
|
|
16
16
|
<OriginalResponsiveContainerModule.ResponsiveContainer
|
|
17
|
-
|
|
17
|
+
aspect={3}
|
|
18
18
|
height={300}
|
|
19
19
|
data-testid="responsive-container"
|
|
20
20
|
>
|
|
@@ -48,19 +48,19 @@ const testTimeBars = [
|
|
|
48
48
|
},
|
|
49
49
|
] as const;
|
|
50
50
|
|
|
51
|
+
const testColorSet = {
|
|
52
|
+
Success: 'lineColor1',
|
|
53
|
+
};
|
|
54
|
+
|
|
51
55
|
describe('Barchart', () => {
|
|
52
56
|
describe('Basic rendering', () => {
|
|
53
57
|
it('should render the Barchart component with category data', async () => {
|
|
54
58
|
const { Wrapper } = getWrapper();
|
|
55
59
|
render(
|
|
56
60
|
<Wrapper>
|
|
57
|
-
<
|
|
58
|
-
type="category"
|
|
59
|
-
|
|
60
|
-
colorSet={{
|
|
61
|
-
Success: 'lineColor1',
|
|
62
|
-
}}
|
|
63
|
-
/>
|
|
61
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
62
|
+
<Barchart type="category" bars={testBars} />
|
|
63
|
+
</ChartLegendWrapper>
|
|
64
64
|
</Wrapper>,
|
|
65
65
|
);
|
|
66
66
|
|
|
@@ -72,20 +72,19 @@ describe('Barchart', () => {
|
|
|
72
72
|
const { Wrapper } = getWrapper();
|
|
73
73
|
render(
|
|
74
74
|
<Wrapper>
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
type
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
/>
|
|
75
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
76
|
+
<Barchart
|
|
77
|
+
type={{
|
|
78
|
+
type: 'time',
|
|
79
|
+
timeRange: {
|
|
80
|
+
startDate: new Date('2024-07-05'),
|
|
81
|
+
endDate: new Date('2024-07-07'),
|
|
82
|
+
interval: ONE_DAY_IN_MILLISECONDS,
|
|
83
|
+
},
|
|
84
|
+
}}
|
|
85
|
+
bars={testTimeBars}
|
|
86
|
+
/>
|
|
87
|
+
</ChartLegendWrapper>
|
|
89
88
|
</Wrapper>,
|
|
90
89
|
);
|
|
91
90
|
|
|
@@ -93,6 +92,43 @@ describe('Barchart', () => {
|
|
|
93
92
|
expect(screen.getByText('Sat06Jul')).toBeInTheDocument();
|
|
94
93
|
expect(screen.getByText('Sun07Jul')).toBeInTheDocument();
|
|
95
94
|
});
|
|
95
|
+
it('should render the Barchart component with error state', async () => {
|
|
96
|
+
const { Wrapper } = getWrapper();
|
|
97
|
+
render(
|
|
98
|
+
<Wrapper>
|
|
99
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
100
|
+
<Barchart type="category" bars={[]} isError />
|
|
101
|
+
</ChartLegendWrapper>
|
|
102
|
+
</Wrapper>,
|
|
103
|
+
);
|
|
104
|
+
expect(
|
|
105
|
+
screen.getByText('Chart data is not available'),
|
|
106
|
+
).toBeInTheDocument();
|
|
107
|
+
});
|
|
108
|
+
it('should render the Barchart component with loading state', async () => {
|
|
109
|
+
const { Wrapper } = getWrapper();
|
|
110
|
+
render(
|
|
111
|
+
<Wrapper>
|
|
112
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
113
|
+
<Barchart type="category" bars={[]} isLoading />
|
|
114
|
+
</ChartLegendWrapper>
|
|
115
|
+
</Wrapper>,
|
|
116
|
+
);
|
|
117
|
+
expect(screen.getByText('Loading Chart Data...')).toBeInTheDocument();
|
|
118
|
+
});
|
|
119
|
+
it('should render the Barchart component with undefined bars', async () => {
|
|
120
|
+
const { Wrapper } = getWrapper();
|
|
121
|
+
render(
|
|
122
|
+
<Wrapper>
|
|
123
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
124
|
+
<Barchart type="category" bars={undefined} />
|
|
125
|
+
</ChartLegendWrapper>
|
|
126
|
+
</Wrapper>,
|
|
127
|
+
);
|
|
128
|
+
expect(
|
|
129
|
+
screen.getByText('Chart data is not available'),
|
|
130
|
+
).toBeInTheDocument();
|
|
131
|
+
});
|
|
96
132
|
});
|
|
97
133
|
|
|
98
134
|
describe('Time data', () => {
|
|
@@ -100,21 +136,20 @@ describe('Barchart', () => {
|
|
|
100
136
|
const { Wrapper } = getWrapper();
|
|
101
137
|
render(
|
|
102
138
|
<Wrapper>
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
type
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
/>
|
|
139
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
140
|
+
<Barchart
|
|
141
|
+
type={{
|
|
142
|
+
type: 'time',
|
|
143
|
+
timeRange: {
|
|
144
|
+
startDate: new Date('2024-07-03'),
|
|
145
|
+
endDate: new Date('2024-07-07'),
|
|
146
|
+
interval: ONE_DAY_IN_MILLISECONDS,
|
|
147
|
+
},
|
|
148
|
+
}}
|
|
149
|
+
// data starts on 2024-07-05
|
|
150
|
+
bars={testTimeBars}
|
|
151
|
+
/>
|
|
152
|
+
</ChartLegendWrapper>
|
|
118
153
|
</Wrapper>,
|
|
119
154
|
);
|
|
120
155
|
expect(screen.getByText('Wed03Jul')).toBeInTheDocument();
|
|
@@ -154,14 +189,14 @@ describe('Barchart', () => {
|
|
|
154
189
|
const { Wrapper } = getWrapper();
|
|
155
190
|
render(
|
|
156
191
|
<Wrapper>
|
|
157
|
-
<
|
|
158
|
-
type={type}
|
|
159
|
-
bars={bars}
|
|
192
|
+
<ChartLegendWrapper
|
|
160
193
|
colorSet={{
|
|
161
194
|
Success: 'lineColor1',
|
|
162
195
|
Failed: 'lineColor2',
|
|
163
196
|
}}
|
|
164
|
-
|
|
197
|
+
>
|
|
198
|
+
<Barchart type={type} bars={bars} />
|
|
199
|
+
</ChartLegendWrapper>
|
|
165
200
|
</Wrapper>,
|
|
166
201
|
);
|
|
167
202
|
|
|
@@ -202,13 +237,9 @@ describe('Barchart', () => {
|
|
|
202
237
|
const { Wrapper } = getWrapper();
|
|
203
238
|
render(
|
|
204
239
|
<Wrapper>
|
|
205
|
-
<
|
|
206
|
-
type={type}
|
|
207
|
-
|
|
208
|
-
colorSet={{
|
|
209
|
-
Success: 'lineColor1',
|
|
210
|
-
}}
|
|
211
|
-
/>
|
|
240
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
241
|
+
<Barchart type={type} bars={testTimeBars} />
|
|
242
|
+
</ChartLegendWrapper>
|
|
212
243
|
</Wrapper>,
|
|
213
244
|
);
|
|
214
245
|
await waitFor(() => {
|
|
@@ -236,20 +267,19 @@ describe('Barchart', () => {
|
|
|
236
267
|
const { Wrapper } = getWrapper();
|
|
237
268
|
render(
|
|
238
269
|
<Wrapper>
|
|
239
|
-
<
|
|
240
|
-
|
|
241
|
-
type
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
/>
|
|
270
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
271
|
+
<Barchart
|
|
272
|
+
type={{
|
|
273
|
+
type: 'time',
|
|
274
|
+
timeRange: {
|
|
275
|
+
startDate: new Date('2024-07-05T10:00:00'),
|
|
276
|
+
endDate: new Date('2024-07-05T12:00:00'),
|
|
277
|
+
interval: ONE_HOUR_IN_MILLISECONDS,
|
|
278
|
+
},
|
|
279
|
+
}}
|
|
280
|
+
bars={testHourlyBars}
|
|
281
|
+
/>
|
|
282
|
+
</ChartLegendWrapper>
|
|
253
283
|
</Wrapper>,
|
|
254
284
|
);
|
|
255
285
|
|
|
@@ -284,15 +314,9 @@ describe('Barchart', () => {
|
|
|
284
314
|
const { Wrapper } = getWrapper();
|
|
285
315
|
render(
|
|
286
316
|
<Wrapper>
|
|
287
|
-
<
|
|
288
|
-
type="category"
|
|
289
|
-
|
|
290
|
-
stacked={true}
|
|
291
|
-
colorSet={{
|
|
292
|
-
Success: 'lineColor1',
|
|
293
|
-
Failed: 'lineColor2',
|
|
294
|
-
}}
|
|
295
|
-
/>
|
|
317
|
+
<ChartLegendWrapper colorSet={{ ...testColorSet, Failed: 'red' }}>
|
|
318
|
+
<Barchart type="category" bars={testStackedBars} stacked={true} />
|
|
319
|
+
</ChartLegendWrapper>
|
|
296
320
|
</Wrapper>,
|
|
297
321
|
);
|
|
298
322
|
|
|
@@ -317,18 +341,17 @@ describe('Barchart', () => {
|
|
|
317
341
|
const { Wrapper } = getWrapper();
|
|
318
342
|
render(
|
|
319
343
|
<Wrapper>
|
|
320
|
-
<
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
/>
|
|
344
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
345
|
+
<Barchart
|
|
346
|
+
type="category"
|
|
347
|
+
bars={testBars}
|
|
348
|
+
defaultSort={(pointA, pointB) => {
|
|
349
|
+
const valueA = pointA.Success;
|
|
350
|
+
const valueB = pointB.Success;
|
|
351
|
+
return valueB - valueA > 0 ? 1 : valueB - valueA < 0 ? -1 : 0;
|
|
352
|
+
}}
|
|
353
|
+
/>
|
|
354
|
+
</ChartLegendWrapper>
|
|
332
355
|
</Wrapper>,
|
|
333
356
|
);
|
|
334
357
|
|
|
@@ -339,37 +362,20 @@ describe('Barchart', () => {
|
|
|
339
362
|
expect(categories[2]).toHaveTextContent('category1'); // 10 (lowest)
|
|
340
363
|
});
|
|
341
364
|
|
|
342
|
-
it('should render the Barchart component with loading state', () => {
|
|
343
|
-
const { Wrapper } = getWrapper();
|
|
344
|
-
render(
|
|
345
|
-
<Wrapper>
|
|
346
|
-
<Barchart
|
|
347
|
-
type="category"
|
|
348
|
-
bars={[]}
|
|
349
|
-
isLoading
|
|
350
|
-
colorSet={{
|
|
351
|
-
Success: 'lineColor1',
|
|
352
|
-
}}
|
|
353
|
-
/>
|
|
354
|
-
</Wrapper>,
|
|
355
|
-
);
|
|
356
|
-
expect(screen.getByText('Loading Chart Data...')).toBeInTheDocument();
|
|
357
|
-
});
|
|
358
365
|
it('should render header with title, secondary title, right title and help tooltip', async () => {
|
|
359
366
|
const { Wrapper } = getWrapper();
|
|
360
367
|
render(
|
|
361
368
|
<Wrapper>
|
|
362
|
-
<
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
/>
|
|
369
|
+
<ChartLegendWrapper colorSet={testColorSet}>
|
|
370
|
+
<Barchart
|
|
371
|
+
type="category"
|
|
372
|
+
bars={[]}
|
|
373
|
+
title="Test Title"
|
|
374
|
+
secondaryTitle="Test Secondary Title"
|
|
375
|
+
rightTitle="Test Right Title"
|
|
376
|
+
helpTooltip="Test Help Tooltip"
|
|
377
|
+
/>
|
|
378
|
+
</ChartLegendWrapper>
|
|
373
379
|
</Wrapper>,
|
|
374
380
|
);
|
|
375
381
|
|
|
@@ -19,11 +19,12 @@ import { IconHelp } from '../iconhelper/IconHelper';
|
|
|
19
19
|
import { Loader } from '../loader/Loader.component';
|
|
20
20
|
import { Text } from '../text/Text.component';
|
|
21
21
|
import { renderTooltipContent, UnitRange, useChartData } from './utils';
|
|
22
|
+
import { useChartLegend } from '../chartlegend/ChartLegendWrapper';
|
|
22
23
|
|
|
23
24
|
const CHART_CONSTANTS = {
|
|
24
25
|
TICK_WIDTH_OFFSET: 5,
|
|
25
26
|
BAR_SIZE: 12,
|
|
26
|
-
MIN_POINT_SIZE:
|
|
27
|
+
MIN_POINT_SIZE: 3,
|
|
27
28
|
DEFAULT_HEIGHT: 200,
|
|
28
29
|
CHART_MARGIN: {
|
|
29
30
|
left: 0,
|
|
@@ -69,18 +70,25 @@ export type BarchartSortFn<T extends BarchartBars> = (
|
|
|
69
70
|
|
|
70
71
|
export type BarchartProps<T extends BarchartBars> = {
|
|
71
72
|
type: 'category' | TimeType;
|
|
72
|
-
bars
|
|
73
|
-
colorSet: Record<T[number]['label'], ChartColors | (string & {})>;
|
|
73
|
+
bars?: T;
|
|
74
74
|
tooltip?: BarchartTooltipFn<T>;
|
|
75
75
|
defaultSort?: BarchartSortFn<T>;
|
|
76
76
|
unitRange?: UnitRange;
|
|
77
77
|
helpTooltip?: string;
|
|
78
78
|
stacked?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Sort the bars by default or by legend order
|
|
81
|
+
* legend will sort the bars by the order of the colorSet property of the ChartLegendWrapper component
|
|
82
|
+
* default will sort the bars by average values in descending order (biggest values will be at bottom)
|
|
83
|
+
* @default 'default'
|
|
84
|
+
*/
|
|
85
|
+
stackedBarSort?: 'default' | 'legend';
|
|
79
86
|
title?: string;
|
|
80
87
|
secondaryTitle?: string;
|
|
81
88
|
rightTitle?: React.ReactNode;
|
|
82
89
|
height?: number;
|
|
83
90
|
isLoading?: boolean;
|
|
91
|
+
isError?: boolean;
|
|
84
92
|
};
|
|
85
93
|
|
|
86
94
|
interface CustomTickProps {
|
|
@@ -177,6 +185,21 @@ const ChartHeader = ({
|
|
|
177
185
|
);
|
|
178
186
|
};
|
|
179
187
|
|
|
188
|
+
const Error = ({ height }: { height: number }) => {
|
|
189
|
+
return (
|
|
190
|
+
<Box
|
|
191
|
+
height={height}
|
|
192
|
+
style={{
|
|
193
|
+
alignItems: 'center',
|
|
194
|
+
justifyContent: 'center',
|
|
195
|
+
display: 'flex',
|
|
196
|
+
}}
|
|
197
|
+
>
|
|
198
|
+
<Text>Chart data is not available</Text>
|
|
199
|
+
</Box>
|
|
200
|
+
);
|
|
201
|
+
};
|
|
202
|
+
|
|
180
203
|
const Loading = ({ height }: { height: number }) => {
|
|
181
204
|
return (
|
|
182
205
|
<Box
|
|
@@ -196,15 +219,16 @@ const Loading = ({ height }: { height: number }) => {
|
|
|
196
219
|
|
|
197
220
|
export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
|
|
198
221
|
const theme = useTheme();
|
|
222
|
+
const { getColor } = useChartLegend();
|
|
199
223
|
const [hoveredValue, setHoveredValue] = useState<string | undefined>();
|
|
200
224
|
|
|
201
225
|
const {
|
|
202
226
|
height = CHART_CONSTANTS.DEFAULT_HEIGHT,
|
|
203
227
|
bars,
|
|
204
228
|
type = 'category',
|
|
205
|
-
colorSet,
|
|
206
229
|
unitRange,
|
|
207
230
|
stacked,
|
|
231
|
+
stackedBarSort = 'default',
|
|
208
232
|
defaultSort,
|
|
209
233
|
tooltip,
|
|
210
234
|
title,
|
|
@@ -212,10 +236,31 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
|
|
|
212
236
|
helpTooltip,
|
|
213
237
|
rightTitle,
|
|
214
238
|
isLoading,
|
|
239
|
+
isError,
|
|
215
240
|
} = props;
|
|
216
241
|
|
|
242
|
+
// Create colorSet from ChartLegendWrapper
|
|
243
|
+
const colorSet = bars?.reduce(
|
|
244
|
+
(acc, bar) => {
|
|
245
|
+
const color = getColor(bar.label);
|
|
246
|
+
if (color) {
|
|
247
|
+
acc[bar.label] = color;
|
|
248
|
+
}
|
|
249
|
+
return acc;
|
|
250
|
+
},
|
|
251
|
+
{} as Record<string, ChartColors | string>,
|
|
252
|
+
);
|
|
253
|
+
|
|
217
254
|
const { rechartsBars, unitLabel, roundReferenceValue, rechartsData } =
|
|
218
|
-
useChartData(
|
|
255
|
+
useChartData(
|
|
256
|
+
bars || [],
|
|
257
|
+
type,
|
|
258
|
+
colorSet || {},
|
|
259
|
+
stacked,
|
|
260
|
+
defaultSort,
|
|
261
|
+
unitRange,
|
|
262
|
+
stackedBarSort,
|
|
263
|
+
);
|
|
219
264
|
|
|
220
265
|
return (
|
|
221
266
|
<Stack direction="vertical" gap="r8">
|
|
@@ -225,7 +270,9 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
|
|
|
225
270
|
helpTooltip={helpTooltip}
|
|
226
271
|
rightTitle={rightTitle}
|
|
227
272
|
/>
|
|
228
|
-
{isLoading ? (
|
|
273
|
+
{isError || (!bars && !isLoading) ? (
|
|
274
|
+
<Error height={height} />
|
|
275
|
+
) : isLoading ? (
|
|
229
276
|
<Loading height={height} />
|
|
230
277
|
) : (
|
|
231
278
|
<StyledResponsiveContainer width="100%" height={height}>
|
|
@@ -248,7 +295,7 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
|
|
|
248
295
|
key={dataKey}
|
|
249
296
|
dataKey={dataKey}
|
|
250
297
|
fill={chartColors[fill] || fill}
|
|
251
|
-
minPointSize={CHART_CONSTANTS.MIN_POINT_SIZE}
|
|
298
|
+
minPointSize={stacked ? 0 : CHART_CONSTANTS.MIN_POINT_SIZE}
|
|
252
299
|
stackId={stackId}
|
|
253
300
|
onMouseOver={() => setHoveredValue(dataKey)}
|
|
254
301
|
onMouseLeave={() => setHoveredValue(undefined)}
|
|
@@ -2,6 +2,7 @@ import { coreUIAvailableThemes } from '../../style/theme';
|
|
|
2
2
|
import {
|
|
3
3
|
applySortingToData,
|
|
4
4
|
computeUnitLabelAndRoundReferenceValue,
|
|
5
|
+
filterChartDataAndBarsByLegendSelection,
|
|
5
6
|
formatPrometheusDataToRechartsDataAndBars,
|
|
6
7
|
getMaxBarValue,
|
|
7
8
|
getRoundReferenceValue,
|
|
@@ -481,8 +482,8 @@ describe('applySortingToData', () => {
|
|
|
481
482
|
|
|
482
483
|
describe('getRoundReferenceValue', () => {
|
|
483
484
|
it('should return appropriate rounded values', () => {
|
|
484
|
-
expect(getRoundReferenceValue(1)).toBe(
|
|
485
|
-
expect(getRoundReferenceValue(2)).toBe(
|
|
485
|
+
expect(getRoundReferenceValue(1)).toBe(5);
|
|
486
|
+
expect(getRoundReferenceValue(2)).toBe(5);
|
|
486
487
|
expect(getRoundReferenceValue(3)).toBe(5);
|
|
487
488
|
expect(getRoundReferenceValue(7)).toBe(10);
|
|
488
489
|
expect(getRoundReferenceValue(15)).toBe(25);
|
|
@@ -716,6 +717,14 @@ describe('sortStackedBars', () => {
|
|
|
716
717
|
{ dataKey: 'bar1', fill: 'blue' },
|
|
717
718
|
]);
|
|
718
719
|
});
|
|
720
|
+
it('should sort bars by legend order when stacked is true and legendOrder is provided', () => {
|
|
721
|
+
const result = sortStackedBars(bars, data, true, ['bar3', 'bar2', 'bar1']);
|
|
722
|
+
expect(result).toEqual([
|
|
723
|
+
{ dataKey: 'bar3', fill: 'green' },
|
|
724
|
+
{ dataKey: 'bar2', fill: 'red' },
|
|
725
|
+
{ dataKey: 'bar1', fill: 'blue' },
|
|
726
|
+
]);
|
|
727
|
+
});
|
|
719
728
|
it('should not sort bars when stacked is false', () => {
|
|
720
729
|
const result = sortStackedBars(bars, data, false);
|
|
721
730
|
expect(result).toEqual([
|
|
@@ -780,3 +789,119 @@ describe('renderTooltipContent', () => {
|
|
|
780
789
|
});
|
|
781
790
|
});
|
|
782
791
|
});
|
|
792
|
+
|
|
793
|
+
describe('filterChartDataAndBarsByLegendSelection', () => {
|
|
794
|
+
const mockChartData = [
|
|
795
|
+
{ category: 'Jan', Success: 10, Failed: 5, Warning: 3, Pending: 2 },
|
|
796
|
+
{ category: 'Feb', Success: 20, Failed: 8, Warning: 6, Pending: 4 },
|
|
797
|
+
{ category: 'Mar', Success: 15, Failed: 12, Warning: 9, Pending: 7 },
|
|
798
|
+
];
|
|
799
|
+
|
|
800
|
+
const mockRechartsBars = [
|
|
801
|
+
{ dataKey: 'Success', fill: '#00D100', stackId: undefined },
|
|
802
|
+
{ dataKey: 'Failed', fill: '#D10000', stackId: undefined },
|
|
803
|
+
{ dataKey: 'Warning', fill: '#FFA500', stackId: 'stacked' },
|
|
804
|
+
{ dataKey: 'Pending', fill: '#337FBD', stackId: 'stacked' },
|
|
805
|
+
];
|
|
806
|
+
|
|
807
|
+
it('should return all data and bars when no resources are selected (empty array)', () => {
|
|
808
|
+
const result = filterChartDataAndBarsByLegendSelection(
|
|
809
|
+
mockChartData,
|
|
810
|
+
mockRechartsBars,
|
|
811
|
+
[],
|
|
812
|
+
);
|
|
813
|
+
|
|
814
|
+
expect(result.filteredData).toEqual(mockChartData);
|
|
815
|
+
expect(result.filteredRechartsBars).toEqual(mockRechartsBars);
|
|
816
|
+
expect(result.filteredData).toHaveLength(3);
|
|
817
|
+
expect(result.filteredRechartsBars).toHaveLength(4);
|
|
818
|
+
// Verify all properties are preserved
|
|
819
|
+
expect(Object.keys(result.filteredData[0])).toEqual([
|
|
820
|
+
'category',
|
|
821
|
+
'Success',
|
|
822
|
+
'Failed',
|
|
823
|
+
'Warning',
|
|
824
|
+
'Pending',
|
|
825
|
+
]);
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
it('should return only selected resources in both data and bars when resources are selected', () => {
|
|
829
|
+
const selectedResources = ['Success', 'Warning'];
|
|
830
|
+
const result = filterChartDataAndBarsByLegendSelection(
|
|
831
|
+
mockChartData,
|
|
832
|
+
mockRechartsBars,
|
|
833
|
+
selectedResources,
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
expect(result.filteredData).toHaveLength(3);
|
|
837
|
+
expect(result.filteredData).toEqual([
|
|
838
|
+
{ category: 'Jan', Success: 10, Warning: 3 },
|
|
839
|
+
{ category: 'Feb', Success: 20, Warning: 6 },
|
|
840
|
+
{ category: 'Mar', Success: 15, Warning: 9 },
|
|
841
|
+
]);
|
|
842
|
+
|
|
843
|
+
expect(result.filteredRechartsBars).toHaveLength(2);
|
|
844
|
+
expect(result.filteredRechartsBars).toEqual([
|
|
845
|
+
{ dataKey: 'Success', fill: '#00D100', stackId: undefined },
|
|
846
|
+
{ dataKey: 'Warning', fill: '#FFA500', stackId: 'stacked' },
|
|
847
|
+
]);
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
it('should return single resource when only one resource is selected', () => {
|
|
851
|
+
const selectedResources = ['Failed'];
|
|
852
|
+
const result = filterChartDataAndBarsByLegendSelection(
|
|
853
|
+
mockChartData,
|
|
854
|
+
mockRechartsBars,
|
|
855
|
+
selectedResources,
|
|
856
|
+
);
|
|
857
|
+
|
|
858
|
+
expect(result.filteredData).toHaveLength(3);
|
|
859
|
+
expect(result.filteredData).toEqual([
|
|
860
|
+
{ category: 'Jan', Failed: 5 },
|
|
861
|
+
{ category: 'Feb', Failed: 8 },
|
|
862
|
+
{ category: 'Mar', Failed: 12 },
|
|
863
|
+
]);
|
|
864
|
+
|
|
865
|
+
expect(result.filteredRechartsBars).toHaveLength(1);
|
|
866
|
+
expect(result.filteredRechartsBars).toEqual([
|
|
867
|
+
{ dataKey: 'Failed', fill: '#D10000', stackId: undefined },
|
|
868
|
+
]);
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
it('should handle empty data array', () => {
|
|
872
|
+
const result = filterChartDataAndBarsByLegendSelection(
|
|
873
|
+
[],
|
|
874
|
+
mockRechartsBars,
|
|
875
|
+
['Success'],
|
|
876
|
+
);
|
|
877
|
+
|
|
878
|
+
expect(result.filteredData).toEqual([]);
|
|
879
|
+
expect(result.filteredRechartsBars).toHaveLength(1);
|
|
880
|
+
expect(result.filteredRechartsBars).toEqual([
|
|
881
|
+
{ dataKey: 'Success', fill: '#00D100', stackId: undefined },
|
|
882
|
+
]);
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
it('should preserve order of selected resources based on data object keys', () => {
|
|
886
|
+
const selectedResources = ['Pending', 'Success', 'Failed']; // Different order
|
|
887
|
+
const result = filterChartDataAndBarsByLegendSelection(
|
|
888
|
+
mockChartData,
|
|
889
|
+
mockRechartsBars,
|
|
890
|
+
selectedResources,
|
|
891
|
+
);
|
|
892
|
+
|
|
893
|
+
// Should maintain the order they appear in selectedResources
|
|
894
|
+
expect(Object.keys(result.filteredData[0])).toEqual([
|
|
895
|
+
'category',
|
|
896
|
+
'Pending',
|
|
897
|
+
'Success',
|
|
898
|
+
'Failed',
|
|
899
|
+
]);
|
|
900
|
+
|
|
901
|
+
// Should maintain original bar order regardless of selection order
|
|
902
|
+
expect(result.filteredRechartsBars).toHaveLength(3);
|
|
903
|
+
expect(result.filteredRechartsBars[0].dataKey).toBe('Success');
|
|
904
|
+
expect(result.filteredRechartsBars[1].dataKey).toBe('Failed');
|
|
905
|
+
expect(result.filteredRechartsBars[2].dataKey).toBe('Pending');
|
|
906
|
+
});
|
|
907
|
+
});
|