@centreon/ui 23.10.1-sync-dev-23-10-x-develop-oss.0 → 23.10.1-sync-release-34346.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.
Files changed (94) hide show
  1. package/package.json +6 -1
  2. package/public/mockServiceWorker.js +2 -2
  3. package/src/Form/Inputs/ConnectedAutocomplete.tsx +3 -1
  4. package/src/Form/Inputs/models.ts +1 -0
  5. package/src/Graph/Gauge/Gauge.stories.tsx +15 -2
  6. package/src/Graph/HeatMap/HeatMap.stories.tsx +105 -0
  7. package/src/Graph/HeatMap/HeatMap.styles.tsx +29 -0
  8. package/src/Graph/HeatMap/HeatMap.tsx +12 -0
  9. package/src/Graph/HeatMap/HeatMapData.json +137 -0
  10. package/src/Graph/HeatMap/ResponsiveHeatMap.tsx +98 -0
  11. package/src/Graph/HeatMap/index.ts +1 -0
  12. package/src/Graph/HeatMap/model.ts +33 -0
  13. package/src/Graph/LineChart/BasicComponents/Lines/RegularLines/index.tsx +1 -1
  14. package/src/Graph/LineChart/BasicComponents/useFilterLines.ts +2 -4
  15. package/src/Graph/LineChart/Legend/InteractiveValue.tsx +3 -3
  16. package/src/Graph/LineChart/Legend/Legend.styles.ts +78 -32
  17. package/src/Graph/LineChart/Legend/LegendContent.tsx +12 -6
  18. package/src/Graph/LineChart/Legend/LegendHeader.tsx +69 -21
  19. package/src/Graph/LineChart/Legend/index.tsx +51 -23
  20. package/src/Graph/LineChart/Legend/models.ts +5 -0
  21. package/src/Graph/LineChart/Legend/useLegend.ts +9 -10
  22. package/src/Graph/LineChart/LineChart.tsx +17 -3
  23. package/src/Graph/index.ts +1 -0
  24. package/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx +1 -0
  25. package/src/InputField/Select/Autocomplete/Connected/index.test.tsx +1 -0
  26. package/src/InputField/Select/Autocomplete/Connected/index.tsx +15 -3
  27. package/src/InputField/Text/index.tsx +6 -1
  28. package/src/Module/LicensedModule/LicenseCheck/index.tsx +24 -9
  29. package/src/Module/LicensedModule/index.tsx +7 -1
  30. package/src/RichTextEditor/RichTextEditor.cypress.spec.tsx +100 -52
  31. package/src/RichTextEditor/RichTextEditor.tsx +9 -3
  32. package/src/RichTextEditor/plugins/ToolbarPlugin/AlignPicker.tsx +21 -20
  33. package/src/RichTextEditor/plugins/ToolbarPlugin/BlockButtons.tsx +35 -77
  34. package/src/RichTextEditor/plugins/ToolbarPlugin/FormatButtons.tsx +29 -83
  35. package/src/RichTextEditor/plugins/ToolbarPlugin/LinkButton.tsx +106 -0
  36. package/src/RichTextEditor/plugins/ToolbarPlugin/ListButton.tsx +155 -0
  37. package/src/RichTextEditor/plugins/ToolbarPlugin/MacrosButton.tsx +23 -39
  38. package/src/RichTextEditor/plugins/ToolbarPlugin/ToolbarPlugin.styles.ts +24 -14
  39. package/src/RichTextEditor/plugins/ToolbarPlugin/UndoRedoButtons.tsx +6 -0
  40. package/src/RichTextEditor/plugins/ToolbarPlugin/index.tsx +5 -10
  41. package/src/RichTextEditor/translatedLabels.ts +3 -0
  42. package/src/ThemeProvider/palettes.ts +4 -4
  43. package/src/Typography/EllipsisTypography.tsx +18 -0
  44. package/src/Typography/Subtitle.tsx +55 -0
  45. package/src/api/buildListingEndpoint/models.ts +2 -1
  46. package/src/api/customFetch.ts +12 -3
  47. package/src/api/useFetchQuery/index.ts +22 -5
  48. package/src/api/useGraphQuery/index.ts +4 -1
  49. package/src/api/useMutationQuery/index.ts +12 -2
  50. package/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx +350 -0
  51. package/src/components/Form/AccessRightsV2/AccessRights.stories.tsx +119 -0
  52. package/src/components/Form/AccessRightsV2/AccessRights.styles.ts +10 -0
  53. package/src/components/Form/AccessRightsV2/AccessRights.tsx +60 -0
  54. package/src/components/Form/AccessRightsV2/Actions/Actions.styles.ts +14 -0
  55. package/src/components/Form/AccessRightsV2/Actions/Actions.tsx +81 -0
  56. package/src/components/Form/AccessRightsV2/Actions/useActions.ts +79 -0
  57. package/src/components/Form/AccessRightsV2/List/Item.tsx +90 -0
  58. package/src/components/Form/AccessRightsV2/List/List.styles.tsx +45 -0
  59. package/src/components/Form/AccessRightsV2/List/List.tsx +52 -0
  60. package/src/components/Form/AccessRightsV2/List/ListItemSkeleton.tsx +18 -0
  61. package/src/components/Form/AccessRightsV2/List/ListSkeleton.tsx +22 -0
  62. package/src/components/Form/AccessRightsV2/List/RemoveAccessRight.tsx +38 -0
  63. package/src/components/Form/AccessRightsV2/List/StateChip.tsx +28 -0
  64. package/src/components/Form/AccessRightsV2/List/useItem.ts +64 -0
  65. package/src/components/Form/AccessRightsV2/Provider.tsx +15 -0
  66. package/src/components/Form/AccessRightsV2/ShareInput/ContactSwitch.tsx +42 -0
  67. package/src/components/Form/AccessRightsV2/ShareInput/ShareInput.styles.ts +9 -0
  68. package/src/components/Form/AccessRightsV2/ShareInput/ShareInput.tsx +77 -0
  69. package/src/components/Form/AccessRightsV2/ShareInput/useShareInput.tsx +109 -0
  70. package/src/components/Form/AccessRightsV2/Stats/Stats.tsx +36 -0
  71. package/src/components/Form/AccessRightsV2/atoms.ts +97 -0
  72. package/src/components/Form/AccessRightsV2/common/RoleSelectField.styles.tsx +7 -0
  73. package/src/components/Form/AccessRightsV2/common/RoleSelectField.tsx +45 -0
  74. package/src/components/Form/AccessRightsV2/models.ts +54 -0
  75. package/src/components/Form/AccessRightsV2/storiesData.ts +221 -0
  76. package/src/components/Form/AccessRightsV2/useAccessRightsInitValues.ts +51 -0
  77. package/src/components/Form/index.ts +1 -0
  78. package/src/components/Header/PageHeader/PageHeader.styles.ts +28 -1
  79. package/src/components/Header/PageHeader/PageHeaderMessage.tsx +32 -0
  80. package/src/components/Header/PageHeader/index.ts +2 -0
  81. package/src/components/ItemComposition/Item.tsx +2 -2
  82. package/src/components/ItemComposition/ItemComposition.styles.ts +3 -0
  83. package/src/components/ItemComposition/ItemComposition.tsx +4 -2
  84. package/src/components/List/Item/ListItem.styles.ts +6 -0
  85. package/src/components/List/Item/ListItem.tsx +3 -1
  86. package/src/components/List/Item/Text.tsx +5 -3
  87. package/src/components/Menu/Button/MenuButton.tsx +4 -2
  88. package/src/components/Menu/MenuItem.tsx +5 -3
  89. package/src/components/Menu/MenuItems.tsx +4 -3
  90. package/src/components/Modal/Modal.styles.ts +4 -2
  91. package/src/index.ts +5 -0
  92. package/src/utils/useInfiniteScrollListing.ts +22 -7
  93. package/src/utils/useLocaleDateTimeFormat/index.ts +3 -0
  94. package/src/Graph/LineChart/Legend/Marker.tsx +0 -43
