@centreon/ui 24.5.2 → 24.5.3

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 (58) hide show
  1. package/package.json +8 -4
  2. package/public/mockServiceWorker.js +81 -100
  3. package/src/ActionsList/index.stories.tsx +7 -1
  4. package/src/Dashboard/Dashboard.styles.ts +3 -2
  5. package/src/Dashboard/Item.tsx +11 -2
  6. package/src/Dashboard/Layout.tsx +4 -2
  7. package/src/Graph/BarStack/BarStack.stories.tsx +8 -6
  8. package/src/Graph/BarStack/ResponsiveBarStack.tsx +3 -3
  9. package/src/Graph/HeatMap/HeatMap.stories.tsx +20 -0
  10. package/src/Graph/LineChart/index.stories.tsx +1 -1
  11. package/src/Graph/PieChart/PieChart.stories.tsx +11 -15
  12. package/src/Graph/PieChart/ResponsivePie.tsx +1 -1
  13. package/src/Graph/Tree/DescendantNodes.tsx +1 -0
  14. package/src/Graph/Tree/Links.tsx +15 -2
  15. package/src/Graph/Tree/Tree.cypress.spec.tsx +24 -0
  16. package/src/Graph/Tree/Tree.stories.tsx +17 -1
  17. package/src/Graph/Tree/models.ts +3 -0
  18. package/src/TimePeriods/index.stories.tsx +7 -12
  19. package/src/TopCounterElements/TopCounterLayout.tsx +3 -4
  20. package/src/TopCounterElements/useCloseOnLegacyPage.tsx +9 -6
  21. package/src/api/QueryProvider.tsx +1 -1
  22. package/src/api/logger.ts +11 -0
  23. package/src/api/useFetchQuery/index.test.ts +0 -5
  24. package/src/api/useFetchQuery/index.ts +2 -5
  25. package/src/api/useGraphQuery/index.ts +7 -1
  26. package/src/api/useMutationQuery/index.ts +2 -5
  27. package/src/api/useRequest/index.test.ts +0 -3
  28. package/src/api/useRequest/index.ts +3 -6
  29. package/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx +27 -13
  30. package/src/components/Form/AccessRights/AccessRights.stories.tsx +0 -19
  31. package/src/components/Form/AccessRights/AccessRights.styles.ts +1 -1
  32. package/src/components/Form/AccessRights/AccessRights.tsx +6 -5
  33. package/src/components/Form/AccessRights/Actions/Actions.styles.ts +3 -7
  34. package/src/components/Form/AccessRights/Actions/Actions.tsx +15 -32
  35. package/src/components/Form/AccessRights/Actions/useActions.ts +4 -37
  36. package/src/components/Form/AccessRights/models.ts +0 -3
  37. package/src/components/Form/AccessRights/storiesData.ts +0 -3
  38. package/src/components/Form/AccessRights/useAccessRightsChange.ts +30 -0
  39. package/src/components/Form/AccessRights/utils.ts +18 -0
  40. package/src/components/Form/Dashboard/translatedLabels.ts +0 -1
  41. package/src/components/List/Item/ListItem.styles.ts +2 -2
  42. package/src/components/Tabs/Tab.styles.ts +25 -0
  43. package/src/components/Tabs/TabPanel.tsx +22 -0
  44. package/src/components/Tabs/Tabs.cypress.spec.tsx +70 -0
  45. package/src/components/Tabs/Tabs.stories.tsx +55 -0
  46. package/src/components/Tabs/Tabs.tsx +55 -0
  47. package/src/components/Tabs/index.ts +6 -0
  48. package/src/components/Zoom/Minimap.tsx +4 -2
  49. package/src/components/Zoom/Zoom.cypress.spec.tsx +13 -13
  50. package/src/components/Zoom/Zoom.tsx +4 -1
  51. package/src/components/Zoom/ZoomContent.tsx +5 -2
  52. package/src/components/index.ts +1 -0
  53. package/src/index.ts +1 -1
  54. package/src/utils/index.ts +1 -0
  55. package/src/utils/resourcesStatusURL.ts +166 -0
  56. package/src/utils/usePluralizedTranslation.test.ts +159 -0
  57. package/src/utils/usePluralizedTranslation.ts +20 -3
  58. package/src/components/Form/Dashboard/DashboardForm.stories.ts +0 -39
