@centreon/ui 24.11.2 → 24.11.4

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 (75) hide show
  1. package/package.json +2 -3
  2. package/src/Dashboard/Dashboard.styles.ts +4 -3
  3. package/src/Dashboard/DashboardLayout.stories.tsx +1 -1
  4. package/src/Dashboard/Grid.tsx +17 -11
  5. package/src/Dashboard/Layout.tsx +56 -27
  6. package/src/FileDropZone/index.tsx +21 -23
  7. package/src/Form/CollapsibleGroup.tsx +3 -2
  8. package/src/Form/Form.cypress.spec.tsx +39 -0
  9. package/src/Form/Form.tsx +1 -0
  10. package/src/Form/Inputs/Autocomplete.tsx +27 -4
  11. package/src/Form/Inputs/ConnectedAutocomplete.tsx +20 -10
  12. package/src/Form/Inputs/File.tsx +69 -0
  13. package/src/Form/Inputs/Grid.tsx +30 -2
  14. package/src/Form/Inputs/Radio.tsx +12 -4
  15. package/src/Form/Inputs/Switch.tsx +10 -2
  16. package/src/Form/Inputs/Text.tsx +13 -4
  17. package/src/Form/Inputs/index.tsx +5 -2
  18. package/src/Form/Inputs/models.ts +18 -2
  19. package/src/Form/storiesData.tsx +15 -3
  20. package/src/Form/translatedLabels.ts +1 -0
  21. package/src/Graph/BarChart/BarChart.tsx +4 -1
  22. package/src/Graph/BarChart/ResponsiveBarChart.tsx +3 -2
  23. package/src/Graph/Chart/Chart.tsx +9 -2
  24. package/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts +2 -2
  25. package/src/Graph/Chart/InteractiveComponents/index.tsx +10 -2
  26. package/src/Graph/Chart/helpers/index.ts +5 -5
  27. package/src/Graph/Chart/index.tsx +7 -0
  28. package/src/Graph/Chart/models.ts +1 -0
  29. package/src/Graph/common/timeSeries/index.ts +15 -8
  30. package/src/InputField/Text/index.tsx +1 -1
  31. package/src/Listing/index.tsx +39 -27
  32. package/src/Listing/models.ts +8 -0
  33. package/src/MultiSelectEntries/index.tsx +0 -2
  34. package/src/PopoverMenu/index.tsx +9 -2
  35. package/src/SortableItems/index.tsx +1 -0
  36. package/src/ThemeProvider/index.tsx +1 -1
  37. package/src/ThemeProvider/palettes.ts +4 -4
  38. package/src/api/customFetch.ts +4 -1
  39. package/src/components/CrudPage/Actions/Actions.styles.ts +16 -0
  40. package/src/components/CrudPage/Actions/Actions.tsx +24 -0
  41. package/src/components/CrudPage/Actions/AddButton.tsx +23 -0
  42. package/src/components/CrudPage/Actions/Filters.tsx +25 -0
  43. package/src/components/CrudPage/Actions/Search.tsx +31 -0
  44. package/src/components/CrudPage/Actions/useSearch.tsx +24 -0
  45. package/src/components/CrudPage/Columns/Actions.tsx +88 -0
  46. package/src/components/CrudPage/CrudPage.cypress.spec.tsx +559 -0
  47. package/src/components/CrudPage/CrudPage.stories.tsx +278 -0
  48. package/src/components/CrudPage/CrudPageRoot.tsx +142 -0
  49. package/src/components/CrudPage/DeleteModal.tsx +77 -0
  50. package/src/components/CrudPage/Form/AddModal.tsx +35 -0
  51. package/src/components/CrudPage/Form/Buttons.tsx +98 -0
  52. package/src/components/CrudPage/Form/UpdateModal.tsx +60 -0
  53. package/src/components/CrudPage/Listing.tsx +63 -0
  54. package/src/components/CrudPage/atoms.ts +30 -0
  55. package/src/components/CrudPage/hooks/useDeleteItem.ts +53 -0
  56. package/src/components/CrudPage/hooks/useGetItem.ts +36 -0
  57. package/src/components/CrudPage/hooks/useGetItems.ts +67 -0
  58. package/src/components/CrudPage/hooks/useListingQueryKey.ts +31 -0
  59. package/src/components/CrudPage/index.tsx +7 -0
  60. package/src/components/CrudPage/models.ts +118 -0
  61. package/src/components/CrudPage/utils.ts +4 -0
  62. package/src/components/DataTable/DataTable.cypress.spec.tsx +2 -1
  63. package/src/components/DataTable/DataTable.stories.tsx +17 -0
  64. package/src/components/DataTable/DataTable.styles.ts +1 -1
  65. package/src/components/DataTable/EmptyState/DataTableEmptyState.styles.ts +3 -1
  66. package/src/components/DataTable/EmptyState/DataTableEmptyState.tsx +6 -0
  67. package/src/components/DataTable/Item/DataTableItem.styles.ts +28 -2
  68. package/src/components/DataTable/Item/DataTableItem.tsx +19 -4
  69. package/src/components/Layout/AreaIndicator.tsx +1 -1
  70. package/src/components/Layout/PageLayout/PageLayout.styles.ts +7 -2
  71. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +1 -0
  72. package/src/components/Modal/Modal.styles.ts +1 -1
  73. package/src/components/Zoom/Zoom.tsx +2 -2
  74. package/src/components/Zoom/ZoomContent.tsx +2 -2
  75. package/src/components/index.ts +1 -0
