@centreon/ui 25.7.2 → 25.8.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 +1 -1
- package/src/Form/CollapsibleGroup.tsx +10 -10
- package/src/Form/Form.cypress.spec.tsx +137 -2
- package/src/Form/Form.stories.tsx +11 -31
- package/src/Form/Form.tsx +2 -0
- package/src/Form/Inputs/Grid.tsx +10 -28
- package/src/Form/Inputs/SubGroupDivider.tsx +7 -0
- package/src/Form/Inputs/Text.tsx +1 -0
- package/src/Form/Inputs/index.tsx +6 -0
- package/src/Form/Inputs/models.ts +2 -1
- package/src/Form/Section/FormSection.tsx +34 -0
- package/src/Form/Section/PanelTabs.tsx +13 -0
- package/src/Form/Section/navigateToSection.ts +9 -0
- package/src/Form/storiesData.tsx +12 -2
- package/src/Graph/BarChart/BarChart.cypress.spec.tsx +27 -2
- package/src/Graph/BarChart/BarChart.stories.tsx +10 -0
- package/src/Graph/BarChart/BarChart.tsx +19 -3
- package/src/Graph/BarChart/ResponsiveBarChart.tsx +12 -2
- package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +7 -1
- package/src/Graph/Chart/BasicComponents/Lines/index.tsx +10 -2
- package/src/Graph/Chart/Chart.cypress.spec.tsx +66 -13
- package/src/Graph/Chart/Chart.stories.tsx +41 -0
- package/src/Graph/Chart/Chart.tsx +15 -3
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx +8 -2
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx +9 -2
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts +19 -2
- package/src/Graph/Chart/InteractiveComponents/index.tsx +16 -3
- package/src/Graph/Chart/index.tsx +6 -0
- package/src/Graph/Chart/models.ts +3 -0
- package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +5 -4
- package/src/Graph/common/timeSeries/index.ts +105 -34
- package/src/Graph/common/utils.ts +19 -0
- package/src/InputField/Select/Autocomplete/Connected/index.tsx +26 -21
- package/src/ThemeProvider/palettes.ts +1 -1
- package/src/api/models.ts +6 -6
- package/src/components/Modal/Modal.stories.tsx +20 -0
- package/src/components/Modal/Modal.styles.ts +2 -23
- package/src/components/Modal/Modal.tsx +1 -1
- package/src/components/Modal/ModalBody.tsx +6 -4
- package/src/components/Modal/ModalHeader.tsx +5 -5
- package/src/components/Modal/modal.module.css +16 -0
- package/src/components/Tabs/Tab.styles.ts +0 -6
- package/src/components/Tabs/Tabs.tsx +31 -10
package/package.json
CHANGED
|
@@ -35,12 +35,6 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
35
35
|
display: 'flex',
|
|
36
36
|
flexDirection: 'row'
|
|
37
37
|
},
|
|
38
|
-
groupTitleIcon: {
|
|
39
|
-
alignItems: 'center',
|
|
40
|
-
columnGap: theme.spacing(1),
|
|
41
|
-
display: 'flex',
|
|
42
|
-
flexDirection: 'row'
|
|
43
|
-
},
|
|
44
38
|
tooltip: {
|
|
45
39
|
maxWidth: theme.spacing(60)
|
|
46
40
|
},
|
|
@@ -77,7 +71,7 @@ const CollapsibleGroup = ({
|
|
|
77
71
|
disableGutters
|
|
78
72
|
disableRipple
|
|
79
73
|
aria-label={group?.name}
|
|
80
|
-
className={cx(classes.groupTitleContainer, containerClassName)}
|
|
74
|
+
className={`${cx(classes.groupTitleContainer, containerClassName)} bg-background-listing-header`}
|
|
81
75
|
onClick={toggle}
|
|
82
76
|
>
|
|
83
77
|
{containerComponentChildren}
|
|
@@ -94,12 +88,17 @@ const CollapsibleGroup = ({
|
|
|
94
88
|
<>
|
|
95
89
|
{hasGroupTitle && (
|
|
96
90
|
<ContainerComponent>
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
<div
|
|
92
|
+
data-testid={`${group?.name}-header`}
|
|
93
|
+
className={
|
|
94
|
+
'snap-y flex flex-row justify-between w-full pl-3 pr-1 text-white items-center'
|
|
95
|
+
}
|
|
96
|
+
>
|
|
99
97
|
<Typography
|
|
100
|
-
className="groupText"
|
|
98
|
+
className="groupText scroll-m-12 snap-start"
|
|
101
99
|
variant="h6"
|
|
102
100
|
{...group?.titleAttributes}
|
|
101
|
+
data-section-group-form-id={group?.name}
|
|
103
102
|
>
|
|
104
103
|
{t(group?.name as string)}
|
|
105
104
|
</Typography>
|
|
@@ -116,6 +115,7 @@ const CollapsibleGroup = ({
|
|
|
116
115
|
</MuiIconButton>
|
|
117
116
|
</Tooltip>
|
|
118
117
|
)}
|
|
118
|
+
{isCollapsible && <CollapseIcon />}
|
|
119
119
|
</div>
|
|
120
120
|
</ContainerComponent>
|
|
121
121
|
)}
|
|
@@ -132,16 +132,129 @@ describe('Form list', () => {
|
|
|
132
132
|
});
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
const
|
|
135
|
+
const initializeFormWithSections = (): void => {
|
|
136
136
|
cy.mount({
|
|
137
137
|
Component: (
|
|
138
138
|
<Form
|
|
139
|
+
isCollapsible
|
|
139
140
|
initialValues={{
|
|
140
141
|
list: []
|
|
141
142
|
}}
|
|
143
|
+
groups={[
|
|
144
|
+
{
|
|
145
|
+
name: 'First group',
|
|
146
|
+
order: 1
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'Third group',
|
|
150
|
+
order: 3
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'Second group',
|
|
154
|
+
order: 2
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: 'Fourth group',
|
|
158
|
+
order: 4
|
|
159
|
+
}
|
|
160
|
+
]}
|
|
142
161
|
inputs={[
|
|
143
162
|
{
|
|
144
|
-
fieldName: '
|
|
163
|
+
fieldName: 'First name',
|
|
164
|
+
group: 'First group',
|
|
165
|
+
label: 'Name',
|
|
166
|
+
type: InputType.Text
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
fieldName: 'Divider',
|
|
170
|
+
group: 'First group',
|
|
171
|
+
label: 'Divider',
|
|
172
|
+
type: InputType.Divider
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
fieldName: 'Second name',
|
|
176
|
+
group: 'First group',
|
|
177
|
+
label: 'Name',
|
|
178
|
+
type: InputType.Text
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
fieldName: 'Third name',
|
|
182
|
+
group: 'First group',
|
|
183
|
+
label: 'Name',
|
|
184
|
+
type: InputType.Text
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
fieldName: 'Fourth name',
|
|
188
|
+
group: 'First group',
|
|
189
|
+
label: 'Name',
|
|
190
|
+
type: InputType.Text
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
fieldName: 'Fifth name',
|
|
194
|
+
group: 'First group',
|
|
195
|
+
label: 'Name',
|
|
196
|
+
type: InputType.Text
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
fieldName: 'Sixth name',
|
|
200
|
+
group: 'First group',
|
|
201
|
+
label: 'Name',
|
|
202
|
+
type: InputType.Text
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
fieldName: 'Seventh name',
|
|
206
|
+
group: 'First group',
|
|
207
|
+
label: 'Name',
|
|
208
|
+
type: InputType.Text
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
fieldName: 'Eighth name',
|
|
212
|
+
group: 'First group',
|
|
213
|
+
label: 'Name',
|
|
214
|
+
type: InputType.Text
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
fieldName: 'Ninth name',
|
|
218
|
+
group: 'First group',
|
|
219
|
+
label: 'Name',
|
|
220
|
+
type: InputType.Text
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
fieldName: 'First second group name',
|
|
224
|
+
group: 'Second group',
|
|
225
|
+
label: 'Name',
|
|
226
|
+
type: InputType.Text
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
fieldName: 'First third group name',
|
|
230
|
+
group: 'Third group',
|
|
231
|
+
label: 'Name',
|
|
232
|
+
type: InputType.Text
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
fieldName: 'First fourth group name',
|
|
236
|
+
group: 'Fourth group',
|
|
237
|
+
label: 'Name',
|
|
238
|
+
type: InputType.Text
|
|
239
|
+
}
|
|
240
|
+
]}
|
|
241
|
+
submit={cy.stub()}
|
|
242
|
+
validationSchema={object()}
|
|
243
|
+
/>
|
|
244
|
+
)
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const initializeFile = () => {
|
|
249
|
+
cy.mount({
|
|
250
|
+
Component: (
|
|
251
|
+
<Form
|
|
252
|
+
initialValues={{
|
|
253
|
+
list: []
|
|
254
|
+
}}
|
|
255
|
+
inputs={[
|
|
256
|
+
{
|
|
257
|
+
fieldName: 'list',
|
|
145
258
|
group: '',
|
|
146
259
|
label: 'json',
|
|
147
260
|
type: InputType.File,
|
|
@@ -170,3 +283,25 @@ describe('File', () => {
|
|
|
170
283
|
cy.makeSnapshot();
|
|
171
284
|
});
|
|
172
285
|
});
|
|
286
|
+
|
|
287
|
+
describe('Form with sections', () => {
|
|
288
|
+
beforeEach(initializeFormWithSections);
|
|
289
|
+
it('displays sections when correct amount of sections', () => {
|
|
290
|
+
cy.contains('First group').should('be.visible');
|
|
291
|
+
cy.contains('Second group').should('be.visible');
|
|
292
|
+
cy.contains('Third group').should('be.visible');
|
|
293
|
+
cy.contains('Fourth group').should('be.visible');
|
|
294
|
+
cy.makeSnapshot();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('scrolls correctly to section', () => {
|
|
298
|
+
cy.window().then((win) => {
|
|
299
|
+
const initialScrollY = win.scrollY;
|
|
300
|
+
cy.contains('Third group').click();
|
|
301
|
+
cy.window().its('scrollY').should('be.greaterThan', initialScrollY);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
cy.wait(500); // Wait for the scroll animation to complete
|
|
305
|
+
cy.makeSnapshot();
|
|
306
|
+
});
|
|
307
|
+
});
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Paper } from '@mui/material';
|
|
2
|
-
|
|
3
1
|
import { Form, GroupDirection } from './Form';
|
|
4
2
|
import {
|
|
5
3
|
BasicForm,
|
|
@@ -27,51 +25,33 @@ const mandatoryProps = {
|
|
|
27
25
|
};
|
|
28
26
|
|
|
29
27
|
export const basicForm = (): JSX.Element => (
|
|
30
|
-
<
|
|
31
|
-
<Form<BasicForm> {...mandatoryProps} />
|
|
32
|
-
</Paper>
|
|
28
|
+
<Form<BasicForm> {...mandatoryProps} />
|
|
33
29
|
);
|
|
34
30
|
|
|
35
31
|
export const basicFormWithGroups = (): JSX.Element => (
|
|
36
|
-
<
|
|
37
|
-
<Form<BasicForm> {...mandatoryProps} groups={basicFormGroups} />
|
|
38
|
-
</Paper>
|
|
32
|
+
<Form<BasicForm> {...mandatoryProps} groups={basicFormGroups} />
|
|
39
33
|
);
|
|
40
34
|
|
|
41
35
|
export const basicFormWithCollapsibleGroups = (): JSX.Element => (
|
|
42
|
-
<
|
|
43
|
-
<Form<BasicForm>
|
|
44
|
-
{...mandatoryProps}
|
|
45
|
-
isCollapsible
|
|
46
|
-
groups={basicFormGroups}
|
|
47
|
-
/>
|
|
48
|
-
</Paper>
|
|
36
|
+
<Form<BasicForm> {...mandatoryProps} isCollapsible groups={basicFormGroups} />
|
|
49
37
|
);
|
|
50
38
|
|
|
51
39
|
export const basicFormWithCustomButton = (): JSX.Element => (
|
|
52
|
-
<
|
|
53
|
-
<Form<BasicForm> {...mandatoryProps} Buttons={CustomButton} />
|
|
54
|
-
</Paper>
|
|
40
|
+
<Form<BasicForm> {...mandatoryProps} Buttons={CustomButton} />
|
|
55
41
|
);
|
|
56
42
|
|
|
57
43
|
export const loadingForm = (): JSX.Element => (
|
|
58
|
-
<
|
|
59
|
-
<Form<BasicForm> {...mandatoryProps} isLoading />
|
|
60
|
-
</Paper>
|
|
44
|
+
<Form<BasicForm> {...mandatoryProps} isLoading />
|
|
61
45
|
);
|
|
62
46
|
|
|
63
47
|
export const loadingFormWithGroups = (): JSX.Element => (
|
|
64
|
-
<
|
|
65
|
-
<Form<BasicForm> {...mandatoryProps} isLoading groups={basicFormGroups} />
|
|
66
|
-
</Paper>
|
|
48
|
+
<Form<BasicForm> {...mandatoryProps} isLoading groups={basicFormGroups} />
|
|
67
49
|
);
|
|
68
50
|
|
|
69
51
|
export const basicFormWithHorizontalGroups = (): JSX.Element => (
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/>
|
|
76
|
-
</Paper>
|
|
52
|
+
<Form<BasicForm>
|
|
53
|
+
{...mandatoryProps}
|
|
54
|
+
groupDirection={GroupDirection.Horizontal}
|
|
55
|
+
groups={basicFormGroups.filter((group) => group.order !== 3)}
|
|
56
|
+
/>
|
|
77
57
|
);
|
package/src/Form/Form.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import { useStyles } from './Form.styles';
|
|
|
11
11
|
import FormButtons from './FormButtons';
|
|
12
12
|
import Inputs from './Inputs';
|
|
13
13
|
import { Group, InputProps } from './Inputs/models';
|
|
14
|
+
import { FormSection } from './Section/FormSection';
|
|
14
15
|
|
|
15
16
|
export enum GroupDirection {
|
|
16
17
|
Horizontal = 'horizontal',
|
|
@@ -76,6 +77,7 @@ const Form = <T extends object>({
|
|
|
76
77
|
{...formikSharedConfig}
|
|
77
78
|
>
|
|
78
79
|
<div>
|
|
80
|
+
<FormSection groups={groups} />
|
|
79
81
|
{children}
|
|
80
82
|
<div className={cx(className, classes.form)}>
|
|
81
83
|
<Inputs
|
package/src/Form/Inputs/Grid.tsx
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { makeStyles } from 'tss-react/mui';
|
|
2
|
-
|
|
3
1
|
import { InputPropsWithoutGroup } from './models';
|
|
4
2
|
|
|
5
3
|
import { Box, Typography } from '@mui/material';
|
|
@@ -7,34 +5,10 @@ import { FormikValues, useFormikContext } from 'formik';
|
|
|
7
5
|
import { isNotEmpty, isNotNil } from 'ramda';
|
|
8
6
|
import { getInput } from '.';
|
|
9
7
|
|
|
10
|
-
interface StylesProps {
|
|
11
|
-
alignItems?: string;
|
|
12
|
-
columns?: number;
|
|
13
|
-
gridTemplateColumns?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const useStyles = makeStyles<StylesProps>()(
|
|
17
|
-
(theme, { columns, gridTemplateColumns, alignItems }) => ({
|
|
18
|
-
gridFields: {
|
|
19
|
-
alignItems: alignItems || 'flex-start',
|
|
20
|
-
columnGap: theme.spacing(4),
|
|
21
|
-
display: 'grid',
|
|
22
|
-
gridTemplateColumns: gridTemplateColumns || `repeat(${columns}, 1fr)`,
|
|
23
|
-
rowGap: theme.spacing(2)
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
);
|
|
27
|
-
|
|
28
8
|
const Grid = ({
|
|
29
9
|
grid,
|
|
30
10
|
hideInput
|
|
31
11
|
}: InputPropsWithoutGroup): JSX.Element | null => {
|
|
32
|
-
const { classes, cx } = useStyles({
|
|
33
|
-
alignItems: grid?.alignItems,
|
|
34
|
-
columns: grid?.columns.length,
|
|
35
|
-
gridTemplateColumns: grid?.gridTemplateColumns
|
|
36
|
-
});
|
|
37
|
-
|
|
38
12
|
const { values } = useFormikContext<FormikValues>();
|
|
39
13
|
|
|
40
14
|
if (hideInput?.(values) ?? false) {
|
|
@@ -44,7 +18,15 @@ const Grid = ({
|
|
|
44
18
|
const className = grid?.className || '';
|
|
45
19
|
|
|
46
20
|
return (
|
|
47
|
-
<div
|
|
21
|
+
<div
|
|
22
|
+
className={`${className} grid gap-3`}
|
|
23
|
+
style={{
|
|
24
|
+
gridTemplateColumns:
|
|
25
|
+
className ? grid?.gridTemplateColumns || undefined : grid?.gridTemplateColumns ||
|
|
26
|
+
`repeat(${grid?.columns.length || 1}, 1fr)`,
|
|
27
|
+
alignItems: grid?.alignItems || 'flex-start'
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
48
30
|
{grid?.columns.map((field) => {
|
|
49
31
|
const Input = getInput(field.type);
|
|
50
32
|
|
|
@@ -62,7 +44,7 @@ const Grid = ({
|
|
|
62
44
|
{field.additionalLabel && (
|
|
63
45
|
<Typography
|
|
64
46
|
sx={{ marginBottom: 0.5, color: 'primary.main' }}
|
|
65
|
-
className={
|
|
47
|
+
className={field?.additionalLabelClassName}
|
|
66
48
|
variant="h6"
|
|
67
49
|
>
|
|
68
50
|
{field.additionalLabel}
|
package/src/Form/Inputs/Text.tsx
CHANGED
|
@@ -43,6 +43,7 @@ import Grid from './Grid';
|
|
|
43
43
|
import List from './List/List';
|
|
44
44
|
import LoadingSkeleton from './LoadingSkeleton';
|
|
45
45
|
import RadioInput from './Radio';
|
|
46
|
+
import { SubgroupDivider } from './SubGroupDivider';
|
|
46
47
|
import SwitchInput from './Switch';
|
|
47
48
|
import TextInput from './Text';
|
|
48
49
|
import { Group, InputProps, InputPropsWithoutGroup, InputType } from './models';
|
|
@@ -82,6 +83,11 @@ export const getInput = cond<
|
|
|
82
83
|
],
|
|
83
84
|
[equals(InputType.List) as (b: InputType) => boolean, always(List)],
|
|
84
85
|
[equals(InputType.File) as (b: InputType) => boolean, always(File)],
|
|
86
|
+
[equals(InputType.Text) as (b: InputType) => boolean, always(TextInput)],
|
|
87
|
+
[
|
|
88
|
+
equals(InputType.Divider) as (b: InputType) => boolean,
|
|
89
|
+
always(SubgroupDivider)
|
|
90
|
+
],
|
|
85
91
|
[T, always(TextInput)]
|
|
86
92
|
]);
|
|
87
93
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Box, TabsProps } from '@mui/material';
|
|
2
|
+
import { isNil } from 'ramda';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { Tabs } from '../../components/Tabs';
|
|
5
|
+
import { Group } from '../Inputs/models';
|
|
6
|
+
import { groupToTab } from './PanelTabs';
|
|
7
|
+
import { useNavigateToSection } from './navigateToSection';
|
|
8
|
+
|
|
9
|
+
export interface FormSectionProps extends TabsProps {
|
|
10
|
+
groups?: Group[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const FormSection = ({ groups }: FormSectionProps) => {
|
|
14
|
+
if (isNil(groups) || groups.length < 4) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const navigateToSection = useNavigateToSection();
|
|
19
|
+
const tabMemo = useMemo(() => groupToTab(groups), [groups]);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Box className="sticky top-0 bg-background-paper z-100">
|
|
23
|
+
<Tabs
|
|
24
|
+
variant="scrollable"
|
|
25
|
+
scrollButtons={false}
|
|
26
|
+
tabs={tabMemo}
|
|
27
|
+
defaultTab={tabMemo[0].value}
|
|
28
|
+
onChange={navigateToSection}
|
|
29
|
+
/>
|
|
30
|
+
</Box>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { FormSection };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { prop, sortBy } from 'ramda';
|
|
2
|
+
import { TabI } from 'src/components/Tabs/Tabs';
|
|
3
|
+
import { Group } from '../Inputs/models';
|
|
4
|
+
|
|
5
|
+
const groupToTab = (groups: Array<Group>): Array<TabI> => {
|
|
6
|
+
const sortedGroups = sortBy(prop('order'), groups);
|
|
7
|
+
|
|
8
|
+
return sortedGroups.map((group) => {
|
|
9
|
+
return { value: group.name, label: group.name };
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { groupToTab };
|
package/src/Form/storiesData.tsx
CHANGED
|
@@ -157,12 +157,16 @@ export const basicFormGroups: Array<Group> = [
|
|
|
157
157
|
{
|
|
158
158
|
EndIcon: () => <HelpOutlineIcon />,
|
|
159
159
|
TooltipContent: (): JSX.Element => <Typography>Tooltip content</Typography>,
|
|
160
|
+
name: 'Third group',
|
|
161
|
+
order: 3
|
|
162
|
+
},
|
|
163
|
+
{
|
|
160
164
|
name: 'Second group',
|
|
161
165
|
order: 2
|
|
162
166
|
},
|
|
163
167
|
{
|
|
164
|
-
name: '
|
|
165
|
-
order:
|
|
168
|
+
name: 'Fourth group',
|
|
169
|
+
order: 4
|
|
166
170
|
}
|
|
167
171
|
];
|
|
168
172
|
|
|
@@ -215,6 +219,12 @@ export const basicFormInputs: Array<InputProps> = [
|
|
|
215
219
|
},
|
|
216
220
|
type: InputType.Radio
|
|
217
221
|
},
|
|
222
|
+
{
|
|
223
|
+
fieldName: 'div',
|
|
224
|
+
group: 'First group',
|
|
225
|
+
label: 'divider',
|
|
226
|
+
type: InputType.Divider
|
|
227
|
+
},
|
|
218
228
|
{
|
|
219
229
|
additionalLabel: 'Notifications',
|
|
220
230
|
fieldName: '',
|
|
@@ -30,10 +30,20 @@ const initialize = ({
|
|
|
30
30
|
tooltip,
|
|
31
31
|
axis,
|
|
32
32
|
orientation,
|
|
33
|
-
barStyle
|
|
33
|
+
barStyle,
|
|
34
|
+
min,
|
|
35
|
+
max
|
|
34
36
|
}: Pick<
|
|
35
37
|
BarChartProps,
|
|
36
|
-
|
|
38
|
+
| 'data'
|
|
39
|
+
| 'legend'
|
|
40
|
+
| 'axis'
|
|
41
|
+
| 'barStyle'
|
|
42
|
+
| 'orientation'
|
|
43
|
+
| 'tooltip'
|
|
44
|
+
| 'start'
|
|
45
|
+
| 'min'
|
|
46
|
+
| 'max'
|
|
37
47
|
>): void => {
|
|
38
48
|
cy.adjustViewport();
|
|
39
49
|
|
|
@@ -47,6 +57,8 @@ const initialize = ({
|
|
|
47
57
|
legend={legend}
|
|
48
58
|
orientation={orientation ?? 'horizontal'}
|
|
49
59
|
tooltip={tooltip}
|
|
60
|
+
min={min}
|
|
61
|
+
max={max}
|
|
50
62
|
{...defaultArgs}
|
|
51
63
|
/>
|
|
52
64
|
</div>
|
|
@@ -287,4 +299,17 @@ describe('Bar chart', () => {
|
|
|
287
299
|
cy.contains('05/31/2023').should('be.visible');
|
|
288
300
|
cy.contains('06/07/2023').should('be.visible');
|
|
289
301
|
});
|
|
302
|
+
|
|
303
|
+
it('displays the bar chart according to min and max boundaries', () => {
|
|
304
|
+
initialize({
|
|
305
|
+
data: dataLastWeek,
|
|
306
|
+
min: -0.05,
|
|
307
|
+
max: 1
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
cy.contains('05/31/2023').should('be.visible');
|
|
311
|
+
cy.contains('06/07/2023').should('be.visible');
|
|
312
|
+
cy.contains('1 s').should('be.visible');
|
|
313
|
+
cy.contains('1%').should('be.visible');
|
|
314
|
+
});
|
|
290
315
|
});
|
|
@@ -250,3 +250,13 @@ export const mixedStackedVertical: Story = {
|
|
|
250
250
|
},
|
|
251
251
|
render: Template
|
|
252
252
|
};
|
|
253
|
+
|
|
254
|
+
export const mixedStackedMinMax: Story = {
|
|
255
|
+
args: {
|
|
256
|
+
...defaultArgs,
|
|
257
|
+
data: dataPingServiceMixedStacked,
|
|
258
|
+
min: 10,
|
|
259
|
+
max: 20
|
|
260
|
+
},
|
|
261
|
+
render: Template
|
|
262
|
+
};
|
|
@@ -10,11 +10,11 @@ import { Provider } from 'jotai';
|
|
|
10
10
|
|
|
11
11
|
import { Box } from '@mui/material';
|
|
12
12
|
|
|
13
|
+
import Loading from '../../LoadingSkeleton';
|
|
13
14
|
import LoadingSkeleton from '../Chart/LoadingSkeleton';
|
|
14
15
|
import { LineChartProps } from '../Chart/models';
|
|
15
16
|
import useChartData from '../Chart/useChartData';
|
|
16
17
|
import { LineChartData, Thresholds } from '../common/models';
|
|
17
|
-
import Loading from '../../LoadingSkeleton';
|
|
18
18
|
|
|
19
19
|
import useResizeObserver from 'use-resize-observer';
|
|
20
20
|
import ResponsiveBarChart from './ResponsiveBarChart';
|
|
@@ -26,7 +26,17 @@ dayjs.extend(timezonePlugin);
|
|
|
26
26
|
|
|
27
27
|
export interface BarChartProps
|
|
28
28
|
extends Partial<
|
|
29
|
-
Pick<
|
|
29
|
+
Pick<
|
|
30
|
+
LineChartProps,
|
|
31
|
+
| 'tooltip'
|
|
32
|
+
| 'legend'
|
|
33
|
+
| 'height'
|
|
34
|
+
| 'axis'
|
|
35
|
+
| 'header'
|
|
36
|
+
| 'min'
|
|
37
|
+
| 'max'
|
|
38
|
+
| 'boundariesUnit'
|
|
39
|
+
>
|
|
30
40
|
> {
|
|
31
41
|
barStyle?: BarStyle;
|
|
32
42
|
data?: LineChartData;
|
|
@@ -58,7 +68,10 @@ const BarChart = ({
|
|
|
58
68
|
opacity: 1,
|
|
59
69
|
radius: 0.2
|
|
60
70
|
},
|
|
61
|
-
skipIntersectionObserver
|
|
71
|
+
skipIntersectionObserver,
|
|
72
|
+
min,
|
|
73
|
+
max,
|
|
74
|
+
boundariesUnit
|
|
62
75
|
}: BarChartProps): JSX.Element => {
|
|
63
76
|
const { adjustedData } = useChartData({ data, end, start });
|
|
64
77
|
const { ref, width, height: responsiveHeight } = useResizeObserver();
|
|
@@ -93,6 +106,9 @@ const BarChart = ({
|
|
|
93
106
|
tooltip={tooltip}
|
|
94
107
|
width={width || 0}
|
|
95
108
|
skipIntersectionObserver={skipIntersectionObserver}
|
|
109
|
+
min={min}
|
|
110
|
+
max={max}
|
|
111
|
+
boundariesUnit={boundariesUnit}
|
|
96
112
|
/>
|
|
97
113
|
)}
|
|
98
114
|
</Box>
|
|
@@ -40,6 +40,9 @@ interface Props
|
|
|
40
40
|
thresholds?: ThresholdsModel;
|
|
41
41
|
width: number;
|
|
42
42
|
skipIntersectionObserver?: boolean;
|
|
43
|
+
min?: number;
|
|
44
|
+
max?: number;
|
|
45
|
+
boundariesUnit?: string;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
const ResponsiveBarChart = ({
|
|
@@ -56,7 +59,10 @@ const ResponsiveBarChart = ({
|
|
|
56
59
|
orientation,
|
|
57
60
|
tooltip,
|
|
58
61
|
barStyle,
|
|
59
|
-
skipIntersectionObserver
|
|
62
|
+
skipIntersectionObserver,
|
|
63
|
+
min,
|
|
64
|
+
max,
|
|
65
|
+
boundariesUnit
|
|
60
66
|
}: Props): JSX.Element => {
|
|
61
67
|
const { title, timeSeries, baseAxis, lines } = graphData || {};
|
|
62
68
|
|
|
@@ -131,7 +137,11 @@ const ResponsiveBarChart = ({
|
|
|
131
137
|
thresholdUnit,
|
|
132
138
|
thresholds: (thresholds?.enabled && thresholdValues) || [],
|
|
133
139
|
valueGraphHeight:
|
|
134
|
-
(isHorizontal ? graphHeight : graphWidth) - margin.bottom
|
|
140
|
+
(isHorizontal ? graphHeight : graphWidth) - margin.bottom,
|
|
141
|
+
min,
|
|
142
|
+
max,
|
|
143
|
+
isBarChart: true,
|
|
144
|
+
boundariesUnit
|
|
135
145
|
}),
|
|
136
146
|
[
|
|
137
147
|
displayedLines,
|