@centreon/ui 24.4.1-MON-33898.13 → 24.4.1-MON-21278-Delete-a-basic-token.9

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 (66) hide show
  1. package/package.json +1 -1
  2. package/src/Button/Icon/index.stories.tsx +1 -1
  3. package/src/Button/Icon/index.tsx +1 -1
  4. package/src/Dialog/Confirm/index.tsx +10 -2
  5. package/src/Dialog/index.tsx +8 -1
  6. package/src/InputField/Select/IconPopover/index.tsx +1 -1
  7. package/src/Listing/ActionBar/index.tsx +2 -1
  8. package/src/Panel/index.tsx +1 -1
  9. package/src/components/Form/AccessRights/AccessRights.resource.ts +45 -0
  10. package/src/components/Form/AccessRights/AccessRightsForm.stories.tsx +59 -0
  11. package/src/components/Form/AccessRights/AccessRightsForm.styles.ts +21 -0
  12. package/src/components/Form/AccessRights/AccessRightsForm.tsx +67 -0
  13. package/src/components/Form/AccessRights/AccessRightsFormActions.tsx +80 -0
  14. package/src/components/Form/AccessRights/Input/AddAction.tsx +31 -0
  15. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.stories.tsx +54 -0
  16. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.tsx +72 -0
  17. package/src/components/Form/AccessRights/Input/ContactAccessRightsInput.styles.ts +22 -0
  18. package/src/components/Form/AccessRights/Input/ContactInputField.tsx +105 -0
  19. package/src/components/Form/AccessRights/Input/RoleInputField.tsx +29 -0
  20. package/src/components/Form/AccessRights/List/ContactAccessRightsList.stories.tsx +97 -0
  21. package/src/components/Form/AccessRights/List/ContactAccessRightsList.styles.ts +71 -0
  22. package/src/components/Form/AccessRights/List/ContactAccessRightsList.tsx +51 -0
  23. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.stories.tsx +116 -0
  24. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.tsx +118 -0
  25. package/src/components/Form/AccessRights/List/ContactAccessRightsListItemSkeleton.tsx +26 -0
  26. package/src/components/Form/AccessRights/List/ContactAccessRightsListSkeleton.tsx +28 -0
  27. package/src/components/Form/AccessRights/Stats/AccessRightsStats.styles.ts +18 -0
  28. package/src/components/Form/AccessRights/Stats/AccessRightsStats.tsx +41 -0
  29. package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +54 -0
  30. package/src/components/Form/AccessRights/common/GroupLabel.styles.ts +18 -0
  31. package/src/components/Form/AccessRights/common/GroupLabel.tsx +15 -0
  32. package/src/components/Form/AccessRights/common/Input.styles.ts +48 -0
  33. package/src/components/Form/AccessRights/common/RoleInputSelect.styles.ts +11 -0
  34. package/src/components/Form/AccessRights/common/RoleInputSelect.tsx +57 -0
  35. package/src/components/Form/AccessRights/index.ts +3 -0
  36. package/src/components/Form/AccessRights/useAccessRightsForm.test.tsx +531 -0
  37. package/src/components/Form/AccessRights/useAccessRightsForm.tsx +282 -0
  38. package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +41 -0
  39. package/src/components/Form/{AccessRights → AccessRightsV2}/AccessRights.cypress.spec.tsx +0 -23
  40. package/src/components/Form/{AccessRights → AccessRightsV2}/ShareInput/ContactSwitch.tsx +1 -9
  41. package/src/components/Form/{AccessRights → AccessRightsV2}/ShareInput/ShareInput.styles.ts +0 -8
  42. package/src/components/Form/{AccessRights → AccessRightsV2}/ShareInput/useShareInput.tsx +0 -4
  43. package/src/components/Form/{AccessRights → AccessRightsV2}/models.ts +0 -1
  44. package/src/components/Form/{AccessRights → AccessRightsV2}/storiesData.ts +0 -1
  45. package/src/components/Form/index.ts +2 -2
  46. /package/src/components/Form/{AccessRights → AccessRightsV2}/AccessRights.stories.tsx +0 -0
  47. /package/src/components/Form/{AccessRights → AccessRightsV2}/AccessRights.styles.ts +0 -0
  48. /package/src/components/Form/{AccessRights → AccessRightsV2}/AccessRights.tsx +0 -0
  49. /package/src/components/Form/{AccessRights → AccessRightsV2}/Actions/Actions.styles.ts +0 -0
  50. /package/src/components/Form/{AccessRights → AccessRightsV2}/Actions/Actions.tsx +0 -0
  51. /package/src/components/Form/{AccessRights → AccessRightsV2}/Actions/useActions.ts +0 -0
  52. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/Item.tsx +0 -0
  53. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/List.styles.tsx +0 -0
  54. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/List.tsx +0 -0
  55. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/ListItemSkeleton.tsx +0 -0
  56. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/ListSkeleton.tsx +0 -0
  57. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/RemoveAccessRight.tsx +0 -0
  58. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/StateChip.tsx +0 -0
  59. /package/src/components/Form/{AccessRights → AccessRightsV2}/List/useItem.ts +0 -0
  60. /package/src/components/Form/{AccessRights → AccessRightsV2}/Provider.tsx +0 -0
  61. /package/src/components/Form/{AccessRights → AccessRightsV2}/ShareInput/ShareInput.tsx +0 -0
  62. /package/src/components/Form/{AccessRights → AccessRightsV2}/Stats/Stats.tsx +0 -0
  63. /package/src/components/Form/{AccessRights → AccessRightsV2}/atoms.ts +0 -0
  64. /package/src/components/Form/{AccessRights → AccessRightsV2}/common/RoleSelectField.styles.tsx +0 -0
  65. /package/src/components/Form/{AccessRights → AccessRightsV2}/common/RoleSelectField.tsx +0 -0
  66. /package/src/components/Form/{AccessRights → AccessRightsV2}/useAccessRightsInitValues.ts +0 -0