@@ -261,7 +261,7 @@ export const getTheme = (mode: ThemeMode): ThemeOptions => ({
261
261
  {
262
262
  backgroundColor: theme.palette.background.default,
263
263
  border: 'none',
264
- borderRadius: 0,
264
+ borderRadius: `${theme.shape.borderRadius}px`,
265
265
  boxShadow: theme.shadows[3]
266
266
  }
267
267
  })
@@ -157,7 +157,7 @@ declare module '@mui/material/Badge' {
157
157
 
158
158
  export const lightPalette: PaletteOptions = {
159
159
  action: {
160
- acknowledged: '#67532C',
160
+ acknowledged: '#745F35',
161
161
  acknowledgedBackground: '#DFD2B9',
162
162
  activatedOpacity: 0.12,
163
163
  active: '#666666',
@@ -167,7 +167,7 @@ export const lightPalette: PaletteOptions = {
167
167
  focusOpacity: 0.12,
168
168
  hover: 'rgba(0, 0, 0, 0.06)',
169
169
  hoverOpacity: 0.06,
170
- inDowntime: '#4B2352',
170
+ inDowntime: '#512980',
171
171
  inDowntimeBackground: '#E5D8F3',
172
172
  selected: 'rgba(102, 102, 102, 0.3)',
173
173
  selectedOpacity: 0.3
@@ -297,7 +297,7 @@ export const lightPalette: PaletteOptions = {
297
297
 
298
298
  export const darkPalette: PaletteOptions = {
299
299
  action: {
300
- acknowledged: '#67532C',
300
+ acknowledged: '#DFD2B9',
301
301
  acknowledgedBackground: '#745F35',
302
302
  activatedOpacity: 0.3,
303
303
  active: '#B5B5B5',
@@ -307,7 +307,7 @@ export const darkPalette: PaletteOptions = {
307
307
  focusOpacity: 0.3,
308
308
  hover: 'rgba(255, 255, 255, 0.16)',
309
309
  hoverOpacity: 0.16,
310
- inDowntime: '#4B2352',
310
+ inDowntime: '#E5D8F3',
311
311
  inDowntimeBackground: '#512980',
312
312
  selected: 'rgba(255, 255, 255, 0.5)',
313
313
  selectedOpacity: 0.5
@@ -55,10 +55,13 @@ export const customFetch = <T>({
55
55
  ? `${baseEndpoint}${endpoint}`
56
56
  : endpoint;
57
57
 
58
+ const isFormData = payload instanceof FormData;
59
+
58
60
  const options = isMutation
59
61
  ? {
60
62
  ...defaultOptions,
61
- body: payload instanceof FormData ? payload : JSON.stringify(payload)
63
+ body: isFormData ? payload : JSON.stringify(payload),
64
+ headers: isFormData ? undefined : headers
62
65
  }
63
66
  : defaultOptions;
64
67
 
@@ -0,0 +1,16 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ export const useActionsStyles = makeStyles()((theme) => ({
4
+ search: {
5
+ maxWidth: theme.spacing(50)
6
+ },
7
+ clearButton: {
8
+ alignSelf: 'flex-start'
9
+ },
10
+ tooltipFilters: {
11
+ padding: theme.spacing(2, 3),
12
+ display: 'flex',
13
+ flexDirection: 'column',
14
+ gap: theme.spacing(2)
15
+ }
16
+ }));
@@ -0,0 +1,24 @@
1
+ import { Box } from '@mui/material';
2
+ import AddButton from './AddButton';
3
+ import Search from './Search';
4
+
5
+ interface Props {
6
+ labels: {
7
+ search: string;
8
+ add: string;
9
+ };
10
+ filters: JSX.Element;
11
+ }
12
+
13
+ const Actions = ({ labels, filters }: Props): JSX.Element => {
14
+ return (
15
+ <Box
16
+ sx={{ display: 'grid', gridTemplateColumns: 'min-content auto', gap: 2 }}
17
+ >
18
+ <AddButton label={labels.add} />
19
+ <Search label={labels.search} filters={filters} />
20
+ </Box>
21
+ );
22
+ };
23
+
24
+ export default Actions;
@@ -0,0 +1,23 @@
1
+ import { Add } from '@mui/icons-material';
2
+ import { useSetAtom } from 'jotai';
3
+ import { useCallback } from 'react';
4
+ import { Button } from '../../Button';
5
+ import { openFormModalAtom } from '../atoms';
6
+
7
+ interface Props {
8
+ label: string;
9
+ }
10
+
11
+ const AddButton = ({ label }: Props): JSX.Element => {
12
+ const setOpenFormModal = useSetAtom(openFormModalAtom);
13
+
14
+ const add = useCallback(() => setOpenFormModal('add'), []);
15
+
16
+ return (
17
+ <Button size="small" icon={<Add />} iconVariant="start" onClick={add}>
18
+ {label}
19
+ </Button>
20
+ );
21
+ };
22
+
23
+ export default AddButton;
@@ -0,0 +1,25 @@
1
+ import { Tune } from '@mui/icons-material';
2
+ import { isValidElement } from 'react';
3
+ import PopoverMenu from '../../../PopoverMenu';
4
+ import { useActionsStyles } from './Actions.styles';
5
+
6
+ interface Props {
7
+ label: string;
8
+ filters: JSX.Element;
9
+ }
10
+
11
+ const Filters: React.FC<Props> = ({ label, filters }: Props): JSX.Element => {
12
+ const { classes } = useActionsStyles();
13
+
14
+ return (
15
+ <PopoverMenu
16
+ title={label}
17
+ icon={<Tune />}
18
+ tooltipClassName={classes.tooltipFilters}
19
+ >
20
+ {isValidElement(filters) ? filters : <div />}
21
+ </PopoverMenu>
22
+ );
23
+ };
24
+
25
+ export default Filters;
@@ -0,0 +1,31 @@
1
+ import { SearchField } from '@centreon/ui';
2
+ import { useActionsStyles } from './Actions.styles';
3
+ import Filters from './Filters';
4
+ import { useSearch } from './useSearch';
5
+
6
+ interface Props {
7
+ label: string;
8
+ filters: JSX.Element;
9
+ }
10
+
11
+ const Search = ({ label, filters }: Props): JSX.Element => {
12
+ const { classes } = useActionsStyles();
13
+
14
+ const { change } = useSearch();
15
+
16
+ return (
17
+ <SearchField
18
+ className={classes.search}
19
+ debounced
20
+ fullWidth
21
+ dataTestId={label}
22
+ placeholder={label}
23
+ onChange={change}
24
+ InputProps={{
25
+ endAdornment: <Filters label="filters" filters={filters} />
26
+ }}
27
+ />
28
+ );
29
+ };
30
+
31
+ export default Search;
@@ -0,0 +1,24 @@
1
+ import { useAtom } from 'jotai';
2
+ import { ChangeEvent, useCallback, useRef } from 'react';
3
+ import { searchAtom } from '../atoms';
4
+
5
+ interface UseSearchState {
6
+ search: string;
7
+ change: (event: ChangeEvent<HTMLInputElement>) => void;
8
+ }
9
+
10
+ export const useSearch = (): UseSearchState => {
11
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null);
12
+
13
+ const [search, setSearch] = useAtom(searchAtom);
14
+
15
+ const change = useCallback((event: ChangeEvent<HTMLInputElement>): void => {
16
+ if (timeoutRef.current) {
17
+ clearTimeout(timeoutRef.current);
18
+ }
19
+
20
+ timeoutRef.current = setTimeout(() => setSearch(event.target.value), 500);
21
+ }, []);
22
+
23
+ return { search, change };
24
+ };
@@ -0,0 +1,88 @@
1
+ import { EditOutlined } from '@mui/icons-material';
2
+ import DeleteOutline from '@mui/icons-material/DeleteOutline';
3
+ import { Box } from '@mui/material';
4
+ import { useAtomValue, useSetAtom } from 'jotai';
5
+ import { isNil } from 'ramda';
6
+ import { useCallback } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { IconButton } from '../../Button';
9
+ import {
10
+ canDeleteSubItemsAtom,
11
+ itemToDeleteAtom,
12
+ openFormModalAtom
13
+ } from '../atoms';
14
+
15
+ interface Props<TData> {
16
+ row: TData & {
17
+ internalListingParentId?: number;
18
+ internalListingParentRow: TData;
19
+ };
20
+ }
21
+
22
+ const labelDelete = 'Delete';
23
+ const labelUpdate = 'Update';
24
+
25
+ const Actions = <TData extends { id: number; name: string }>({
26
+ row
27
+ }: Props<TData>): JSX.Element => {
28
+ const { t } = useTranslation();
29
+ const canDeleteSubItems = useAtomValue(canDeleteSubItemsAtom);
30
+ const setItemToDelete = useSetAtom(itemToDeleteAtom);
31
+ const setOpenFormModal = useSetAtom(openFormModalAtom);
32
+
33
+ const askBeforeDelete = (): void => {
34
+ setItemToDelete({
35
+ id: row.id,
36
+ name: row.name,
37
+ parent: isNil(row.internalListingParentRow)
38
+ ? undefined
39
+ : {
40
+ id: row.internalListingParentRow.id,
41
+ name: row.internalListingParentRow.name
42
+ }
43
+ });
44
+ };
45
+
46
+ const updateRow = useCallback(() => setOpenFormModal(row.id), [row.id]);
47
+
48
+ return (
49
+ <Box
50
+ sx={{
51
+ display: 'flex',
52
+ flexDirection: 'row',
53
+ gap: 1,
54
+ width: '100%',
55
+ justifyContent: 'flex-end'
56
+ }}
57
+ >
58
+ {isNil(row.internalListingParentRow) && (
59
+ <IconButton
60
+ size="small"
61
+ icon={<EditOutlined fontSize="small" color="primary" />}
62
+ onClick={updateRow}
63
+ title={t(labelUpdate)}
64
+ data-testid={
65
+ row.internalListingParentRow
66
+ ? `edit-${row.internalListingParentRow.id}-${row.id}`
67
+ : `edit-${row.id}`
68
+ }
69
+ />
70
+ )}
71
+ {(canDeleteSubItems || isNil(row.internalListingParentRow)) && (
72
+ <IconButton
73
+ size="small"
74
+ icon={<DeleteOutline fontSize="small" color="error" />}
75
+ onClick={askBeforeDelete}
76
+ title={t(labelDelete)}
77
+ data-testid={
78
+ row.internalListingParentRow
79
+ ? `delete-${row.internalListingParentRow.id}-${row.id}`
80
+ : `delete-${row.id}`
81
+ }
82
+ />
83
+ )}
84
+ </Box>
85
+ );
86
+ };
87
+
88
+ export default Actions;