@centreon/ui 23.10.39 → 23.10.41

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 (68) hide show
  1. package/package.json +3 -1
  2. package/src/Listing/Cell/DataCell.tsx +16 -4
  3. package/src/Listing/Cell/index.tsx +82 -2
  4. package/src/Listing/Listing.cypress.spec.tsx +120 -0
  5. package/src/Listing/Listing.styles.ts +2 -2
  6. package/src/Listing/ListingDocs.mdx +61 -0
  7. package/src/Listing/Row/Row.tsx +5 -2
  8. package/src/Listing/index.stories.tsx +104 -31
  9. package/src/Listing/index.tsx +103 -33
  10. package/src/Listing/models.ts +1 -0
  11. package/src/Listing/tableAtoms.ts +2 -0
  12. package/src/Panel/index.tsx +1 -1
  13. package/src/ThemeProvider/index.tsx +0 -24
  14. package/src/ThemeProvider/palettes.ts +36 -6
  15. package/src/api/useMutationQuery/index.ts +16 -6
  16. package/src/components/Form/AccessRights/AccessRights.resource.ts +45 -0
  17. package/src/components/Form/AccessRights/AccessRightsForm.stories.tsx +59 -0
  18. package/src/components/Form/AccessRights/AccessRightsForm.styles.ts +21 -0
  19. package/src/components/Form/AccessRights/AccessRightsForm.tsx +67 -0
  20. package/src/components/Form/AccessRights/AccessRightsFormActions.tsx +80 -0
  21. package/src/components/Form/AccessRights/Input/AddAction.tsx +31 -0
  22. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.stories.tsx +54 -0
  23. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.tsx +72 -0
  24. package/src/components/Form/AccessRights/Input/ContactAccessRightsInput.styles.ts +22 -0
  25. package/src/components/Form/AccessRights/Input/ContactInputField.tsx +105 -0
  26. package/src/components/Form/AccessRights/Input/RoleInputField.tsx +29 -0
  27. package/src/components/Form/AccessRights/List/ContactAccessRightsList.stories.tsx +97 -0
  28. package/src/components/Form/AccessRights/List/ContactAccessRightsList.styles.ts +71 -0
  29. package/src/components/Form/AccessRights/List/ContactAccessRightsList.tsx +51 -0
  30. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.stories.tsx +116 -0
  31. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.tsx +118 -0
  32. package/src/components/Form/AccessRights/List/ContactAccessRightsListItemSkeleton.tsx +26 -0
  33. package/src/components/Form/AccessRights/List/ContactAccessRightsListSkeleton.tsx +28 -0
  34. package/src/components/Form/AccessRights/Stats/AccessRightsStats.styles.ts +18 -0
  35. package/src/components/Form/AccessRights/Stats/AccessRightsStats.tsx +41 -0
  36. package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +52 -0
  37. package/src/components/Form/AccessRights/common/GroupLabel.styles.ts +18 -0
  38. package/src/components/Form/AccessRights/common/GroupLabel.tsx +15 -0
  39. package/src/components/Form/AccessRights/common/Input.styles.ts +48 -0
  40. package/src/components/Form/AccessRights/common/RoleInputSelect.styles.ts +11 -0
  41. package/src/components/Form/AccessRights/common/RoleInputSelect.tsx +57 -0
  42. package/src/components/Form/AccessRights/index.ts +3 -0
  43. package/src/components/Form/AccessRights/useAccessRightsForm.test.tsx +531 -0
  44. package/src/components/Form/AccessRights/useAccessRightsForm.tsx +282 -0
  45. package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +41 -0
  46. package/src/components/Form/Dashboard/DashboardForm.styles.ts +1 -7
  47. package/src/components/Form/Dashboard/DashboardForm.tsx +9 -12
  48. package/src/components/Form/Form.resource.ts +1 -0
  49. package/src/components/Form/Form.styles.ts +17 -0
  50. package/src/components/Form/{Dashboard/DashboardFormActions.tsx → FormActions.tsx} +17 -16
  51. package/src/components/Form/index.ts +1 -0
  52. package/src/components/Header/PageHeader/PageHeader.stories.tsx +9 -0
  53. package/src/components/List/Item/Avatar.tsx +21 -0
  54. package/src/components/List/Item/AvatarSkeleton.tsx +17 -0
  55. package/src/components/List/Item/ListItem.stories.tsx +41 -0
  56. package/src/components/List/Item/ListItem.styles.ts +57 -0
  57. package/src/components/List/Item/ListItem.tsx +32 -0
  58. package/src/components/List/Item/Text.tsx +25 -0
  59. package/src/components/List/Item/TextSkeleton.tsx +22 -0
  60. package/src/components/List/Item/index.ts +14 -0
  61. package/src/components/List/List.stories.tsx +70 -0
  62. package/src/components/List/List.styles.ts +8 -0
  63. package/src/components/List/List.tsx +19 -0
  64. package/src/components/List/index.ts +6 -0
  65. package/src/components/Modal/ModalActions.tsx +4 -1
  66. package/src/components/index.ts +1 -0
  67. package/src/utils/index.ts +1 -0
  68. package/src/utils/useInfiniteScrollListing.ts +106 -0