@@ -14,6 +14,8 @@ export interface BaseProp {
14
14
  name: string;
15
15
  }
16
16
 
17
+ export type Link = 'curve' | 'line' | 'step';
18
+
17
19
  export interface ChildrenProps<TData> {
18
20
  ancestors: Array<Node<TData>>;
19
21
  depth: number;
@@ -48,5 +50,6 @@ export interface TreeProps<TData> {
48
50
  ) => string | number | undefined;
49
51
  getStrokeOpacity?: (props: LinkProps<TData>) => string | number | undefined;
50
52
  getStrokeWidth?: (props: LinkProps<TData>) => string | number | undefined;
53
+ type?: Link;
51
54
  };
52
55
  }
@@ -10,6 +10,9 @@ import TimePeriod from '.';
10
10
 
11
11
  const meta: Meta<typeof TimePeriod> = {
12
12
  component: TimePeriod,
13
+ parameters: {
14
+ chromatic: { disableSnapshot: true }
15
+ },
13
16
  tags: ['autodocs']
14
17
  };
15
18
 
@@ -88,27 +91,20 @@ const args = {
88
91
  ]
89
92
  };
90
93
 
91
- const parameters = {
92
- chromatic: { diffThreshold: 0.1 }
93
- };
94
-
95
94
  export const BasicTimePeriod: Story = {
96
95
  ...Template,
97
- argTypes,
98
- parameters
96
+ argTypes
99
97
  };
100
98
 
101
99
  export const WithExtraTimePeriods: Story = {
102
100
  ...Template,
103
101
  argTypes,
104
- args,
105
- parameters
102
+ args
106
103
  };
107
104
 
108
105
  export const WithExternalComponent: Story = {
109
106
  ...TemplateWithExternalComponent,
110
- argTypes,
111
- parameters
107
+ argTypes
112
108
  };
113
109
 
114
110
  export const SimpleTimePeriod: StorySimpleTimePeriod = {
@@ -116,6 +112,5 @@ export const SimpleTimePeriod: StorySimpleTimePeriod = {
116
112
  args: {
117
113
  endDate: dayjs(Date.now()).toDate(),
118
114
  startDate: dayjs(Date.now()).subtract(29, 'day').toDate()
119
- },
120
- parameters
115
+ }
121
116
  };
@@ -1,11 +1,11 @@
1
- import { useState, useEffect } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
 
3
3
  import { makeStyles } from 'tss-react/mui';
4
4
 
5
- import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
6
5
  import ExpandLessIcon from '@mui/icons-material/ExpandLess';
7
- import { Badge, ClickAwayListener } from '@mui/material';
6
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
8
7
  import type { SvgIcon } from '@mui/material';
8
+ import { Badge, ClickAwayListener } from '@mui/material';
9
9
 
10
10
  import useCloseOnLegacyPage from './useCloseOnLegacyPage';
11
11
 