@@ -0,0 +1,282 @@
1
+ import { ReactElement, ReactNode, useEffect, useRef } from 'react';
2
+
3
+ import {
4
+ atom,
5
+ createStore,
6
+ Provider,
7
+ useAtom,
8
+ useAtomValue,
9
+ useSetAtom,
10
+ useStore
11
+ } from 'jotai';
12
+
13
+ import {
14
+ ContactAccessRightResource,
15
+ ContactAccessRightStateResource,
16
+ ContactGroupResource,
17
+ ContactResource,
18
+ RoleResource
19
+ } from './AccessRights.resource';
20
+ import {
21
+ createInitialState,
22
+ sortOnAddedStateFirstAndContactName
23
+ } from './useAccessRightsForm.utils';
24
+
25
+ /** state */
26
+
27
+ type loadingState = 'idle' | 'loading';
28
+
29
+ const loadingStatusAtom = atom<loadingState>('idle');
30
+
31
+ type formOptions = {
32
+ contacts: Array<ContactResource | ContactGroupResource>;
33
+ roles: Array<RoleResource>;
34
+ };
35
+
36
+ const formOptionsAtom = atom<formOptions>({
37
+ contacts: [],
38
+ roles: []
39
+ });
40
+
41
+ const contactAccessRightsAtom = atom<Array<ContactAccessRightStateResource>>(
42
+ []
43
+ );
44
+
45
+ type StateStats = {
46
+ added: number;
47
+ removed: number;
48
+ updated: number;
49
+ };
50
+
51
+ const contactAccessRightsStateAtom = atom<{
52
+ isDirty: boolean;
53
+ isLoading: boolean;
54
+ stats: StateStats;
55
+ }>((get) => ({
56
+ isDirty: get(contactAccessRightsAtom).some(
57
+ ({ state }) => state !== 'unchanged'
58
+ ),
59
+ isLoading: get(loadingStatusAtom) === 'loading',
60
+ stats: {
61
+ added: get(contactAccessRightsAtom).filter(({ state }) => state === 'added')
62
+ .length,
63
+ removed: get(contactAccessRightsAtom).filter(
64
+ ({ state }) => state === 'removed'
65
+ ).length,
66
+ updated: get(contactAccessRightsAtom).filter(
67
+ ({ state }) => state === 'updated'
68
+ ).length
69
+ }
70
+ }));
71
+
72
+ type callbacks = {
73
+ onSubmit?: (values: Array<ContactAccessRightStateResource>) => void;
74
+ };
75
+
76
+ const callbacksAtom = atom<callbacks>({});
77
+
78
+ /** provider */
79
+
80
+ export type AccessRightsFormProviderProps = {
81
+ children: ReactNode;
82
+ initialValues?: Array<ContactAccessRightResource>;
83
+ loadingStatus?: loadingState;
84
+ onSubmit?: callbacks['onSubmit'];
85
+ options?: formOptions;
86
+ };
87
+
88
+ const AccessRightsFormProvider = ({
89
+ children,
90
+ initialValues,
91
+ options,
92
+ loadingStatus = 'idle',
93
+ onSubmit
94
+ }: AccessRightsFormProviderProps): ReactElement => {
95
+ const store = useRef(createStore()).current;
96
+
97
+ const setLoadingStatus = useSetAtom(loadingStatusAtom, { store });
98
+ const setFormOptions = useSetAtom(formOptionsAtom, { store });
99
+ const setContactAccessRights = useSetAtom(contactAccessRightsAtom, { store });
100
+ const setCallbacks = useSetAtom(callbacksAtom, { store });
101
+
102
+ useEffect(() => {
103
+ setLoadingStatus(loadingStatus);
104
+ }, [loadingStatus]);
105
+
106
+ useEffect(() => {
107
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
108
+ options && setFormOptions(options);
109
+ }, [options]);
110
+
111
+ useEffect(() => {
112
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
113
+ onSubmit && setCallbacks({ onSubmit });
114
+ }, [onSubmit]);
115
+
116
+ useEffect(() => {
117
+ setContactAccessRights(
118
+ initialValues ? createInitialState(initialValues) : []
119
+ );
120
+ }, [initialValues]);
121
+
122
+ return <Provider store={store}>{children}</Provider>;
123
+ };
124
+
125
+ /** hook */
126
+
127
+ type UseAccessRightsForm = {
128
+ addContactAccessRight: (
129
+ contactAccessRight: ContactAccessRightResource
130
+ ) => void;
131
+ contactAccessRights: Array<ContactAccessRightStateResource>;
132
+ isDirty: boolean;
133
+ isLoading: boolean;
134
+ options: formOptions;
135
+ removeContactAccessRight: (
136
+ contactAccessRight: ContactAccessRightResource,
137
+ restore?: boolean
138
+ ) => void;
139
+ stats: StateStats;
140
+ submit: () => void;
141
+ updateContactAccessRight: (
142
+ contactAccessRight: ContactAccessRightResource
143
+ ) => void;
144
+ };
145
+
146
+ const useAccessRightsForm = (): UseAccessRightsForm => {
147
+ const store = useStore();
148
+
149
+ const [contactAccessRights, setContactAccessRights] = useAtom(
150
+ contactAccessRightsAtom,
151
+ { store }
152
+ );
153
+ const { isLoading, isDirty, stats } = useAtomValue(
154
+ contactAccessRightsStateAtom,
155
+ { store }
156
+ );
157
+ const options = useAtomValue(formOptionsAtom, { store });
158
+ const callbacks = useAtomValue(callbacksAtom, { store });
159
+
160
+ const addContactAccessRight = (
161
+ contactAccessRight: ContactAccessRightResource
162
+ ): void =>
163
+ setContactAccessRights((prev) => {
164
+ const isContactAlreadyAdded = prev.some(
165
+ ({ contactAccessRight: c }) =>
166
+ c.contact?.id === contactAccessRight.contact?.id
167
+ );
168
+
169
+ return isContactAlreadyAdded
170
+ ? prev
171
+ : [
172
+ ...prev,
173
+ {
174
+ contactAccessRight,
175
+ state: 'added',
176
+ stateHistory: []
177
+ } as ContactAccessRightStateResource
178
+ ].sort(sortOnAddedStateFirstAndContactName);
179
+ });
180
+
181
+ const removeContactAccessRight = (
182
+ contactAccessRight: ContactAccessRightResource,
183
+ restore = false
184
+ ): void =>
185
+ setContactAccessRights((prev) => {
186
+ const contactAccessRightIndex = prev.findIndex(
187
+ ({ contactAccessRight: prevContactAccessRight }) =>
188
+ prevContactAccessRight.contact?.id === contactAccessRight.contact?.id
189
+ );
190
+
191
+ if (contactAccessRightIndex === -1) {
192
+ return prev;
193
+ }
194
+
195
+ const { stateHistory } = prev[contactAccessRightIndex];
196
+
197
+ if (restore) {
198
+ return [
199
+ ...prev.slice(0, contactAccessRightIndex),
200
+ {
201
+ ...prev[contactAccessRightIndex],
202
+ state: stateHistory[stateHistory.length - 1],
203
+ stateHistory: [...stateHistory, prev[contactAccessRightIndex].state]
204
+ } as ContactAccessRightStateResource,
205
+ ...prev.slice(contactAccessRightIndex + 1)
206
+ ];
207
+ }
208
+
209
+ if (
210
+ prev[contactAccessRightIndex].state === 'added' ||
211
+ stateHistory[0] === 'added'
212
+ ) {
213
+ return [
214
+ ...prev.slice(0, contactAccessRightIndex),
215
+ ...prev.slice(contactAccessRightIndex + 1)
216
+ ];
217
+ }
218
+
219
+ return [
220
+ ...prev.slice(0, contactAccessRightIndex),
221
+ {
222
+ ...prev[contactAccessRightIndex],
223
+ state: 'removed',
224
+ stateHistory: [...stateHistory, prev[contactAccessRightIndex].state]
225
+ } as ContactAccessRightStateResource,
226
+ ...prev.slice(contactAccessRightIndex + 1)
227
+ ];
228
+ });
229
+
230
+ const updateContactAccessRight = (
231
+ contactAccessRight: ContactAccessRightResource
232
+ ): void =>
233
+ setContactAccessRights((prev) => {
234
+ const contactAccessRightIndex = prev.findIndex(
235
+ ({ contactAccessRight: prevContactAccessRight }) =>
236
+ prevContactAccessRight.contact?.id === contactAccessRight.contact?.id
237
+ );
238
+
239
+ if (contactAccessRightIndex === -1) {
240
+ return prev;
241
+ }
242
+
243
+ const { stateHistory } = prev[contactAccessRightIndex];
244
+
245
+ const isAdded =
246
+ prev[contactAccessRightIndex].state === 'added' ||
247
+ stateHistory[0] === 'added';
248
+ const isUpdated =
249
+ prev[contactAccessRightIndex].state === 'updated' ||
250
+ stateHistory.findIndex((state) => state === 'updated') <
251
+ stateHistory.findIndex((state) => state === 'unchanged');
252
+
253
+ // eslint-disable-next-line no-nested-ternary
254
+ const state = isAdded ? 'added' : isUpdated ? 'unchanged' : 'updated';
255
+
256
+ return [
257
+ ...prev.slice(0, contactAccessRightIndex),
258
+ {
259
+ contactAccessRight,
260
+ state,
261
+ stateHistory: [...stateHistory, prev[contactAccessRightIndex].state]
262
+ } as ContactAccessRightStateResource,
263
+ ...prev.slice(contactAccessRightIndex + 1)
264
+ ];
265
+ });
266
+
267
+ const submit = (): void => callbacks.onSubmit?.(contactAccessRights);
268
+
269
+ return {
270
+ addContactAccessRight,
271
+ contactAccessRights,
272
+ isDirty,
273
+ isLoading,
274
+ options,
275
+ removeContactAccessRight,
276
+ stats,
277
+ submit,
278
+ updateContactAccessRight
279
+ };
280
+ };
281
+
282
+ export { AccessRightsFormProvider, useAccessRightsForm };
@@ -0,0 +1,41 @@
1
+ import { ContactAccessRightStateResource } from './AccessRights.resource';
2
+
3
+ export const sortOnContactName = (
4
+ a: ContactAccessRightStateResource,
5
+ b: ContactAccessRightStateResource
6
+ ): number =>
7
+ a.contactAccessRight.contact?.name.localeCompare(
8
+ b.contactAccessRight.contact?.name ?? ''
9
+ ) || 0;
10
+
11
+ export const sortOnAddedStateFirstAndContactName = (
12
+ a: ContactAccessRightStateResource,
13
+ b: ContactAccessRightStateResource
14
+ ): number => {
15
+ if (a.state === 'added' && b.state !== 'added') {
16
+ return -1;
17
+ }
18
+ if (a.state !== 'added' && b.state === 'added') {
19
+ return 1;
20
+ }
21
+
22
+ return (
23
+ a.contactAccessRight.contact?.name.localeCompare(
24
+ b.contactAccessRight.contact?.name ?? ''
25
+ ) || 0
26
+ );
27
+ };
28
+
29
+ export const createInitialState = (
30
+ values
31
+ ): Array<ContactAccessRightStateResource> =>
32
+ values
33
+ ?.map(
34
+ (contactAccessRight) =>
35
+ ({
36
+ contactAccessRight,
37
+ state: 'unchanged',
38
+ stateHistory: []
39
+ }) as ContactAccessRightStateResource
40
+ )
41
+ .sort(sortOnAddedStateFirstAndContactName);
@@ -347,27 +347,4 @@ describe('Access rights', () => {
347
347
 
348
348
  cy.makeSnapshot();
349
349
  });