@@ -0,0 +1,221 @@
1
+ import { faker } from '@faker-js/faker';
2
+
3
+ import { Listing } from '../../../api/models';
4
+ import { SelectEntry } from '../../..';
5
+
6
+ import { AccessRightInitialValues, Labels } from './models';
7
+
8
+ faker.seed(42);
9
+
10
+ export const defaultAccessRights: Array<AccessRightInitialValues> = Array(10)
11
+ .fill(0)
12
+ .map((_, idx) => ({
13
+ email: faker.internet.email(),
14
+ id: idx,
15
+ isContactGroup: idx % 5 === 0,
16
+ name: faker.person.fullName(),
17
+ role: idx % 2 === 0 ? 'viewer' : 'editor'
18
+ }));
19
+
20
+ export const simpleAccessRights: Array<AccessRightInitialValues> = Array(6)
21
+ .fill(0)
22
+ .map((_, idx) => ({
23
+ email: faker.internet.email(),
24
+ id: idx,
25
+ isContactGroup: idx % 5 === 0,
26
+ name: faker.person.fullName(),
27
+ role: idx % 2 === 0 ? 'viewer' : 'editor'
28
+ }));
29
+
30
+ export const accessRightsWithStates = [
31
+ {
32
+ email: faker.internet.email(),
33
+ id: 1,
34
+ isAdded: false,
35
+ isContactGroup: true,
36
+ isRemoved: false,
37
+ isUpdated: false,
38
+ name: faker.person.fullName(),
39
+ role: 'viewer'
40
+ },
41
+ {
42
+ email: faker.internet.email(),
43
+ id: 2,
44
+ isAdded: true,
45
+ isContactGroup: true,
46
+ isRemoved: false,
47
+ isUpdated: false,
48
+ name: faker.person.fullName(),
49
+ role: 'editor'
50
+ },
51
+ {
52
+ email: faker.internet.email(),
53
+ id: 3,
54
+ isAdded: false,
55
+ isContactGroup: false,
56
+ isRemoved: false,
57
+ isUpdated: true,
58
+ name: faker.person.fullName(),
59
+ role: 'viewer'
60
+ },
61
+ {
62
+ email: faker.internet.email(),
63
+ id: 4,
64
+ isAdded: false,
65
+ isContactGroup: false,
66
+ isRemoved: true,
67
+ isUpdated: false,
68
+ name: faker.person.fullName(),
69
+ role: 'editor'
70
+ },
71
+ {
72
+ email: faker.internet.email(),
73
+ id: 5,
74
+ isAdded: false,
75
+ isContactGroup: true,
76
+ isRemoved: true,
77
+ isUpdated: true,
78
+ name: faker.person.fullName(),
79
+ role: 'viewer'
80
+ }
81
+ ];
82
+
83
+ export const emptyAccessRights = [];
84
+
85
+ const buildEntities = (from, isGroup): Array<SelectEntry> => {
86
+ return Array(10)
87
+ .fill(0)
88
+ .map((_, index) => ({
89
+ email: isGroup ? undefined : faker.internet.email(),
90
+ id: 1000 + index,
91
+ name: `Entity ${isGroup ? 'Group' : ''} ${from + index}`
92
+ }));
93
+ };
94
+
95
+ export const buildResult = (isGroup): Listing<SelectEntry> => ({
96
+ meta: {
97
+ limit: 10,
98
+ page: 1,
99
+ total: 10
100
+ },
101
+ result: buildEntities(10, isGroup)
102
+ });
103
+
104
+ export const labels: Labels = {
105
+ actions: {
106
+ cancel: 'Cancel',
107
+ copyError: 'Failed to copy',
108
+ copyLink: 'Copy link',
109
+ copySuccess: 'Copied',
110
+ save: 'Save'
111
+ },
112
+ add: {
113
+ autocompleteContact: 'Add a contact',
114
+ autocompleteContactGroup: 'Add a contact group',
115
+ contact: 'Contact',
116
+ contactGroup: 'Contact group',
117
+ title: 'Share dashboard with'
118
+ },
119
+ list: {
120
+ added: 'Added',
121
+ empty: 'The contact list is empty',
122
+ group: 'Group',
123
+ removed: 'Removed',
124
+ title: 'User rights',
125
+ updated: 'Updated'
126
+ }
127
+ };
128
+
129
+ export const roles = [
130
+ {
131
+ id: 'viewer',
132
+ name: 'Viewer'
133
+ },
134
+ {
135
+ id: 'editor',
136
+ name: 'Editor'
137
+ }
138
+ ];
139
+
140
+ export const removedAccessRights = [
141
+ {
142
+ email: 'Virgie14@yahoo.com',
143
+ id: 1,
144
+ isContactGroup: false,
145
+ name: 'Jody Blanda',
146
+ role: 'editor'
147
+ },
148
+ {
149
+ email: 'Wyman29@yahoo.com',
150
+ id: 2,
151
+ isContactGroup: false,
152
+ name: 'Susan Dooley',
153
+ role: 'viewer'
154
+ },
155
+ {
156
+ email: 'Merle.Schamberger@hotmail.com',
157
+ id: 3,
158
+ isContactGroup: false,
159
+ name: 'Lewis Buckridge PhD',
160
+ role: 'editor'
161
+ },
162
+ {
163
+ email: 'Rossie6@gmail.com',
164
+ id: 4,
165
+ isContactGroup: false,
166
+ name: 'Bertha Hane',
167
+ role: 'viewer'
168
+ },
169
+ {
170
+ email: 'Monty_Nienow47@gmail.com',
171
+ id: 5,
172
+ isContactGroup: true,
173
+ name: 'Mildred Ratke-Stanton',
174
+ role: 'editor'
175
+ }
176
+ ];
177
+
178
+ export const updatedAccessRights = [
179
+ {
180
+ email: 'Jovani.Willms74@gmail.com',
181
+ id: 0,
182
+ isContactGroup: true,
183
+ name: 'Leah McGlynn',
184
+ role: 'editor'
185
+ },
186
+ {
187
+ email: 'Virgie14@yahoo.com',
188
+ id: 1,
189
+ isContactGroup: false,
190
+ name: 'Jody Blanda',
191
+ role: 'editor'
192
+ },
193
+ {
194
+ email: 'Wyman29@yahoo.com',
195
+ id: 2,
196
+ isContactGroup: false,
197
+ name: 'Susan Dooley',
198
+ role: 'viewer'
199
+ },
200
+ {
201
+ email: 'Merle.Schamberger@hotmail.com',
202
+ id: 3,
203
+ isContactGroup: false,
204
+ name: 'Lewis Buckridge PhD',
205
+ role: 'editor'
206
+ },
207
+ {
208
+ email: 'Rossie6@gmail.com',
209
+ id: 4,
210
+ isContactGroup: false,
211
+ name: 'Bertha Hane',
212
+ role: 'viewer'
213
+ },
214
+ {
215
+ email: 'Monty_Nienow47@gmail.com',
216
+ id: 5,
217
+ isContactGroup: true,
218
+ name: 'Mildred Ratke-Stanton',
219
+ role: 'editor'
220
+ }
221
+ ];
@@ -0,0 +1,51 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { useAtom, useSetAtom } from 'jotai';
4
+ import { equals } from 'ramda';
5
+
6
+ import { initialValuesAtom, valuesAtom } from './atoms';
7
+ import { AccessRightInitialValues, ContactType } from './models';
8
+
9
+ interface Props {
10
+ initialValues: Array<AccessRightInitialValues>;
11
+ }
12
+
13
+ export const useAccessRightsInitValues = ({
14
+ initialValues
15
+ }: Props): (() => void) => {
16
+ const [currentInitialValues, setInitialValues] = useAtom(initialValuesAtom);
17
+ const setValues = useSetAtom(valuesAtom);
18
+
19
+ const formattedInitialValues = useMemo(
20
+ () =>
21
+ initialValues.map((value) => ({
22
+ ...value,
23
+ id: `${
24
+ value.isContactGroup ? ContactType.ContactGroup : ContactType.Contact
25
+ }_${value.id}`
26
+ })),
27
+ [initialValues]
28
+ );
29
+
30
+ if (!equals(formattedInitialValues, currentInitialValues)) {
31
+ setInitialValues(formattedInitialValues);
32
+ setValues(
33
+ initialValues.map((value) => ({
34
+ isAdded: false,
35
+ isRemoved: false,
36
+ isUpdated: false,
37
+ ...value,
38
+ id: `${
39
+ value.isContactGroup ? ContactType.ContactGroup : ContactType.Contact
40
+ }_${value.id}`
41
+ }))
42
+ );
43
+ }
44
+
45
+ const clearValues = (): void => {
46
+ setInitialValues([]);
47
+ setValues([]);
48
+ };
49
+
50
+ return clearValues;
51
+ };
@@ -1,3 +1,4 @@
1
1
  export * from './Form.models';