@@ -115,7 +115,6 @@ const TopCounterLayout = ({
115
115
  }: TopCounterLayoutProps): JSX.Element => {
116
116
  const { classes, cx } = useStyles();
117
117
  const [toggled, setToggled] = useState(false);
118
-
119
118
  const subMenuId = title.replace(/[^A-Za-z]/, '-');
120
119
  useCloseOnLegacyPage({ setToggled });
121
120
 
@@ -1,5 +1,6 @@
1
1
  import { Dispatch, SetStateAction, useEffect } from 'react';
2
2
 
3
+ import { isNil } from 'ramda';
3
4
  import { useLocation } from 'react-router-dom';
4
5
 
5
6
  interface Props {
@@ -14,21 +15,23 @@ const useCloseOnLegacyPage = ({ setToggled }: Props): void => {
14
15
  };
15
16
 
16
17
  useEffect(() => {
17
- const iframe = document.getElementById('main-content') as HTMLIFrameElement;
18
+ const iframe = document.getElementById(
19
+ 'main-content'
20
+ ) as HTMLIFrameElement | null;
18
21
 
19
- if (!isLegacyRoute) {
22
+ if (!isLegacyRoute || isNil(iframe)) {
20
23
  return () => undefined;
21
24
  }
22
25
 
23
26
  const closeSubMenuOnLegacyPage = (): void => {
24
- iframe.contentWindow?.document?.addEventListener('click', closeSubMenu);
27
+ iframe?.contentWindow?.document?.addEventListener('click', closeSubMenu);
25
28
  };
26
29
 
27
- iframe.addEventListener('load', closeSubMenuOnLegacyPage);
30
+ iframe?.addEventListener('load', closeSubMenuOnLegacyPage);
28
31
 
29
32
  return () => {
30
- iframe.removeEventListener('load', closeSubMenuOnLegacyPage);
31
- iframe.contentWindow?.document?.removeEventListener(
33
+ iframe?.removeEventListener('load', closeSubMenuOnLegacyPage);
34
+ iframe?.contentWindow?.document?.removeEventListener(
32
35
  'click',
33
36
  closeSubMenu
34
37
  );
@@ -4,7 +4,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
4
 
5
5
  const defaultCacheTime = 5 * 1_000;
6
6
 
7
- const client = new QueryClient({
7
+ export const client = new QueryClient({
8
8
  defaultOptions: {
9
9
  queries: {
10
10
  gcTime: defaultCacheTime,
@@ -0,0 +1,11 @@
1
+ export const errorLog = (text: string): void => {
2
+ const { error: log } = console;
3
+
4
+ log(`API Request: ${text}`);
5
+ };
6
+
7
+ export const warnLog = (text: string): void => {
8
+ const { warn: log } = console;
9
+
10
+ log(`API Request: ${text}`);
11
+ };
@@ -1,6 +1,5 @@
1
1
  import { renderHook, waitFor, RenderHookResult } from '@testing-library/react';
2
2
  import fetchMock from 'jest-fetch-mock';
3
- import anyLogger from 'anylogger';
4
3
 
5
4
  import TestQueryProvider from '../TestQueryProvider';
6
5
 
@@ -77,8 +76,6 @@ describe('useFetchQuery', () => {
77
76
  expect(mockedShowErrorMessage).toHaveBeenCalledWith('custom message');
78
77
  });
79
78
 
80
- expect(anyLogger().error).toHaveBeenCalledWith('custom message');
81
-
82
79
  await waitFor(() => {
83
80
  expect(result.current.error).toStrictEqual({
84
81
  additionalInformation: {
@@ -102,8 +99,6 @@ describe('useFetchQuery', () => {
102
99
  await waitFor(() => {
103
100
  expect(mockedShowErrorMessage).toHaveBeenCalledWith('error');
104
101
  });
105
-
106
- expect(anyLogger().error).toHaveBeenCalledWith('error');
107
102
  });
108
103
 
109
104
  it('shows a default failure message via the Snackbar as fallback', async () => {
@@ -1,6 +1,5 @@
1
1
  import { useEffect, useMemo, useRef } from 'react';
2
2
 
3
- import 'ulog';
4
3
  import {
5
4
  QueryKey,
6
5
  QueryObserverBaseResult,
@@ -9,12 +8,12 @@ import {
9
8
  UseQueryOptions
10
9
  } from '@tanstack/react-query';
11
10
  import { JsonDecoder } from 'ts.data.json';
12
- import anylogger from 'anylogger';
13
11
  import { has, includes, isNil, not, omit } from 'ramda';
14
12
 
15
13
  import { CatchErrorProps, customFetch, ResponseError } from '../customFetch';
16
14
  import useSnackbar from '../../Snackbar/useSnackbar';
17
15
  import { useDeepCompare } from '../../utils';
16
+ import { errorLog } from '../logger';
18
17
 
19
18
  export interface UseFetchQueryProps<T> {
20
19
  baseEndpoint?: string;
@@ -48,8 +47,6 @@ export interface PrefetchEndpointParams {
48
47
  page: number;
49
48
  }
50
49
 
51
- const log = anylogger('API Request');
52
-
53
50
  const useFetchQuery = <T extends object>({
54
51
  getEndpoint,
55
52
  getQueryKey,
@@ -87,7 +84,7 @@ const useFetchQuery = <T extends object>({
87
84
  const manageError = (): void => {
88
85
  const data = queryData.data as ResponseError | undefined;
89
86
  if (data?.isError) {
90
- log.error(data.message);
87
+ errorLog(data.message);
91
88
  const hasACorrespondingHttpCode = includes(
92
89
  data?.statusCode || 0,
93
90
  httpCodesBypassErrorSnackbar
@@ -24,6 +24,7 @@ interface CustomTimePeriod {
24
24
  interface UseMetricsQueryProps {
25
25
  baseEndpoint: string;
26
26
  bypassMetricsExclusion?: boolean;
27
+ bypassQueryParams?: boolean;
27
28
  includeAllResources?: boolean;
28
29
  metrics: Array<Metric>;
29
30
  refreshCount?: number;
@@ -90,7 +91,8 @@ const useGraphQuery = ({
90
91
  timePeriodType: 1
91
92
  },
92
93
  refreshInterval = false,
93
- refreshCount
94
+ refreshCount,
95
+ bypassQueryParams = false
94
96
  }: UseMetricsQueryProps): UseMetricsQueryState => {
95
97
  const timePeriodToUse = equals(timePeriod?.timePeriodType, -1)
96
98
  ? {
@@ -114,6 +116,10 @@ const useGraphQuery = ({
114
116
  isLoading
115
117
  } = useFetchQuery<PerformanceGraphData>({
116
118
  getEndpoint: () => {
119
+ if (bypassQueryParams) {
120
+ return baseEndpoint;
121
+ }
122
+
117
123
  const endpoint = buildListingEndpoint({
118
124
  baseEndpoint,
119
125
  parameters: {
@@ -1,4 +1,3 @@
1
- import 'ulog';
2
1
  import { useEffect } from 'react';
3
2
 
4
3
  import {
@@ -7,12 +6,12 @@ import {
7
6
  UseMutationResult
8
7
  } from '@tanstack/react-query';
9
8
  import { JsonDecoder } from 'ts.data.json';
10
- import anylogger from 'anylogger';
11
9
  import { includes, omit } from 'ramda';
12
10
 
13
11
  import { CatchErrorProps, customFetch, ResponseError } from '../customFetch';
14
12
  import useSnackbar from '../../Snackbar/useSnackbar';
15
13
  import { useDeepCompare } from '../../utils';
14
+ import { errorLog } from '../logger';
16
15
 
17
16
  export enum Method {
18
17
  DELETE = 'DELETE',
@@ -52,8 +51,6 @@ export type UseMutationQueryProps<T, TMeta> = {
52
51
  'mutationFn' | 'onError' | 'onMutate' | 'onSuccess' | 'mutateAsync' | 'mutate'
53
52
  >;
54
53
 
55
- const log = anylogger('API Request');
56
-
57
54
  export type UseMutationQueryState<T, TMeta> = Omit<
58
55
  UseMutationResult<T | ResponseError>,
59
56
  'isError' | 'mutate' | 'mutateAsync'
@@ -127,7 +124,7 @@ const useMutationQuery = <T extends object, TMeta>({
127
124
  const manageError = (): void => {
128
125
  const data = queryData.data as ResponseError | undefined;
129
126
  if (data?.isError) {
130
- log.error(data.message);
127
+ errorLog(data.message);
131
128
  const hasACorrespondingHttpCode = includes(
132
129
  data?.statusCode || 0,
133
130
  httpCodesBypassErrorSnackbar
@@ -1,5 +1,4 @@
1
1
  import axios from 'axios';
2
- import anyLogger from 'anylogger';
3
2
  import { RenderHookResult, renderHook, act } from '@testing-library/react';
4
3
 
5
4
  import useRequest, { RequestResult, RequestParams } from '.';
@@ -77,8 +76,6 @@ describe(useRequest, () => {
77
76
  });
78
77
  });
79
78
 
80
- expect(anyLogger().error).toHaveBeenCalledWith(response);
81
-
82
79
  expect(mockedShowErrorMessage).toHaveBeenCalledWith('failure');
83
80
  });
84
81
 
@@ -1,15 +1,12 @@
1
1
  import { useState, useEffect } from 'react';
2
2
 
3
- import 'ulog';
4
3
  import axios from 'axios';
5
4
  import { pathOr, defaultTo, path, includes, or } from 'ramda';
6
- import anylogger from 'anylogger';
7
5
  import { JsonDecoder } from 'ts.data.json';
8
6
 
9
7
  import useCancelTokenSource from '../useCancelTokenSource';
10
8
  import useSnackbar from '../../Snackbar/useSnackbar';
11
-
12
- const log = anylogger('API Request');
9
+ import { errorLog, warnLog } from '../logger';
13
10
 
14
11
  export interface RequestParams<TResult> {
15
12
  decoder?: JsonDecoder.Decoder<TResult>;
@@ -41,7 +38,7 @@ const useRequest = <TResult>({
41
38
  }, []);
42
39
 
43
40
  const showRequestErrorMessage = (error): void => {
44
- log.error(error);
41
+ errorLog(error.message);
45
42
 
46
43
  const message = or(
47
44
  pathOr(undefined, ['response', 'data', 'message'], error),
@@ -68,7 +65,7 @@ const useRequest = <TResult>({
68
65
  .catch((error) => {
69
66
  setSending(false);
70
67
  if (axios.isCancel(error)) {
71
- log.warn(error);
68
+ warnLog(error);
72
69
 
73
70
  throw error;
74
71
  }
@@ -15,11 +15,11 @@ import {
15
15
 
16
16
  const initialize = ({
17
17
  initialValues = simpleAccessRights,
18
- loading = false,
19
- link = 'link'
18
+ loading = false
20
19
  }): unknown => {
21
20
  const cancel = cy.stub();
22
21
  const save = cy.stub();
22
+ const change = cy.stub();
23
23
 
24
24
  cy.interceptAPIRequest({
25
25
  alias: 'getContacts',
@@ -47,10 +47,10 @@ const initialize = ({
47
47
  }}
48
48
  initialValues={initialValues}
49
49
  labels={labels}
50
- link={link}
51
50
  loading={loading}
52
51
  roles={roles}
53
52
  submit={save}
53
+ onChange={change}
54
54
  />
55
55
  </Provider>
56
56
  </TestQueryProvider>
@@ -60,6 +60,7 @@ const initialize = ({
60
60
 
61
61
  return {
62
62
  cancel,
63
+ change,
63
64
  save
64
65
  };
65
66
  };
@@ -74,21 +75,12 @@ describe('Access rights', () => {
74
75
  cy.findByLabelText('Add a contact').should('be.visible');
75
76
  cy.findByTestId('add_role').should('be.disabled');
76
77
  cy.findByTestId('add').should('be.disabled');
77
- cy.findByLabelText('Copy link').should('be.visible');
78
78
  cy.findByLabelText('Cancel').should('be.visible');
79
79
  cy.findByLabelText('Save').should('be.visible');
80
80
 
81
81
  cy.makeSnapshot();
82
82
  });
83
83
 
84
- it('displays the access rights without link', () => {
85
- initialize({ link: null });
86
-
87
- cy.findByLabelText('Copy link').should('not.exist');
88
-
89
- cy.makeSnapshot();
90
- });
91
-
92
84
  it('displays the access rights with an empty list', () => {
93
85
  initialize({ initialValues: emptyAccessRights });
94
86
 
@@ -97,7 +89,7 @@ describe('Access rights', () => {
97
89
  cy.makeSnapshot();
98
90
  });
99
91
 
100
- it('displays the access rights with an empty list', () => {
92
+ it('displays the access rights list', () => {
101
93
  initialize({});
102
94
 
103
95
  simpleAccessRights.forEach(({ name, email, isContactGroup, role }) => {
@@ -370,4 +362,26 @@ describe('Access rights', () => {
370
362
 
371
363
  cy.makeSnapshot();
372
364
  });
365
+
366
+ it('calls the change function when the corresponding prop is set and the form is updated', () => {
367
+ const { change } = initialize({});
368
+
369
+ cy.contains(labels.add.contact).click();
370
+ cy.findByLabelText(labels.add.autocompleteContact).click();
371
+
372
+ cy.waitForRequest('@getContacts');
373
+
374
+ cy.contains('Entity 10').click();
375
+
376
+ cy.findByTestId('add').click();
377
+
378
+ cy.contains('Entity 10').should('be.visible');
379
+
380
+ cy.findByTestId('role-Entity 10').should('have.value', 'viewer');
381
+ cy.contains(labels.list.added)
382
+ .should('be.visible')
383
+ .then(() => {
384
+ expect(change).to.have.callCount(2);
385
+ });
386
+ });
373
387
  });
@@ -47,7 +47,6 @@ export const Default: Story = {
47
47
  },
48
48
  initialValues: defaultAccessRights,
49
49
  labels,
50
- link: 'link',
51
50
  roles,
52
51
  submit: () => undefined
53
52
  },
@@ -63,7 +62,6 @@ export const AccessRightsWithStates: Story = {
63
62
  },
64
63
  initialValues: accessRightsWithStates,
65
64
  labels,
66
- link: 'link',
67
65
  roles,
68
66
  submit: () => undefined
69
67
  },
@@ -79,22 +77,6 @@ export const withEmptyState: Story = {
79
77
  },
80
78
  initialValues: emptyAccessRights,
81
79
  labels,
82
- link: 'link',
83
- roles,
84
- submit: () => undefined
85
- },
86
- render: Template
87
- };
88
-
89
- export const withoutLink: Story = {
90
- args: {
91
- cancel: () => undefined,
92
- endpoints: {
93
- contact: '/contact',
94
- contactGroup: '/contactGroup'
95
- },
96
- initialValues: defaultAccessRights,
97
- labels,
98
80
  roles,
99
81
  submit: () => undefined
100
82
  },
@@ -110,7 +92,6 @@ export const loading: Story = {
110
92
  },
111
93
  initialValues: emptyAccessRights,
112
94
  labels,
113
- link: 'link',
114
95
  loading: true,
115
96
  roles,
116
97
  submit: () => undefined
@@ -5,6 +5,6 @@ export const useAccessRightsStyles = makeStyles()((theme) => ({
5
5
  display: 'flex',
6
6
  flexDirection: 'column',
7
7
  gap: theme.spacing(3),
8
- maxWidth: '520px'
8
+ width: '100%'
9
9
  }
10
10
  }));
@@ -8,16 +8,17 @@ import Provider from './Provider';
8
8
  import ShareInput from './ShareInput/ShareInput';
9
9
  import Stats from './Stats/Stats';
10
10
  import { AccessRightInitialValues, Endpoints, Labels } from './models';
11
+ import { useAccessRightsChange } from './useAccessRightsChange';
11
12
  import { useAccessRightsInitValues } from './useAccessRightsInitValues';
12
13
 
13
14
  interface Props {
14
- cancel: ({ dirty, values }) => void;
15
+ cancel?: ({ dirty, values }) => void;
15
16
  endpoints: Endpoints;
16
17
  initialValues: Array<AccessRightInitialValues>;
17
18
  isSubmitting?: boolean;
18
19
  labels: Labels;
19
- link?: string;
20
20
  loading?: boolean;
21
+ onChange?: (values: Array<AccessRightInitialValues>) => void;
21
22
  roles: Array<SelectEntry>;
22
23
  submit: (values: Array<AccessRightInitialValues>) => Promise<void>;
23
24
  }
@@ -28,13 +29,14 @@ export const AccessRights = ({
28
29
  endpoints,
29
30
  submit,
30
31
  cancel,
31
- link,
32
32
  loading,
33
33
  labels,
34
- isSubmitting
34
+ isSubmitting,
35
+ onChange
35
36
  }: Props): JSX.Element => {
36
37
  const { classes } = useAccessRightsStyles();
37
38
  const clear = useAccessRightsInitValues({ initialValues });
39
+ useAccessRightsChange(onChange);
38
40
 
39
41
  return (
40
42
  <div className={classes.container}>
@@ -46,7 +48,6 @@ export const AccessRights = ({
46
48
  clear={clear}
47
49
  isSubmitting={isSubmitting}
48
50
  labels={labels.actions}
49
- link={link}
50
51
  submit={submit}
51
52
  />
52
53
  </div>
@@ -1,14 +1,10 @@
1
1
  import { makeStyles } from 'tss-react/mui';
2
2
 
3
3
  export const useActionsStyles = makeStyles()((theme) => ({
4
- actions: {
5
- backgroundColor: theme.palette.background.paper,
6
- display: 'flex',
7
- justifyContent: 'space-between'
8
- },
9
4
  cancelAndSave: {
10
5
  display: 'flex',
11
- flex: 'row',
12
- gap: theme.spacing(2)
6
+ flexDirection: 'row',
7
+ gap: theme.spacing(2),
8
+ justifyContent: 'flex-end'
13
9
  }
14
10
  }));
@@ -1,6 +1,5 @@
1
1
  import { useTranslation } from 'react-i18next';
2
2
 
3
- import LinkIcon from '@mui/icons-material/Link';
4
3
  import { CircularProgress } from '@mui/material';
5
4
 
6
5
  import { Button } from '../../..';
@@ -10,11 +9,10 @@ import { useActions } from './useActions';
10
9
  import { useActionsStyles } from './Actions.styles';
11
10
 
12
11
  interface Props {
13
- cancel: ({ dirty, values }) => void;
12
+ cancel?: ({ dirty, values }) => void;
14
13
  clear: () => void;
15
14
  isSubmitting?: boolean;
16
15
  labels: Labels['actions'];
17
- link?: string;
18
16
  submit: (values: Array<AccessRightInitialValues>) => Promise<void>;
19
17
  }
20
18
 
@@ -22,17 +20,15 @@ const Actions = ({
22
20
  labels,
23
21
  cancel,
24
22
  submit,
25
- link,
26
23
  isSubmitting,
27
24
  clear
28
25
  }: Props): JSX.Element => {
29
26
  const { t } = useTranslation();
30
27
  const { classes } = useActionsStyles();
31
28
 
32
- const { dirty, copyLink, save, formattedValues } = useActions({
29
+ const { dirty, save, formattedValues } = useActions({
33
30
  clear,
34
31
  labels,
35
- link,
36
32
  submit
37
33
  });
38
34
 
@@ -41,21 +37,8 @@ const Actions = ({
41
37
  };
42
38
 
43
39
  return (
44
- <div className={classes.actions}>
45
- {link ? (
46
- <Button
47
- aria-label={t(labels.copyLink)}
48
- icon={<LinkIcon />}
49
- iconVariant="start"
50
- variant="ghost"
51
- onClick={copyLink}
52
- >
53
- {t(labels.copyLink)}
54
- </Button>
55
- ) : (
56
- <div />
57
- )}
58
- <div className={classes.cancelAndSave}>
40
+ <div className={classes.cancelAndSave}>
41
+ {cancel && (
59
42
  <Button
60
43
  aria-label={t(labels.cancel)}
61
44
  variant="secondary"
@@ -63,17 +46,17 @@ const Actions = ({
63
46
  >
64
47
  {t(labels.cancel)}
65
48
  </Button>
66
- <Button
67
- aria-label={t(labels.save)}
68
- disabled={isSubmitting || !dirty}
69
- icon={isSubmitting ? <CircularProgress size={24} /> : null}
70
- iconVariant={isSubmitting ? 'start' : 'none'}
71
- variant="primary"
72
- onClick={save}
73
- >
74
- {t(labels.save)}
75
- </Button>
76
- </div>
49
+ )}
50
+ <Button
51
+ aria-label={t(labels.save)}
52
+ disabled={isSubmitting || !dirty}
53
+ icon={isSubmitting ? <CircularProgress size={24} /> : null}
54
+ iconVariant={isSubmitting ? 'start' : 'none'}
55
+ variant="primary"
56
+ onClick={save}
57
+ >
58
+ {t(labels.save)}
59
+ </Button>
77
60
  </div>
78
61
  );
79
62
  };