350
-
351
- it('resets the role to "viewer" when the "editor" role is selected and a contact with "viewer" right is selected', () => {
352
- initialize({});
353
-
354
- cy.findByLabelText(labels.add.autocompleteContact).click();
355
-
356
- cy.waitForRequest('@getContacts');
357
-
358
- cy.contains('Entity 10').click();
359
-
360
- cy.findByTestId('add_role').parent().click();
361
- cy.get('li[data-value="editor"]').click();
362
-
363
- cy.findByLabelText(labels.add.autocompleteContact).click();
364
-
365
- cy.waitForRequest('@getContacts');
366
-
367
- cy.contains('Entity 11').click();
368
-
369
- cy.findByTestId('add_role').should('have.value', 'viewer');
370
-
371
- cy.makeSnapshot();
372
- });
373
350
  });
@@ -7,14 +7,11 @@ import { ContactType, Labels } from '../models';
7
7
  import { contactTypeAtom } from '../atoms';
8
8
  import { Subtitle } from '../../../..';
9
9
 
10
- import { useContactSwitchStyles } from './ShareInput.styles';
11
-
12
10
  interface Props {
13
11
  labels: Labels['add'];
14
12
  }
15
13
 
16
14
  const ContactSwitch = ({ labels }: Props): JSX.Element => {
17
- const { classes } = useContactSwitchStyles();
18
15
  const { t } = useTranslation();
19
16
 
20
17
  const setContactType = useSetAtom(contactTypeAtom);
@@ -26,12 +23,7 @@ const ContactSwitch = ({ labels }: Props): JSX.Element => {
26
23
  return (
27
24
  <>
28
25
  <Subtitle>{t(labels.title)}</Subtitle>
29
- <RadioGroup
30
- row
31
- className={classes.inputs}
32
- defaultValue={ContactType.Contact}
33
- onChange={change}
34
- >
26
+ <RadioGroup row defaultValue={ContactType.Contact} onChange={change}>
35
27
  <FormControlLabel
36
28
  control={<Radio />}
37
29
  label={labels.contact}
@@ -7,11 +7,3 @@ export const useShareInputStyles = makeStyles()((theme) => ({
7
7
  gridTemplateColumns: `1fr min-content min-content`
8
8
  }
9
9
  }));
10
-
11
- export const useContactSwitchStyles = makeStyles()((theme) => ({
12
- inputs: {
13
- display: 'flex',
14
- flexDirection: 'row',
15
- gap: theme.spacing(2)
16
- }
17
- }));
@@ -40,10 +40,6 @@ const useShareInput = (endpoints: Endpoints): UseShareInputState => {
40
40
 
41
41
  const selectContact = (_, entry): void => {
42
42
  setSelectedContact(entry);
43
- if (equals('editor', entry.most_permissive_role)) {
44
- return;
45
- }
46
- setSelectedRole('viewer');
47
43
  };
48
44
 
49
45
  const add = (): void => {
@@ -2,7 +2,6 @@ export interface AccessRightInitialValues {
2
2
  email?: string;
3
3
  id: number | string;
4
4
  isContactGroup: boolean;
5
- most_permissive_role?: 'editor' | 'viewer';
6
5
  name: string;
7
6
  role: string;
8
7
  }
@@ -88,7 +88,6 @@ const buildEntities = (from, isGroup): Array<SelectEntry> => {
88
88
  .map((_, index) => ({
89
89
  email: isGroup ? undefined : faker.internet.email(),
90
90
  id: 1000 + index,
91
- most_permissive_role: index % 3 === 0 ? 'editor' : 'viewer',
92
91
  name: `Entity ${isGroup ? 'Group' : ''} ${from + index}`
93
92
  }));
94
93
  };
@@ -1,4 +1,4 @@
1
1
  export * from './Form.models';
2
2
  export * from './Dashboard';
3
- export { default as AccessRights } from './AccessRights/AccessRights';
4
- export { default as AccessRightsV2 } from './AccessRights/AccessRights';
3
+ export * from './AccessRights';
4
+ export { default as AccessRightsV2 } from './AccessRightsV2/AccessRights';