@centreon/ui 24.4.8 → 24.4.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.
- package/package.json +17 -12
- package/src/Button/Save/StartIcon.tsx +3 -3
- package/src/Dashboard/Item.tsx +1 -1
- package/src/Dashboard/Layout.tsx +2 -2
- package/src/FileDropZone/index.tsx +3 -1
- package/src/Form/Form.cypress.spec.tsx +133 -0
- package/src/Form/Inputs/CheckboxGroup.tsx +1 -4
- package/src/Form/Inputs/List/Content.tsx +62 -0
- package/src/Form/Inputs/List/List.styles.ts +29 -0
- package/src/Form/Inputs/List/List.tsx +58 -0
- package/src/Form/Inputs/List/useList.ts +81 -0
- package/src/Form/Inputs/index.tsx +3 -1
- package/src/Form/Inputs/models.ts +9 -1
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx +2 -2
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +5 -4
- package/src/Graph/LineChart/BasicComponents/Thresholds.tsx +2 -2
- package/src/Graph/LineChart/BasicComponents/useFilterLines.ts +1 -1
- package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +2 -2
- package/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx +2 -3
- package/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx +1 -1
- package/src/Graph/LineChart/Legend/useLegend.ts +3 -3
- package/src/Graph/LineChart/helpers/doc.ts +16 -13
- package/src/Graph/LineChart/helpers/index.ts +1 -1
- package/src/Graph/LineChart/index.stories.tsx +4 -2
- package/src/Graph/SingleBar/Thresholds.tsx +2 -2
- package/src/Graph/Text/Text.stories.tsx +60 -4
- package/src/Graph/common/timeSeries/index.ts +3 -3
- package/src/InputField/Select/Autocomplete/Connected/index.tsx +10 -7
- package/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx +1 -1
- package/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx +1 -1
- package/src/InputField/Select/Autocomplete/Draggable/index.tsx +1 -1
- package/src/InputField/Select/IconPopover/index.tsx +2 -2
- package/src/InputField/Select/index.tsx +1 -1
- package/src/Listing/Header/ListingHeader.tsx +1 -1
- package/src/Listing/Listing.styles.ts +2 -3
- package/src/Listing/index.stories.tsx +12 -1
- package/src/Listing/index.tsx +1 -2
- package/src/RichTextEditor/RichTextEditor.tsx +12 -1
- package/src/SortableItems/index.tsx +2 -7
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +8 -3
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +0 -2
- package/src/TimePeriods/DateTimePickerInput.tsx +45 -17
- package/src/TimePeriods/TimePeriods.cypress.spec.tsx +9 -33
- package/src/TimePeriods/helpers/index.ts +1 -1
- package/src/TimePeriods/index.stories.tsx +12 -4
- package/src/TimePeriods/index.tsx +2 -2
- package/src/Typography/Subtitle.tsx +55 -0
- package/src/api/QueryProvider.tsx +1 -1
- package/src/api/TestQueryProvider.tsx +1 -1
- package/src/api/useFetchQuery/index.ts +27 -23
- package/src/api/useMutationQuery/index.ts +41 -17
- package/src/components/DataTable/DataListing.tsx +6 -0
- package/src/components/DataTable/DataTable.cypress.spec.tsx +193 -0
- package/src/components/DataTable/DataTable.stories.tsx +40 -0
- package/src/components/DataTable/DataTable.styles.ts +3 -0
- package/src/components/DataTable/DataTable.tsx +3 -3
- package/src/components/DataTable/Item/DataTableItem.styles.ts +7 -2
- package/src/components/DataTable/Item/DataTableItem.tsx +2 -2
- package/src/components/DataTable/index.ts +3 -1
- package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +2 -0
- package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +1 -1
- package/src/components/Form/Dashboard/DashboardForm.tsx +15 -12
- package/src/components/Modal/Modal.styles.ts +4 -3
- package/src/components/Modal/ModalActions.tsx +4 -2
- package/src/index.ts +2 -0
- package/src/queryParameters/url/index.ts +5 -1
- package/src/utils/index.ts +1 -1
- package/src/utils/{useLicenseExpirationWarning.cypress.spec.tsx → useLicenseExpirationWarning.test.tsx} +48 -37
- package/src/utils/useLicenseExpirationWarning.ts +18 -18
- package/src/utils/usePluralizedTranslation.ts +21 -0
- package/src/screens/dashboard/DashboardsDetail.stories.tsx +0 -108
- package/src/screens/dashboard/DashboardsOverview.stories.tsx +0 -281
- package/src/utils/useDateTimePickerAdapter.ts +0 -309
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "24.4.
|
|
3
|
+
"version": "24.4.10",
|
|
4
4
|
"description": "Centreon UI Components",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"test:ci": "jest --silent --reporter=jest-junit",
|
|
13
13
|
"cypress:ui": "cypress open --component --browser=chrome",
|
|
14
14
|
"cypress:cli:updateSnapshot": "pnpm cypress:cli --env updateSnapshots=true",
|
|
15
|
+
"cypress:run:coverage": "cypress run --component --browser=chrome --env codeCoverageTasksRegistered=true",
|
|
15
16
|
"cypress:cli": "cypress run --component --browser=chrome",
|
|
16
17
|
"tokens:transform": "TS_NODE_PROJECT=tsconfig.node.json ts-node style-dictionary.transform.ts"
|
|
17
18
|
},
|
|
@@ -73,13 +74,14 @@
|
|
|
73
74
|
"@testing-library/react-hooks": "^8.0.1",
|
|
74
75
|
"@types/cypress": "^1.1.3",
|
|
75
76
|
"@types/jest": "^27.5.0",
|
|
76
|
-
"@types/
|
|
77
|
+
"@types/mocha": "^10.0.6",
|
|
78
|
+
"@types/ramda": "^0.29.6",
|
|
77
79
|
"@types/react": "^18.0.26",
|
|
78
80
|
"@types/testing-library__jest-dom": "^5.14.6",
|
|
79
81
|
"@vitejs/plugin-react": "^4.0.0",
|
|
80
82
|
"@vitejs/plugin-react-swc": "^3.3.0",
|
|
81
83
|
"axios-mock-adapter": "^1.21.4",
|
|
82
|
-
"cypress": "^
|
|
84
|
+
"cypress": "^13.3.1",
|
|
83
85
|
"identity-obj-proxy": "^3.0.0",
|
|
84
86
|
"jest-transform-stub": "^2.0.0",
|
|
85
87
|
"mochawesome": "^7.1.3",
|
|
@@ -97,16 +99,18 @@
|
|
|
97
99
|
"ts-node": "^10.9.1",
|
|
98
100
|
"use-resize-observer": "^9.1.0",
|
|
99
101
|
"vite": "^4.3.5",
|
|
102
|
+
"vite-plugin-istanbul": "^5.0.0",
|
|
100
103
|
"vite-plugin-svgr": "^3.2.0",
|
|
101
104
|
"vite-plugin-turbosnap": "^1.0.2"
|
|
102
105
|
},
|
|
103
106
|
"dependencies": {
|
|
104
|
-
"@lexical/
|
|
105
|
-
"@lexical/
|
|
106
|
-
"@lexical/
|
|
107
|
-
"@lexical/
|
|
108
|
-
"@lexical/
|
|
109
|
-
"@lexical/
|
|
107
|
+
"@lexical/html": "^0.12.2",
|
|
108
|
+
"@lexical/link": "^0.12.2",
|
|
109
|
+
"@lexical/list": "^0.12.2",
|
|
110
|
+
"@lexical/react": "^0.12.2",
|
|
111
|
+
"@lexical/rich-text": "^0.12.2",
|
|
112
|
+
"@lexical/selection": "^0.12.2",
|
|
113
|
+
"@lexical/utils": "^0.12.2",
|
|
110
114
|
"@react-spring/web": "^9.7.3",
|
|
111
115
|
"@visx/curve": "^2.1.0",
|
|
112
116
|
"@visx/group": "^3.3.0",
|
|
@@ -118,8 +122,9 @@
|
|
|
118
122
|
"anylogger": "^1.0.11",
|
|
119
123
|
"d3-array": "3.2.0",
|
|
120
124
|
"humanize-duration": "^3.27.3",
|
|
121
|
-
"lexical": "0.
|
|
122
|
-
"notistack": "^
|
|
125
|
+
"lexical": "^0.12.2",
|
|
126
|
+
"notistack": "^3.0.1",
|
|
127
|
+
"ramda": "0.29.1",
|
|
123
128
|
"react-grid-layout": "^1.3.4",
|
|
124
129
|
"react-html-parser": "^2.0.2",
|
|
125
130
|
"react-resizable": "^3.0.5",
|
|
@@ -135,7 +140,7 @@
|
|
|
135
140
|
"@mui/icons-material": "5.x",
|
|
136
141
|
"@mui/material": "5.x",
|
|
137
142
|
"@mui/styles": "5.x",
|
|
138
|
-
"@tanstack/react-query": "
|
|
143
|
+
"@tanstack/react-query": "5.x",
|
|
139
144
|
"axios": "0.x",
|
|
140
145
|
"dayjs": "1.x",
|
|
141
146
|
"formik": "2.x",
|
|
@@ -15,9 +15,9 @@ interface Props {
|
|
|
15
15
|
|
|
16
16
|
const StartIcon = ({ startIconConfig }: Props): JSX.Element | null =>
|
|
17
17
|
cond<Array<StartIconConfigProps>, JSX.Element | null>([
|
|
18
|
-
[pipe(propEq('hasLabel'
|
|
19
|
-
[propEq('succeeded'
|
|
20
|
-
[propEq('loading'
|
|
18
|
+
[pipe(propEq(true, 'hasLabel'), not), always(null)],
|
|
19
|
+
[propEq(true, 'succeeded'), always(<CheckIcon />)],
|
|
20
|
+
[propEq(true, 'loading'), always(<SaveIcon />)],
|
|
21
21
|
[T, always(<SaveIcon />)]
|
|
22
22
|
])(startIconConfig);
|
|
23
23
|
|
package/src/Dashboard/Item.tsx
CHANGED
package/src/Dashboard/Layout.tsx
CHANGED
|
@@ -23,7 +23,7 @@ interface DashboardLayoutProps<T> {
|
|
|
23
23
|
layout: Array<T>;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const DashboardLayout = <T extends Layout>({
|
|
27
27
|
children,
|
|
28
28
|
changeLayout,
|
|
29
29
|
displayGrid,
|
|
@@ -76,4 +76,4 @@ const Layout = <T extends Layout>({
|
|
|
76
76
|
});
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
export default
|
|
79
|
+
export default DashboardLayout;
|
|
@@ -98,7 +98,9 @@ const getExtensions = cond([
|
|
|
98
98
|
[T, identity]
|
|
99
99
|
]) as (accept: string) => Array<string>;
|
|
100
100
|
|
|
101
|
-
export const transformFileListToArray = (
|
|
101
|
+
export const transformFileListToArray = (
|
|
102
|
+
files: FileList | null
|
|
103
|
+
): Array<File> =>
|
|
102
104
|
isNil(files)
|
|
103
105
|
? []
|
|
104
106
|
: (Array(files.length)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { object } from 'yup';
|
|
2
|
+
import { faker } from '@faker-js/faker';
|
|
3
|
+
import { useFormikContext } from 'formik';
|
|
4
|
+
|
|
5
|
+
import { Typography } from '@mui/material';
|
|
6
|
+
|
|
7
|
+
import { Button } from '../components';
|
|
8
|
+
|
|
9
|
+
import { Form } from './Form';
|
|
10
|
+
import { InputType } from './Inputs/models';
|
|
11
|
+
|
|
12
|
+
faker.seed(42);
|
|
13
|
+
|
|
14
|
+
const AddItem = ({ addItem }: { addItem: (item) => void }): JSX.Element => {
|
|
15
|
+
const { values } = useFormikContext();
|
|
16
|
+
const add = (): void => {
|
|
17
|
+
addItem({
|
|
18
|
+
alias: faker.company.name(),
|
|
19
|
+
id: values.list.length,
|
|
20
|
+
name: faker.person.firstName()
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Button variant="ghost" onClick={add}>
|
|
26
|
+
Add item
|
|
27
|
+
</Button>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const SortContent = ({
|
|
32
|
+
name,
|
|
33
|
+
alias
|
|
34
|
+
}: {
|
|
35
|
+
alias: string;
|
|
36
|
+
name: string;
|
|
37
|
+
}): JSX.Element => (
|
|
38
|
+
<Typography>
|
|
39
|
+
{name} ({alias})
|
|
40
|
+
</Typography>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const initializeFormList = (): void => {
|
|
44
|
+
cy.mount({
|
|
45
|
+
Component: (
|
|
46
|
+
<Form
|
|
47
|
+
initialValues={{
|
|
48
|
+
list: []
|
|
49
|
+
}}
|
|
50
|
+
inputs={[
|
|
51
|
+
{
|
|
52
|
+
fieldName: 'list',
|
|
53
|
+
group: '',
|
|
54
|
+
label: '',
|
|
55
|
+
list: {
|
|
56
|
+
AddItem,
|
|
57
|
+
SortContent,
|
|
58
|
+
addItemLabel: 'Add an item to the list',
|
|
59
|
+
itemProps: ['id', 'name', 'alias'],
|
|
60
|
+
sortLabel: 'Sort items'
|
|
61
|
+
},
|
|
62
|
+
type: InputType.List
|
|
63
|
+
}
|
|
64
|
+
]}
|
|
65
|
+
submit={cy.stub()}
|
|
66
|
+
validationSchema={object()}
|
|
67
|
+
/>
|
|
68
|
+
)
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
describe('Form list', () => {
|
|
73
|
+
beforeEach(initializeFormList);
|
|
74
|
+
|
|
75
|
+
it('adds an element to the list', () => {
|
|
76
|
+
cy.contains('Add an item to the list').should('be.visible');
|
|
77
|
+
cy.contains('Sort items').should('be.visible');
|
|
78
|
+
|
|
79
|
+
cy.contains('Add item').click();
|
|
80
|
+
|
|
81
|
+
cy.findByLabelText('sort-0').should('be.visible');
|
|
82
|
+
cy.findByLabelText('delete-0').should('be.visible');
|
|
83
|
+
cy.contains('Christelle (Schinner - Wiegand)').should('be.visible');
|
|
84
|
+
|
|
85
|
+
cy.makeSnapshot();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('sorts elements in the list', () => {
|
|
89
|
+
cy.contains('Add an item to the list').should('be.visible');
|
|
90
|
+
cy.contains('Sort items').should('be.visible');
|
|
91
|
+
|
|
92
|
+
cy.contains('Add item').click();
|
|
93
|
+
cy.contains('Add item').click();
|
|
94
|
+
|
|
95
|
+
cy.findByLabelText('sort-0').should('be.visible');
|
|
96
|
+
cy.findByLabelText('delete-0').should('be.visible');
|
|
97
|
+
cy.contains('Carley (Satterfield, Miller and Metz)').should('be.visible');
|
|
98
|
+
cy.findByLabelText('sort-1').should('be.visible');
|
|
99
|
+
cy.findByLabelText('delete-1').should('be.visible');
|
|
100
|
+
cy.contains('Anderson (Crist - Bradtke)').should('be.visible');
|
|
101
|
+
|
|
102
|
+
cy.moveSortableElementUsingAriaLabel({
|
|
103
|
+
ariaLabel: 'sort-0',
|
|
104
|
+
direction: 'down'
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
cy.contains('Carley (Satterfield, Miller and Metz)').should('be.visible');
|
|
108
|
+
cy.contains('Anderson (Crist - Bradtke)').should('be.visible');
|
|
109
|
+
|
|
110
|
+
cy.makeSnapshot();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('removes an element from the list', () => {
|
|
114
|
+
cy.contains('Add an item to the list').should('be.visible');
|
|
115
|
+
cy.contains('Sort items').should('be.visible');
|
|
116
|
+
|
|
117
|
+
cy.contains('Add item').click();
|
|
118
|
+
cy.contains('Add item').click();
|
|
119
|
+
|
|
120
|
+
cy.findByLabelText('sort-0').should('be.visible');
|
|
121
|
+
cy.findByLabelText('delete-0').should('be.visible');
|
|
122
|
+
cy.contains('Lea (Streich - Hartmann)').should('be.visible');
|
|
123
|
+
cy.findByLabelText('sort-1').should('be.visible');
|
|
124
|
+
cy.findByLabelText('delete-1').should('be.visible');
|
|
125
|
+
cy.contains('Akeem (Quigley LLC)').should('be.visible');
|
|
126
|
+
|
|
127
|
+
cy.findByLabelText('delete-0').click();
|
|
128
|
+
|
|
129
|
+
cy.contains('Lea (Streich - Hartmann)').should('not.exist');
|
|
130
|
+
|
|
131
|
+
cy.makeSnapshot();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { DraggableSyntheticListeners } from '@dnd-kit/core';
|
|
4
|
+
|
|
5
|
+
import KrilinIndicatorIcon from '@mui/icons-material/DragIndicator';
|
|
6
|
+
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
|
7
|
+
|
|
8
|
+
import { IconButton } from '../../../components';
|
|
9
|
+
|
|
10
|
+
import { useListStyles } from './List.styles';
|
|
11
|
+
|
|
12
|
+
export interface ContentProps {
|
|
13
|
+
attributes;
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
deleteItem: (id: string) => () => void;
|
|
16
|
+
id: string;
|
|
17
|
+
isDragging: boolean;
|
|
18
|
+
isInDragOverlay?: boolean;
|
|
19
|
+
itemRef: React.RefObject<HTMLDivElement>;
|
|
20
|
+
listeners: DraggableSyntheticListeners;
|
|
21
|
+
name: string;
|
|
22
|
+
style;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const Content = ({
|
|
26
|
+
listeners,
|
|
27
|
+
itemRef,
|
|
28
|
+
attributes,
|
|
29
|
+
style,
|
|
30
|
+
isDragging,
|
|
31
|
+
id,
|
|
32
|
+
children,
|
|
33
|
+
deleteItem
|
|
34
|
+
}: ContentProps): JSX.Element => {
|
|
35
|
+
const { classes } = useListStyles();
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
className={classes.content}
|
|
40
|
+
ref={itemRef}
|
|
41
|
+
{...attributes}
|
|
42
|
+
style={style}
|
|
43
|
+
>
|
|
44
|
+
<IconButton
|
|
45
|
+
data-dragging={isDragging}
|
|
46
|
+
size="small"
|
|
47
|
+
{...listeners}
|
|
48
|
+
aria-label={`sort-${id}`}
|
|
49
|
+
icon={<KrilinIndicatorIcon fontSize="small" />}
|
|
50
|
+
/>
|
|
51
|
+
<div className={classes.innerContent}>{children}</div>
|
|
52
|
+
<IconButton
|
|
53
|
+
aria-label={`delete-${id}`}
|
|
54
|
+
icon={<DeleteOutlineIcon color="error" fontSize="small" />}
|
|
55
|
+
size="small"
|
|
56
|
+
onClick={deleteItem(id)}
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default Content;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { makeStyles } from 'tss-react/mui';
|
|
2
|
+
|
|
3
|
+
export const useListStyles = makeStyles()((theme) => ({
|
|
4
|
+
content: {
|
|
5
|
+
'& [data-dragging="false"]': {
|
|
6
|
+
cursor: 'grab'
|
|
7
|
+
},
|
|
8
|
+
'& [data-dragging="true"]': {
|
|
9
|
+
cursor: 'grabbing'
|
|
10
|
+
},
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
borderBottom: `1px dashed ${theme.palette.action.disabledBackground}`,
|
|
13
|
+
display: 'flex',
|
|
14
|
+
flexDirection: 'row',
|
|
15
|
+
padding: theme.spacing(1, 0)
|
|
16
|
+
},
|
|
17
|
+
innerContent: {
|
|
18
|
+
flexGrow: 1
|
|
19
|
+
},
|
|
20
|
+
items: {
|
|
21
|
+
maxHeight: theme.spacing(16),
|
|
22
|
+
overflowY: 'auto'
|
|
23
|
+
},
|
|
24
|
+
list: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
flexDirection: 'column',
|
|
27
|
+
gap: theme.spacing(1)
|
|
28
|
+
}
|
|
29
|
+
}));
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
|
|
3
|
+
import { closestCenter } from '@dnd-kit/core';
|
|
4
|
+
import { verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
import { InputPropsWithoutGroup } from '../models';
|
|
8
|
+
import { SortableItems, Subtitle } from '../../..';
|
|
9
|
+
|
|
10
|
+
import { useList } from './useList';
|
|
11
|
+
import { useListStyles } from './List.styles';
|
|
12
|
+
import Content, { ContentProps } from './Content';
|
|
13
|
+
|
|
14
|
+
const List = ({
|
|
15
|
+
list,
|
|
16
|
+
fieldName
|
|
17
|
+
}: InputPropsWithoutGroup): JSX.Element | null => {
|
|
18
|
+
const { t } = useTranslation();
|
|
19
|
+
const { classes } = useListStyles();
|
|
20
|
+
|
|
21
|
+
const { addItem, sortList, sortedList, deleteItem } = useList({ fieldName });
|
|
22
|
+
|
|
23
|
+
const { AddItem, addItemLabel, sortLabel, SortContent, itemProps } = list as {
|
|
24
|
+
AddItem: ComponentType<{ addItem }>;
|
|
25
|
+
SortContent: ComponentType;
|
|
26
|
+
addItemLabel?: string;
|
|
27
|
+
itemProps: Array<string>;
|
|
28
|
+
sortLabel?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className={classes.list}>
|
|
33
|
+
{addItemLabel && <Subtitle>{t(addItemLabel)}</Subtitle>}
|
|
34
|
+
<AddItem addItem={addItem} />
|
|
35
|
+
{sortLabel && <Subtitle>{t(sortLabel)}</Subtitle>}
|
|
36
|
+
<div className={classes.items}>
|
|
37
|
+
<SortableItems
|
|
38
|
+
updateSortableItemsOnItemsChange
|
|
39
|
+
// eslint-disable-next-line react/no-unstable-nested-components
|
|
40
|
+
Content={(props: Omit<ContentProps, 'children' | 'deleteItem'>) => (
|
|
41
|
+
<Content {...props} deleteItem={deleteItem}>
|
|
42
|
+
<SortContent {...props} />
|
|
43
|
+
</Content>
|
|
44
|
+
)}
|
|
45
|
+
collisionDetection={closestCenter}
|
|
46
|
+
itemProps={itemProps}
|
|
47
|
+
items={sortedList}
|
|
48
|
+
sortingStrategy={verticalListSortingStrategy}
|
|
49
|
+
onDragEnd={({ items }): void => {
|
|
50
|
+
sortList(items);
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default List;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useMemo, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { FormikValues, useFormikContext } from 'formik';
|
|
4
|
+
import {
|
|
5
|
+
append,
|
|
6
|
+
equals,
|
|
7
|
+
inc,
|
|
8
|
+
isEmpty,
|
|
9
|
+
pluck,
|
|
10
|
+
prop,
|
|
11
|
+
reject,
|
|
12
|
+
sortBy
|
|
13
|
+
} from 'ramda';
|
|
14
|
+
|
|
15
|
+
import { SelectEntry } from '../../..';
|
|
16
|
+
|
|
17
|
+
interface UseListState {
|
|
18
|
+
addItem: (newItem: SelectEntry) => void;
|
|
19
|
+
deleteItem: (id: string) => () => void;
|
|
20
|
+
sortList: (items: Array<string>) => void;
|
|
21
|
+
sortedList: Array<unknown>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const useList = ({ fieldName }): UseListState => {
|
|
25
|
+
const { values, setFieldValue } = useFormikContext<FormikValues>();
|
|
26
|
+
const maxOrder = useRef(0);
|
|
27
|
+
|
|
28
|
+
const list = values[fieldName];
|
|
29
|
+
|
|
30
|
+
const sortedList = useMemo(
|
|
31
|
+
() =>
|
|
32
|
+
sortBy(prop('order'), list).map(({ id, ...props }) => ({
|
|
33
|
+
id: `${id}`,
|
|
34
|
+
...props
|
|
35
|
+
})),
|
|
36
|
+
[list]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const addItem = (newItem: SelectEntry): void => {
|
|
40
|
+
setFieldValue(
|
|
41
|
+
fieldName,
|
|
42
|
+
append(
|
|
43
|
+
{
|
|
44
|
+
...newItem,
|
|
45
|
+
id: (newItem as SelectEntry).id as number,
|
|
46
|
+
order: inc(maxOrder.current)
|
|
47
|
+
},
|
|
48
|
+
list
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const deleteItem = (id: string) => (): void => {
|
|
54
|
+
const newItems = reject((item) => equals(Number(id), item.id))(list);
|
|
55
|
+
|
|
56
|
+
setFieldValue(fieldName, newItems);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const sortList = (items: Array<string>): void => {
|
|
60
|
+
const newOrderedList = items.map((itemId, idx) => {
|
|
61
|
+
const item = sortedList.find(({ id }) => equals(id, itemId));
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
...item,
|
|
65
|
+
id: Number(item?.id),
|
|
66
|
+
order: inc(idx)
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
setFieldValue(fieldName, newOrderedList);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
maxOrder.current = isEmpty(list) ? 0 : Math.max(...pluck('order', list));
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
addItem,
|
|
77
|
+
deleteItem,
|
|
78
|
+
sortList,
|
|
79
|
+
sortedList
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -21,6 +21,7 @@ import CheckboxGroup from './CheckboxGroup';
|
|
|
21
21
|
import Checkbox from './Checkbox';
|
|
22
22
|
import Custom from './Custom';
|
|
23
23
|
import LoadingSkeleton from './LoadingSkeleton';
|
|
24
|
+
import List from './List/List';
|
|
24
25
|
|
|
25
26
|
export const getInput = R.cond<
|
|
26
27
|
Array<InputType>,
|
|
@@ -66,6 +67,7 @@ export const getInput = R.cond<
|
|
|
66
67
|
R.equals(InputType.CheckboxGroup) as (b: InputType) => boolean,
|
|
67
68
|
R.always(CheckboxGroup)
|
|
68
69
|
],
|
|
70
|
+
[R.equals(InputType.List) as (b: InputType) => boolean, R.always(List)],
|
|
69
71
|
[R.T, R.always(TextInput)]
|
|
70
72
|
]);
|
|
71
73
|
|
|
@@ -185,7 +187,7 @@ const Inputs = ({
|
|
|
185
187
|
const hasGroupTitle = R.not(R.isNil(groupName));
|
|
186
188
|
|
|
187
189
|
const groupProps = hasGroupTitle
|
|
188
|
-
? R.find(R.propEq('name'
|
|
190
|
+
? R.find(R.propEq(groupName, 'name'), groups)
|
|
189
191
|
: ({} as Group);
|
|
190
192
|
|
|
191
193
|
const isFirstElement = areGroupsOpen || R.equals(index, 0);
|
|
@@ -18,7 +18,8 @@ export enum InputType {
|
|
|
18
18
|
Grid,
|
|
19
19
|
Custom,
|
|
20
20
|
Checkbox,
|
|
21
|
-
CheckboxGroup
|
|
21
|
+
CheckboxGroup,
|
|
22
|
+
List
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
interface FieldsTableGetRequiredProps {
|
|
@@ -76,6 +77,13 @@ export interface InputProps {
|
|
|
76
77
|
hideInput?: (values: FormikValues) => boolean;
|
|
77
78
|
inputClassName?: string;
|
|
78
79
|
label: string;
|
|
80
|
+
list?: {
|
|
81
|
+
AddItem: React.ComponentType<{ addItem }>;
|
|
82
|
+
SortContent: React.ComponentType<object>;
|
|
83
|
+
addItemLabel?: string;
|
|
84
|
+
itemProps: Array<string>;
|
|
85
|
+
sortLabel?: string;
|
|
86
|
+
};
|
|
79
87
|
radio?: {
|
|
80
88
|
options?: Array<{
|
|
81
89
|
label: string | JSX.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Shape } from '@visx/visx';
|
|
2
2
|
import { isEmpty, isNil } from 'ramda';
|
|
3
3
|
|
|
4
|
-
import { Circle } from './models';
|
|
4
|
+
import { Circle as CircleModel } from './models';
|
|
5
5
|
import useCoordinateCircle from './useCoordinateCircle';
|
|
6
6
|
|
|
7
7
|
const Circle = ({
|
|
@@ -11,7 +11,7 @@ const Circle = ({
|
|
|
11
11
|
timeSeries,
|
|
12
12
|
getX,
|
|
13
13
|
getCountDisplayedCircles
|
|
14
|
-
}:
|
|
14
|
+
}: CircleModel): JSX.Element | null => {
|
|
15
15
|
const coordinates = useCoordinateCircle({
|
|
16
16
|
getCountDisplayedCircles,
|
|
17
17
|
getX,
|
|
@@ -130,10 +130,11 @@ const WrapperThresholdLines = ({
|
|
|
130
130
|
|
|
131
131
|
return (
|
|
132
132
|
<g>
|
|
133
|
-
{filteredThresholdLines.map(
|
|
134
|
-
element
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
{filteredThresholdLines.map(
|
|
134
|
+
(element) =>
|
|
135
|
+
element?.map(({ Component, props, key }) => (
|
|
136
|
+
<Component {...props} id={key} key={key} />
|
|
137
|
+
))
|
|
137
138
|
)}
|
|
138
139
|
</g>
|
|
139
140
|
);
|
|
@@ -2,7 +2,7 @@ import { equals, isNil } from 'ramda';
|
|
|
2
2
|
|
|
3
3
|
import { getUnits, getYScale } from '../../common/timeSeries';
|
|
4
4
|
import { Line } from '../../common/timeSeries/models';
|
|
5
|
-
import { Thresholds } from '../../common/models';
|
|
5
|
+
import { Thresholds as ThresholdsModel } from '../../common/models';
|
|
6
6
|
|
|
7
7
|
import { ThresholdLine } from './ThresholdLine';
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ interface Props {
|
|
|
13
13
|
rightScale: (value: number) => number;
|
|
14
14
|
showTooltip: (props) => void;
|
|
15
15
|
thresholdUnit?: string;
|
|
16
|
-
thresholds:
|
|
16
|
+
thresholds: ThresholdsModel;
|
|
17
17
|
width: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -28,7 +28,7 @@ const useFilterLines = ({
|
|
|
28
28
|
linesGraph,
|
|
29
29
|
setLinesGraph
|
|
30
30
|
}: UseFilterLines): Result => {
|
|
31
|
-
const displayedLines = reject(propEq('display'
|
|
31
|
+
const displayedLines = reject(propEq(false, 'display'), linesGraph ?? lines);
|
|
32
32
|
const filterLines = (): Array<Line> => {
|
|
33
33
|
const lineOriginMetric = findLineOfOriginMetricThreshold(lines);
|
|
34
34
|
|
|
@@ -2,7 +2,7 @@ import { Shape } from '@visx/visx';
|
|
|
2
2
|
|
|
3
3
|
import { grey } from '@mui/material/colors';
|
|
4
4
|
|
|
5
|
-
import { GuidingLines } from './models';
|
|
5
|
+
import { GuidingLines as GuidingLinesModel } from './models';
|
|
6
6
|
import useTickGraph from './useTickGraph';
|
|
7
7
|
|
|
8
8
|
const GuidingLines = ({
|
|
@@ -10,7 +10,7 @@ const GuidingLines = ({
|
|
|
10
10
|
xScale,
|
|
11
11
|
graphHeight,
|
|
12
12
|
graphWidth
|
|
13
|
-
}:
|
|
13
|
+
}: GuidingLinesModel): JSX.Element | null => {
|
|
14
14
|
const { positionX, positionY } = useTickGraph({
|
|
15
15
|
timeSeries,
|
|
16
16
|
xScale
|
|
@@ -43,9 +43,8 @@ const Annotation = ({
|
|
|
43
43
|
|
|
44
44
|
const setAnnotationHovered = useSetAtom(annotationHoveredAtom);
|
|
45
45
|
|
|
46
|
-
const content = `${truncate(event.content)} (${t(labelBy)} ${
|
|
47
|
-
|
|
48
|
-
})`;
|
|
46
|
+
const content = `${truncate(event.content)} (${t(labelBy)} ${event.contact
|
|
47
|
+
?.name})`;
|
|
49
48
|
|
|
50
49
|
return (
|
|
51
50
|
<g>
|