@@ -0,0 +1,116 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+
3
+ import { Meta, StoryObj } from '@storybook/react';
4
+
5
+ import {
6
+ AccessRightsFormProvider,
7
+ AccessRightsFormProviderProps
8
+ } from '../useAccessRightsForm';
9
+ import { ContactAccessRightResource } from '../AccessRights.resource';
10
+
11
+ import { ContactAccessRightsListItem } from './ContactAccessRightsListItem';
12
+ import { ContactAccessRightsListItemSkeleton } from './ContactAccessRightsListItemSkeleton';
13
+
14
+ const meta: Meta<typeof ContactAccessRightsListItem> = {
15
+ component: ContactAccessRightsListItem,
16
+ title: 'components/Form/AccessRights/ContactAccessRightsListItem'
17
+ };
18
+
19
+ export default meta;
20
+ type Story = StoryObj<typeof ContactAccessRightsListItem>;
21
+
22
+ const Wrapper = ({ children }: { children: ReactNode }): ReactElement => {
23
+ const options: AccessRightsFormProviderProps['options'] = {
24
+ contacts: [],
25
+ roles: [{ role: 'viewer' }, { role: 'editor' }]
26
+ };
27
+
28
+ return (
29
+ <AccessRightsFormProvider options={options}>
30
+ {children}
31
+ </AccessRightsFormProvider>
32
+ );
33
+ };
34
+
35
+ export const Default: Story = {
36
+ args: {
37
+ labels: {
38
+ group: 'Group',
39
+ state: {
40
+ added: 'Add',
41
+ removed: 'Remove',
42
+ updated: 'Update'
43
+ }
44
+ },
45
+ resource: {
46
+ contactAccessRight: {
47
+ contact: {
48
+ email: 'user@company.com',
49
+ id: '1',
50
+ name: 'User Name',
51
+ type: 'contact'
52
+ },
53
+ role: 'viewer'
54
+ },
55
+ state: 'unchanged',
56
+ stateHistory: []
57
+ }
58
+ },
59
+ render: (args) => (
60
+ <Wrapper>
61
+ <ContactAccessRightsListItem {...args} />
62
+ </Wrapper>
63
+ )
64
+ };
65
+
66
+ export const AsContactGroup: Story = {
67
+ args: {
68
+ labels: Default.args?.labels,
69
+ resource: {
70
+ contactAccessRight: {
71
+ contact: {
72
+ id: '1',
73
+ name: 'Team Name',
74
+ type: 'contact_group'
75
+ },
76
+ role: 'editor'
77
+ },
78
+ state: 'unchanged',
79
+ stateHistory: []
80
+ }
81
+ },
82
+ render: Default.render
83
+ };
84
+
85
+ export const WithAddedState: Story = {
86
+ args: {
87
+ labels: Default.args?.labels,
88
+ resource: {
89
+ contactAccessRight: {
90
+ ...Default.args?.resource?.contactAccessRight
91
+ } as ContactAccessRightResource,
92
+ state: 'added',
93
+ stateHistory: []
94
+ }
95
+ },
96
+ render: Default.render
97
+ };
98
+
99
+ export const WithRemovedState: Story = {
100
+ args: {
101
+ labels: Default.args?.labels,
102
+ resource: {
103
+ contactAccessRight: {
104
+ ...Default.args?.resource?.contactAccessRight
105
+ } as ContactAccessRightResource,
106
+ state: 'removed',
107
+ stateHistory: []
108
+ }
109
+ },
110
+ render: Default.render
111
+ };
112
+
113
+ export const AsLoadingState: Story = {
114
+ args: {},
115
+ render: () => <ContactAccessRightsListItemSkeleton />
116
+ };
@@ -0,0 +1,118 @@
1
+ import { ReactElement, useMemo } from 'react';
2
+
3
+ import RotateRightIcon from '@mui/icons-material/RotateRight';
4
+ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
5
+ import { Chip as MuiChip } from '@mui/material';
6
+
7
+ import { IconButton } from '../../../Button';
8
+ import { List } from '../../../List';
9
+ import {
10
+ ContactAccessRightState,
11
+ ContactAccessRightStateResource,
12
+ isContactResource
13
+ } from '../AccessRights.resource';
14
+ import { useAccessRightsForm } from '../useAccessRightsForm';
15
+ import { RoleInputSelect } from '../common/RoleInputSelect';
16
+ import { GroupLabel } from '../common/GroupLabel';
17
+
18
+ import { useStyles } from './ContactAccessRightsList.styles';
19
+
20
+ export type ContactAccessRightsListItemProps = {
21
+ hasAvatar?: boolean;
22
+ labels: {
23
+ group: string;
24
+ state: Record<Exclude<ContactAccessRightState, 'unchanged'>, string>;
25
+ };
26
+ resource: ContactAccessRightStateResource;
27
+ };
28
+
29
+ const ContactAccessRightsListItem = ({
30
+ labels,
31
+ resource: { contactAccessRight, state },
32
+ hasAvatar = true
33
+ }: ContactAccessRightsListItemProps): ReactElement => {
34
+ const { classes } = useStyles();
35
+ const { updateContactAccessRight, removeContactAccessRight } =
36
+ useAccessRightsForm();
37
+
38
+ const isRemoved = useMemo(() => state === 'removed', [state]);
39
+
40
+ const updateRole = (e): void => {
41
+ updateContactAccessRight({
42
+ ...contactAccessRight,
43
+ role: e.target.value
44
+ });
45
+ };
46
+ const toggleRemoved = (): void => {
47
+ removeContactAccessRight(contactAccessRight, isRemoved);
48
+ };
49
+
50
+ const getNameInitials = (name: string): string =>
51
+ name
52
+ .split(' ')
53
+ .map((n) => n.charAt(0).toUpperCase())
54
+ .slice(0, 2)
55
+ .join('');
56
+
57
+ return (
58
+ <List.Item
59
+ action={
60
+ <IconButton
61
+ data-testid={isRemoved ? 'restore_user' : 'remove_user'}
62
+ icon={isRemoved ? <RotateRightIcon /> : <DeleteOutlineIcon />}
63
+ size="small"
64
+ variant="primary"
65
+ onClick={toggleRemoved}
66
+ />
67
+ }
68
+ className={classes.contactAccessRightsListItem}
69
+ data-is-removed={isRemoved}
70
+ data-state={state}
71
+ key={contactAccessRight.contact?.id}
72
+ >
73
+ <span>
74
+ {hasAvatar && (
75
+ <List.Item.Avatar>
76
+ {getNameInitials(contactAccessRight.contact?.name || '')}
77
+ </List.Item.Avatar>
78
+ )}
79
+ <List.Item.Text
80
+ primaryText={
81
+ contactAccessRight.contact && (
82
+ <>
83
+ {contactAccessRight.contact.name}{' '}
84
+ {!isContactResource(contactAccessRight.contact) && (
85
+ <GroupLabel label={labels.group} />
86
+ )}
87
+ </>
88
+ )
89
+ }
90
+ secondaryText={
91
+ isContactResource(contactAccessRight.contact) &&
92
+ contactAccessRight.contact?.email
93
+ ? contactAccessRight.contact?.email
94
+ : undefined
95
+ }
96
+ />
97
+ </span>
98
+
99
+ {state !== 'unchanged' && (
100
+ <MuiChip
101
+ data-state={state}
102
+ label={labels.state[state]}
103
+ size="small"
104
+ variant="outlined"
105
+ />
106
+ )}
107
+ <RoleInputSelect
108
+ disabled={isRemoved}
109
+ id={`role-${contactAccessRight.contact?.id}`}
110
+ name={`role-${contactAccessRight.contact?.id}`}
111
+ value={contactAccessRight.role}
112
+ onChange={updateRole}
113
+ />
114
+ </List.Item>
115
+ );
116
+ };
117
+
118
+ export { ContactAccessRightsListItem };
@@ -0,0 +1,26 @@
1
+ import { ReactElement } from 'react';
2
+
3
+ import { List } from '../../../List';
4
+
5
+ import { useStyles } from './ContactAccessRightsList.styles';
6
+
7
+ export type ContactAccessRightsListItemSkeletonProps = {
8
+ hasAvatar?: boolean;
9
+ };
10
+
11
+ const ContactAccessRightsListItemSkeleton = ({
12
+ hasAvatar = true
13
+ }: ContactAccessRightsListItemSkeletonProps): ReactElement => {
14
+ const { classes } = useStyles();
15
+
16
+ return (
17
+ <List.Item className={classes.contactAccessRightsListItem}>
18
+ <span>
19
+ {hasAvatar && <List.Item.Avatar.Skeleton />}
20
+ <List.Item.Text.Skeleton secondaryText />
21
+ </span>
22
+ </List.Item>
23
+ );
24
+ };
25
+
26
+ export { ContactAccessRightsListItemSkeleton };
@@ -0,0 +1,28 @@
1
+ import { ReactElement } from 'react';
2
+
3
+ import { List } from '../../../List';
4
+
5
+ import { useStyles } from './ContactAccessRightsList.styles';
6
+ import { ContactAccessRightsListItemSkeleton } from './ContactAccessRightsListItemSkeleton';
7
+
8
+ export type ContactAccessRightsListSkeletonProps = {
9
+ length?: number;
10
+ };
11
+
12
+ const ContactAccessRightsListSkeleton = ({
13
+ length = 3
14
+ }: ContactAccessRightsListSkeletonProps): ReactElement => {
15
+ const { classes } = useStyles();
16
+
17
+ return (
18
+ <div className={classes.contactAccessRightsList}>
19
+ <List>
20
+ {[...Array(length).keys()].map((key) => (
21
+ <ContactAccessRightsListItemSkeleton key={key} />
22
+ ))}
23
+ </List>
24
+ </div>
25
+ );
26
+ };
27
+
28
+ export { ContactAccessRightsListSkeleton };
@@ -0,0 +1,18 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ const useStyles = makeStyles()((theme) => ({
4
+ accessRightsStats: {
5
+ '& > span:not(:last-child)::after': {
6
+ content: '", "'
7
+ },
8
+ alignSelf: 'flex-end',
9
+ color: theme.palette.text.secondary,
10
+ fontSize: '0.75rem',
11
+ height: '1.5rem',
12
+ lineHeight: '1.5rem',
13
+
14
+ padding: theme.spacing(1, 0)
15
+ }
16
+ }));
17
+
18
+ export { useStyles };
@@ -0,0 +1,41 @@
1
+ import { ReactElement, useMemo } from 'react';
2
+
3
+ import { useAccessRightsForm } from '../useAccessRightsForm';
4
+ import { ContactAccessRightState } from '../AccessRights.resource';
5
+
6
+ import { useStyles } from './AccessRightsStats.styles';
7
+
8
+ export type AccessRightsStatsProps = {
9
+ labels: Record<Exclude<ContactAccessRightState, 'unchanged'>, string>;
10
+ };
11
+
12
+ const AccessRightsStats = ({
13
+ labels
14
+ }: AccessRightsStatsProps): ReactElement => {
15
+ const { classes } = useStyles();
16
+
17
+ const { stats } = useAccessRightsForm();
18
+
19
+ const statsElements = useMemo(() => {
20
+ const elements: Array<ReactElement> = [];
21
+
22
+ ['added', 'updated', 'removed'].forEach((state) => {
23
+ if (stats?.[state] > 0)
24
+ elements.push(
25
+ <span key={state}>
26
+ <strong>{stats[state]}</strong> {labels[state]}
27
+ </span>
28
+ );
29
+ });
30
+
31
+ return elements;
32
+ }, [stats]);
33
+
34
+ return (
35
+ <div className={classes.accessRightsStats}>
36
+ {statsElements.length !== 0 && statsElements.map((el) => el)}
37
+ </div>
38
+ );
39
+ };
40
+
41
+ export { AccessRightsStats };
@@ -0,0 +1,52 @@
1
+ import { faker } from '@faker-js/faker';
2
+
3
+ import {
4
+ ContactAccessRightResource,
5
+ ContactGroupResource,
6
+ ContactResource,
7
+ RoleResource
8
+ } from '../AccessRights.resource';
9
+
10
+ export const rolesMock = (): Array<RoleResource> => [
11
+ { role: 'viewer' },
12
+ { role: 'editor' }
13
+ ];
14
+
15
+ export const contactMock = (): ContactResource => ({
16
+ email: faker.internet.email(),
17
+ id: faker.string.uuid(),
18
+ name: faker.person.fullName(),
19
+ type: 'contact'
20
+ });
21
+
22
+ export const contactsMock = (length: number): Array<ContactResource> =>
23
+ [...Array(length).keys()].map(contactMock);
24
+
25
+ export const contactGroupMock = (): ContactGroupResource => ({
26
+ id: faker.string.uuid(),
27
+ name: faker.company.name(),
28
+ type: 'contact_group'
29
+ });
30
+ export const contactGroupsMock = (
31
+ length: number
32
+ ): Array<ContactGroupResource> =>
33
+ [...Array(length).keys()].map(contactGroupMock);
34
+
35
+ export const contactsAndGroupsMock = (
36
+ length: number
37
+ ): Array<ContactResource | ContactGroupResource> =>
38
+ [...Array(length).keys()].map(
39
+ () =>
40
+ faker.helpers.maybe(contactGroupMock, { probability: 0.2 }) ??
41
+ contactMock()
42
+ );
43
+
44
+ export const contactAccessRightsMock = (
45
+ length: number
46
+ ): Array<ContactAccessRightResource> =>
47
+ [...Array(length).keys()].map(() => ({
48
+ contact:
49
+ faker.helpers.maybe(contactGroupMock, { probability: 0.2 }) ??
50
+ contactMock(),
51
+ role: faker.helpers.arrayElement(rolesMock().map(({ role }) => role))
52
+ }));
@@ -0,0 +1,18 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ const useStyles = makeStyles()((theme) => ({
4
+ groupLabel: {
5
+ backgroundColor: theme.palette.chip.color.neutral,
6
+ borderRadius: '0.1875rem',
7
+ color: theme.palette.primary.contrastText,
8
+ fontSize: '0.5625rem',
9
+ fontWeight: 500,
10
+ letterSpacing: '0.05rem',
11
+ marginLeft: theme.spacing(1),
12
+ padding: theme.spacing(0.125, 0.5),
13
+ textTransform: 'uppercase',
14
+ verticalAlign: 'middle'
15
+ }
16
+ }));
17
+
18
+ export { useStyles };
@@ -0,0 +1,15 @@
1
+ import { ReactElement } from 'react';
2
+
3
+ import { useStyles } from './GroupLabel.styles';
4
+
5
+ export type GroupLabelProps = {
6
+ label: string;
7
+ };
8
+
9
+ const GroupLabel = ({ label }: GroupLabelProps): ReactElement => {
10
+ const { classes } = useStyles();
11
+
12
+ return <span className={classes.groupLabel}>{label}</span>;
13
+ };
14
+
15
+ export { GroupLabel };
@@ -0,0 +1,48 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ const useInputStyles = makeStyles()((theme) => ({
4
+ inputDropdown: {
5
+ '& .MuiMenuItem-root': {
6
+ '& > .MuiTouchRipple-root': {
7
+ display: 'none'
8
+ },
9
+
10
+ '&.Mui-disabled': {
11
+ opacity: 0.5
12
+ },
13
+ '&.Mui-selected, &.Mui-selected:hover, &.MuiAutocomplete-option[aria-selected="true"], &.MuiAutocomplete-option[aria-selected="true"].Mui-focused':
14
+ {
15
+ '&.Mui-disabled': {
16
+ opacity: 1
17
+ },
18
+ backgroundColor: theme.palette.menu.item.background.active,
19
+ color: theme.palette.menu.item.color.active,
20
+ opacity: 1
21
+ },
22
+ '&:hover, &.MuiAutocomplete-option.Mui-focused:not(&[aria-selected="true"])':
23
+ {
24
+ backgroundColor: theme.palette.menu.item.background.hover,
25
+ color: theme.palette.menu.item.color.hover
26
+ },
27
+ backgroundColor: theme.palette.menu.item.background.default,
28
+ color: theme.palette.menu.item.color.default,
29
+ fontSize: '0.875rem',
30
+
31
+ minHeight: 'unset',
32
+
33
+ padding: theme.spacing(0.75, 2)
34
+ },
35
+ '&.MuiAutocomplete-popper > .MuiPaper-root, &.MuiPopover-root > .MuiPaper-root':
36
+ {
37
+ '& > ul.MuiAutocomplete-listbox, & > ul.MuiList-root': {
38
+ padding: theme.spacing(1, 0)
39
+ },
40
+ backgroundColor: theme.palette.menu.background,
41
+ borderRadius: '4px',
42
+
43
+ boxShadow: theme.shadows[8]
44
+ }
45
+ }
46
+ }));
47
+
48
+ export { useInputStyles };
@@ -0,0 +1,11 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ const useStyles = makeStyles()(() => ({
4
+ roleInputSelect: {
5
+ flexShrink: 0,
6
+ lineHeight: '1.5',
7
+ minWidth: '6rem'
8
+ }
9
+ }));
10
+
11
+ export { useStyles };
@@ -0,0 +1,57 @@
1
+ import { ReactElement, useCallback } from 'react';
2
+
3
+ import {
4
+ MenuItem as MuiMenuItem,
5
+ Select as MuiSelect,
6
+ SelectProps as MuiSelectProps
7
+ } from '@mui/material';
8
+
9
+ import { useAccessRightsForm } from '../useAccessRightsForm';
10
+ import { RoleResource } from '../AccessRights.resource';
11
+
12
+ import { useStyles } from './RoleInputSelect.styles';
13
+ import { useInputStyles } from './Input.styles';
14
+
15
+ type RoleInputSelectProps = {
16
+ id: string;
17
+ label?: string;
18
+ name: string;
19
+ onChange?: (value: RoleResource['role']) => void;
20
+ } & Pick<MuiSelectProps, 'value' | 'defaultValue' | 'disabled'>;
21
+
22
+ const RoleInputSelect = ({
23
+ label,
24
+ onChange,
25
+ ...props
26
+ }: RoleInputSelectProps): ReactElement => {
27
+ const { classes } = useStyles();
28
+ const { classes: inputClasses } = useInputStyles();
29
+
30
+ const {
31
+ options: { roles }
32
+ } = useAccessRightsForm();
33
+
34
+ const onInputChange = useCallback((e) => onChange?.(e), [onChange]);
35
+
36
+ return (
37
+ <MuiSelect
38
+ size="small"
39
+ {...props}
40
+ {...(label && { label })}
41
+ MenuProps={{
42
+ className: inputClasses.inputDropdown
43
+ }}
44
+ className={classes.roleInputSelect}
45
+ data-testid="role-input"
46
+ onChange={onInputChange}
47
+ >
48
+ {roles.map(({ role }) => (
49
+ <MuiMenuItem key={role} value={role}>
50
+ {role}
51
+ </MuiMenuItem>
52
+ ))}
53
+ </MuiSelect>
54
+ );
55
+ };
56
+
57
+ export { RoleInputSelect };
@@ -0,0 +1,3 @@
1
+ export * from './AccessRightsForm';
2
+ export * from './AccessRights.resource';
3
+ export * from './useAccessRightsForm.utils';