2
2
  export * from './Dashboard';
3
3
  export * from './AccessRights';
4
+ export { default as AccessRightsV2 } from './AccessRightsV2/AccessRights';
@@ -1,5 +1,7 @@
1
1
  import { makeStyles } from 'tss-react/mui';
2
2
 
3
+ import { alpha } from '@mui/system';
4
+
3
5
  const useStyles = makeStyles()((theme) => ({
4
6
  header: {
5
7
  alignItems: 'flex-start',
@@ -22,7 +24,7 @@ const useStyles = makeStyles()((theme) => ({
22
24
  padding: theme.spacing(0, 0, 1.5, 0)
23
25
  },
24
26
  pageHeader: {
25
- alignItems: 'flex-start',
27
+ alignItems: 'center',
26
28
  borderBottom: `1px solid ${theme.palette.header.page.border}`,
27
29
  display: 'flex',
28
30
  gap: theme.spacing(4),
@@ -53,6 +55,31 @@ const useStyles = makeStyles()((theme) => ({
53
55
  position: 'relative',
54
56
  transform: `translateY(-${theme.spacing(0.25)})`
55
57
  },
58
+ pageHeaderMessage: {
59
+ alignItems: 'center',
60
+ color: theme.palette.warning.main,
61
+ display: 'flex',
62
+ gap: theme.spacing(1)
63
+ },
64
+ pageHeaderMessageIcon: {
65
+ alignItems: 'center',
66
+ background: theme.palette.warning.main,
67
+ borderRadius: '50%',
68
+ color: theme.palette.common.white,
69
+ display: 'flex',
70
+ height: theme.spacing(2.5),
71
+ justifyContent: 'center',
72
+ width: theme.spacing(2.5)
73
+ },
74
+ pageHeaderMessageIconWrapper: {
75
+ alignItems: 'center',
76
+ backgroundColor: alpha(theme.palette.warning.main, 0.7),
77
+ borderRadius: '50%',
78
+ display: 'flex',
79
+ height: theme.spacing(3.5),
80
+ justifyContent: 'center',
81
+ width: theme.spacing(3.5)
82
+ },
56
83
  pageHeaderTitle: {
57
84
  '& > *': {
58
85
  display: 'grid'
@@ -0,0 +1,32 @@
1
+ import { ReactElement } from 'react';
2
+
3
+ import { Box, Typography } from '@mui/material';
4
+
5
+ import { useStyles } from './PageHeader.styles';
6
+
7
+ type PageHeaderMessageProps = {
8
+ message: string;
9
+ };
10
+
11
+ const PageHeaderMessage = ({
12
+ message
13
+ }: PageHeaderMessageProps): ReactElement => {
14
+ const { classes } = useStyles();
15
+
16
+ return (
17
+ <Box className={classes.pageHeaderMessage}>
18
+ {message && (
19
+ <>
20
+ <Box className={classes.pageHeaderMessageIconWrapper}>
21
+ <Box className={classes.pageHeaderMessageIcon}>!</Box>
22
+ </Box>
23
+ <Typography aria-label="page header message" variant="h6">
24
+ {message}
25
+ </Typography>
26
+ </>
27
+ )}
28
+ </Box>
29
+ );
30
+ };
31
+
32
+ export { PageHeaderMessage };
@@ -3,10 +3,12 @@ import { PageHeaderMain } from './PageHeaderMain';
3
3
  import { PageHeaderMenu } from './PageHeaderMenu';
4
4
  import { PageHeaderTitle } from './PageHeaderTitle';
5
5
  import { PageHeaderActions } from './PageHeaderActions';
6
+ import { PageHeaderMessage } from './PageHeaderMessage';
6
7
 
7
8
  export const PageHeader = Object.assign(PageHeaderRoot, {
8
9
  Actions: PageHeaderActions,
9
10
  Main: PageHeaderMain,
10
11
  Menu: PageHeaderMenu,
12
+ Message: PageHeaderMessage,
11
13
  Title: PageHeaderTitle
12
14
  });
@@ -26,7 +26,7 @@ export const Item = ({
26
26
  return (
27
27
  <div className={classes.itemContainer}>
28
28
  <div className={cx(classes.itemContent, className)}>{children}</div>
29
- {!deleteButtonHidden && (
29
+ <div className={cx({ [classes.visibilityHiden]: deleteButtonHidden })}>
30
30
  <IconButton
31
31
  aria-label={labelDelete}
32
32
  data-testid={labelDelete}
@@ -35,7 +35,7 @@ export const Item = ({
35
35
  variant="ghost"
36
36
  onClick={onDeleteItem}
37
37
  />
38
- )}
38
+ </div>
39
39
  </div>
40
40
  );
41
41
  };
@@ -22,5 +22,8 @@ export const useItemStyles = makeStyles()((theme) => ({
22
22
  display: 'flex',
23
23
  flexDirection: 'row',
24
24
  width: '100%'
25
+ },
26
+ visibilityHiden: {
27
+ visibility: 'hidden'
25
28
  }
26
29
  }));
@@ -7,6 +7,7 @@ import { Button } from '..';
7
7
  import { useItemCompositionStyles } from './ItemComposition.styles';
8
8
 
9
9
  type Props = {
10
+ IconAdd?;
10
11
  addButtonHidden?: boolean;
11
12
  addbuttonDisabled?: boolean;
12
13
  children: Array<ReactElement>;
@@ -19,7 +20,8 @@ export const ItemComposition = ({
19
20
  children,
20
21
  labelAdd,
21
22
  addbuttonDisabled,
22
- addButtonHidden
23
+ addButtonHidden,
24
+ IconAdd
23
25
  }: Props): JSX.Element => {
24
26
  const { classes } = useItemCompositionStyles();
25
27
 
@@ -31,7 +33,7 @@ export const ItemComposition = ({
31
33
  aria-label={labelAdd}
32
34
  data-testid={labelAdd}
33
35
  disabled={addbuttonDisabled}
34
- icon={<AddIcon />}
36
+ icon={IconAdd || <AddIcon />}
35
37
  iconVariant="start"
36
38
  size="small"
37
39
  variant="ghost"
@@ -23,6 +23,12 @@ export const useStyles = makeStyles()((theme) => ({
23
23
  paddingBottom: theme.spacing(1),
24
24
  paddingTop: theme.spacing(1)
25
25
  },
26
+ secondary: {
27
+ alignItems: 'center',
28
+ display: 'flex',
29
+ flexDirection: 'row',
30
+ gap: theme.spacing(1)
31
+ },
26
32
  text: {
27
33
  '&, &.MuiListItemText-root': {
28
34
  '& .MuiListItemText-primary': {
@@ -22,7 +22,9 @@ export const ListItem = forwardRef(
22
22
  disableGutters
23
23
  className={cx(classes.listItem, className)}
24
24
  ref={ref}
25
- secondaryAction={action}
25
+ secondaryAction={
26
+ action && <div className={classes.secondary}>{action}</div>
27
+ }
26
28
  {...attr}
27
29
  >
28
30
  {children}
@@ -5,19 +5,21 @@ import { ListItemText as MuiListItemText } from '@mui/material';
5
5
  import { useStyles } from './ListItem.styles';
6
6
 
7
7
  type TextProps = {
8
+ className?: string;
8
9
  primaryText: ReactNode;
9
10
  secondaryText?: ReactNode;
10
11
  };
11
12
 
12
13
  export const Text = ({
13
14
  primaryText,
14
- secondaryText
15
+ secondaryText,
16
+ className
15
17
  }: TextProps): ReactElement => {
16
- const { classes } = useStyles();
18
+ const { classes, cx } = useStyles();
17
19
 
18
20
  return (
19
21
  <MuiListItemText
20
- className={classes.text}
22
+ className={cx(classes.text, className)}
21
23
  primary={primaryText}
22
24
  secondary={secondaryText}
23
25
  />
@@ -15,6 +15,7 @@ import { useStyles } from './MenuButton.styles';
15
15
  type MenuButtonProps = {
16
16
  ariaLabel?: string;
17
17
  children?: ReactNode;
18
+ className?: string;
18
19
  hasArrow?: boolean;
19
20
  isOpen?: boolean;
20
21
  onClick?: (args: { isOpen: boolean }) => void;
@@ -29,9 +30,10 @@ const MenuButton = ({
29
30
  size = 'small',
30
31
  variant = 'ghost',
31
32
  ariaLabel,
33
+ className,
32
34
  ...attr
33
35
  }: MenuButtonProps): ReactElement => {
34
- const { classes } = useStyles();
36
+ const { cx, classes } = useStyles();
35
37
 
36
38
  const { isMenuOpen, setIsMenuOpen, setAnchorEl, onOpen } = useMenu();
37
39
 
@@ -50,7 +52,7 @@ const MenuButton = ({
50
52
  <Button
51
53
  {...attr}
52
54
  aria-label={ariaLabel}
53
- className={classes.menuButton}
55
+ className={cx(classes.menuButton, className)}
54
56
  data-is-active={isMenuOpen}
55
57
  size={size}
56
58
  variant={variant}
@@ -6,6 +6,7 @@ import { useStyles } from './Menu.styles';
6
6
 
7
7
  type MenuItemProps = {
8
8
  children?: ReactNode;
9
+ className?: string;
9
10
  isActive?: boolean;
10
11
  isDisabled?: boolean;
11
12
  onClick?: () => void;
@@ -15,13 +16,14 @@ const MenuItem = ({
15
16
  children,
16
17
  onClick,
17
18
  isActive = false,
18
- isDisabled = false
19
+ isDisabled = false,
20
+ className
19
21
  }: MenuItemProps): ReactElement => {
20
- const { classes } = useStyles();
22
+ const { cx, classes } = useStyles();
21
23
 
22
24
  return (
23
25
  <MuiMenuItem
24
- className={classes.menuItem}
26
+ className={cx(classes.menuItem, className)}
25
27
  data-is-active={isActive}
26
28
  data-is-disabled={isDisabled}
27
29
  disabled={isDisabled}
@@ -7,9 +7,10 @@ import { useMenu } from './useMenu';
7
7
 
8
8
  type MenuItemsProps = {
9
9
  children?: ReactNode | Array<ReactNode>;
10
+ className?: string;
10
11
  };
11
- const MenuItems = ({ children }: MenuItemsProps): ReactElement => {
12
- const { classes } = useStyles();
12
+ const MenuItems = ({ children, className }: MenuItemsProps): ReactElement => {
13
+ const { cx, classes } = useStyles();
13
14
 
14
15
  const { isMenuOpen, setIsMenuOpen, anchorEl, onClose } = useMenu();
15
16
 
@@ -21,7 +22,7 @@ const MenuItems = ({ children }: MenuItemsProps): ReactElement => {
21
22
  return (
22
23
  <MuiMenu
23
24
  anchorEl={anchorEl}
24
- className={classes.menuItems}
25
+ className={cx(classes.menuItems, className)}
25
26
  open={isMenuOpen}
26
27
  variant="menu"
27
28
  onClick={onCloseMenu}
@@ -24,9 +24,9 @@ const useStyles = makeStyles<{
24
24
  },
25
25
  '&[data-size="fullscreen"] .MuiDialog-paper': {
26
26
  bottom: props?.bottom ?? 0,
27
+ height: 'calc(100vh - 90px)',
27
28
  left: props?.left ?? 0,
28
29
  margin: 0,
29
- maxHeight: 'unset',
30
30
  maxWidth: 'unset',
31
31
  position: 'absolute',
32
32
  right: props?.right ?? 0,
@@ -50,11 +50,13 @@ const useStyles = makeStyles<{
50
50
  },
51
51
  modalActions: {
52
52
  bottom: 0,
53
+ bottom: theme.spacing(2),
53
54
  display: 'flex',
54
55
  flexDirection: 'row',
55
56
  gap: theme.spacing(2),
56
57
  justifyContent: 'flex-end',
57
- position: 'sticky'
58
+ position: 'fixed',
59
+ right: theme.spacing(2)
58
60
  },
59
61
  modalBody: {
60
62
  '& > p': {
package/src/index.ts CHANGED
@@ -154,6 +154,7 @@ export type { ResponseError, CatchErrorProps } from './api/customFetch';
154
154
 
155
155
  export * from './utils';
156
156
  export { default as FluidTypography } from './Typography/FluidTypography';
157
+ export { default as EllipsisTypography } from './Typography/EllipsisTypography';
157
158
  export * from './Dashboard';
158
159
  export * from './Graph';
159
160
  export type { LineChartData } from './Graph/common/models';
@@ -162,3 +163,7 @@ export * from './Graph/common/timeSeries';
162
163
  export { default as TimePeriods } from './TimePeriods';
163
164
  export { default as SimpleCustomTimePeriod } from './TimePeriods/CustomTimePeriod/SimpleCustomTimePeriod';
164
165
  export * from './ParentSize';
166
+
167
+ export { default as TablePagination } from './Listing/ActionBar/Pagination';
168
+ export { default as PaginationActions } from './Listing/ActionBar/PaginationActions';
169
+ export { default as Subtitle } from './Typography/Subtitle';
@@ -5,33 +5,42 @@ import { PrimitiveAtom, useAtom } from 'jotai';
5
5
  import { JsonDecoder } from 'ts.data.json';
6
6
 
7
7
  import {
8
+ QueryParameter,
8
9
  buildListingEndpoint,
9
10
  useFetchQuery,
10
11
  useIntersectionObserver
11
12
  } from '@centreon/ui';
12
13
 
13
14
  import type { Listing } from '../api/models';
14
-
15
- const limit = 100;
15
+ import { Parameters } from '../api/buildListingEndpoint/models';
16
16
 
17
17
  interface UseInfiniteScrollListing<T> {
18
18
  elementRef: (node) => void;
19
19
  elements: Array<T>;
20
20
  isLoading: boolean;
21
+ total?: number;
21
22
  }
22
23
 
23
24
  interface UseInfiniteScrollListingProps<T> {
24
- decoder: JsonDecoder.Decoder<Listing<T>>;
25
+ customQueryParameters?: Array<QueryParameter>;
26
+ decoder?: JsonDecoder.Decoder<Listing<T>>;
25
27
  endpoint: string;
28
+ limit?: number;
26
29
  pageAtom: PrimitiveAtom<number>;
30
+ parameters?: Parameters;
27
31
  queryKeyName: string;
32
+ suspense?: boolean;
28
33
  }
29
34
 
30
35
  export const useInfiniteScrollListing = <T>({
31
36
  queryKeyName,
32
37
  endpoint,
33
38
  decoder,
34
- pageAtom
39
+ pageAtom,
40
+ suspense = true,
41
+ parameters,
42
+ customQueryParameters,
43
+ limit = 100
35
44
  }: UseInfiniteScrollListingProps<T>): UseInfiniteScrollListing<T> => {
36
45
  const [maxPage, setMaxPage] = useState(1);
37
46
 
@@ -46,14 +55,15 @@ export const useInfiniteScrollListing = <T>({
46
55
  getEndpoint: (params) =>
47
56
  buildListingEndpoint({
48
57
  baseEndpoint: endpoint,
49
- parameters: { limit, page: params?.page || page }
58
+ customQueryParameters,
59
+ parameters: { limit, page: params?.page || page, ...parameters }
50
60
  }),
51
61
  getQueryKey: () => [queryKeyName, page],
52
62
  isPaginated: true,
53
63
  queryOptions: {
54
64
  refetchOnMount: false,
55
65
  refetchOnWindowFocus: false,
56
- suspense: equals(page, 1)
66
+ suspense: suspense && equals(page, 1)
57
67
  }
58
68
  });
59
69
 
@@ -98,9 +108,14 @@ export const useInfiniteScrollListing = <T>({
98
108
  });
99
109
  }, [data]);
100
110
 
111
+ useEffect(() => {
112
+ return () => setPage(1);
113
+ }, []);
114
+
101
115
  return {
102
116
  elementRef,
103
117
  elements: elements.current || [],
104
- isLoading
118
+ isLoading,
119
+ total: data?.meta.total
105
120
  };
106
121
  };