@centreon/ui 24.5.8 → 24.5.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.
- package/package.json +4 -8
- package/public/mockServiceWorker.js +100 -81
- package/src/ActionsList/index.stories.tsx +1 -7
- package/src/Dashboard/Dashboard.styles.ts +2 -3
- package/src/Dashboard/Item.tsx +5 -39
- package/src/Dashboard/Layout.tsx +2 -4
- package/src/Dashboard/utils.ts +1 -1
- package/src/Graph/BarStack/BarStack.stories.tsx +6 -8
- package/src/Graph/BarStack/ResponsiveBarStack.tsx +3 -3
- package/src/Graph/HeatMap/HeatMap.stories.tsx +0 -20
- package/src/Graph/LineChart/BasicComponents/Lines/RegularLines/index.tsx +8 -12
- package/src/Graph/LineChart/BasicComponents/Lines/StackedLines/index.tsx +8 -8
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/BasicThreshold.tsx +2 -1
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx +2 -1
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/ThresholdWithVariation.tsx +2 -1
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +2 -1
- package/src/Graph/LineChart/BasicComponents/Lines/index.tsx +2 -1
- package/src/Graph/LineChart/BasicComponents/Lines/models.ts +3 -0
- package/src/Graph/LineChart/Legend/LegendHeader.tsx +1 -4
- package/src/Graph/LineChart/LineChart.cypress.spec.tsx +0 -53
- package/src/Graph/LineChart/LineChart.tsx +2 -1
- package/src/Graph/LineChart/common/index.ts +1 -15
- package/src/Graph/LineChart/index.stories.tsx +3 -15
- package/src/Graph/LineChart/index.tsx +4 -2
- package/src/Graph/LineChart/useLineChartData.ts +18 -57
- package/src/Graph/PieChart/PieChart.stories.tsx +15 -11
- package/src/Graph/PieChart/ResponsivePie.tsx +1 -1
- package/src/Graph/Tree/DescendantNodes.tsx +0 -1
- package/src/Graph/Tree/Links.tsx +2 -15
- package/src/Graph/Tree/Tree.cypress.spec.tsx +0 -24
- package/src/Graph/Tree/Tree.stories.tsx +1 -17
- package/src/Graph/Tree/models.ts +0 -3
- package/src/Graph/common/utils.ts +1 -49
- package/src/Listing/Cell/index.tsx +23 -17
- package/src/TimePeriods/index.stories.tsx +12 -7
- package/src/TopCounterElements/TopCounterLayout.tsx +4 -3
- package/src/api/QueryProvider.tsx +1 -1
- package/src/api/useFetchQuery/index.test.ts +5 -0
- package/src/api/useFetchQuery/index.ts +7 -12
- package/src/api/useGraphQuery/index.ts +2 -9
- package/src/api/useMutationQuery/index.ts +5 -2
- package/src/api/useRequest/index.test.ts +3 -0
- package/src/api/useRequest/index.ts +6 -3
- package/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx +13 -27
- package/src/components/Form/AccessRights/AccessRights.stories.tsx +19 -0
- package/src/components/Form/AccessRights/AccessRights.styles.ts +1 -1
- package/src/components/Form/AccessRights/AccessRights.tsx +5 -6
- package/src/components/Form/AccessRights/Actions/Actions.styles.ts +7 -3
- package/src/components/Form/AccessRights/Actions/Actions.tsx +32 -15
- package/src/components/Form/AccessRights/Actions/useActions.ts +37 -4
- package/src/components/Form/AccessRights/ShareInput/ShareInput.tsx +0 -1
- package/src/components/Form/AccessRights/models.ts +3 -0
- package/src/components/Form/AccessRights/storiesData.ts +3 -0
- package/src/components/Form/Dashboard/DashboardForm.stories.ts +39 -0
- package/src/components/Form/Dashboard/translatedLabels.ts +1 -0
- package/src/components/List/Item/ListItem.styles.ts +2 -2
- package/src/components/Modal/Modal.styles.ts +5 -5
- package/src/components/Zoom/Minimap.tsx +2 -4
- package/src/components/Zoom/Zoom.cypress.spec.tsx +13 -13
- package/src/components/Zoom/Zoom.tsx +1 -4
- package/src/components/Zoom/ZoomContent.tsx +2 -5
- package/src/components/index.ts +0 -1
- package/src/index.ts +1 -1
- package/src/utils/index.ts +0 -1
- package/src/utils/usePluralizedTranslation.ts +3 -20
- package/src/Dashboard/Dashboard.cypress.spec.tsx +0 -68
- package/src/Graph/LineChart/mockedData/curvesWithSameColor.json +0 -252
- package/src/api/logger.ts +0 -11
- package/src/components/Form/AccessRights/useAccessRightsChange.ts +0 -30
- package/src/components/Form/AccessRights/utils.ts +0 -18
- package/src/components/Tabs/Tab.styles.ts +0 -25
- package/src/components/Tabs/TabPanel.tsx +0 -22
- package/src/components/Tabs/Tabs.cypress.spec.tsx +0 -70
- package/src/components/Tabs/Tabs.stories.tsx +0 -55
- package/src/components/Tabs/Tabs.tsx +0 -55
- package/src/components/Tabs/index.ts +0 -6
- package/src/utils/resourcesStatusURL.ts +0 -166
- package/src/utils/usePluralizedTranslation.test.ts +0 -159
|
@@ -95,6 +95,9 @@ const useStyles = makeStyles<StylesProps>()(
|
|
|
95
95
|
caretMore: {
|
|
96
96
|
transform: 'rotate3d(0,0,1,180deg)'
|
|
97
97
|
},
|
|
98
|
+
fakeCaret: {
|
|
99
|
+
marginLeft: theme.spacing(3)
|
|
100
|
+
},
|
|
98
101
|
root: {
|
|
99
102
|
alignItems: 'center',
|
|
100
103
|
backgroundColor: getBackgroundColor({
|
|
@@ -195,23 +198,26 @@ const Cell = ({
|
|
|
195
198
|
props
|
|
196
199
|
)}
|
|
197
200
|
>
|
|
198
|
-
{displaySubItemsCaret &&
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
201
|
+
{displaySubItemsCaret &&
|
|
202
|
+
(hasSubItems ? (
|
|
203
|
+
<IconButton
|
|
204
|
+
ariaLabel={`${isSubItemsExpanded ? labelCollapse : labelExpand} ${
|
|
205
|
+
props.row.id
|
|
206
|
+
}`}
|
|
207
|
+
size="small"
|
|
208
|
+
onClick={click}
|
|
209
|
+
>
|
|
210
|
+
<ExpandMoreIcon
|
|
211
|
+
className={cx(
|
|
212
|
+
classes.caret,
|
|
213
|
+
isSubItemsExpanded ? classes.caretMore : classes.caretLess
|
|
214
|
+
)}
|
|
215
|
+
fontSize="small"
|
|
216
|
+
/>
|
|
217
|
+
</IconButton>
|
|
218
|
+
) : (
|
|
219
|
+
<div className={classes.fakeCaret} />
|
|
220
|
+
))}
|
|
215
221
|
{children}
|
|
216
222
|
</TableCell>
|
|
217
223
|
);
|
|
@@ -10,9 +10,6 @@ import TimePeriod from '.';
|
|
|
10
10
|
|
|
11
11
|
const meta: Meta<typeof TimePeriod> = {
|
|
12
12
|
component: TimePeriod,
|
|
13
|
-
parameters: {
|
|
14
|
-
chromatic: { disableSnapshot: true }
|
|
15
|
-
},
|
|
16
13
|
tags: ['autodocs']
|
|
17
14
|
};
|
|
18
15
|
|
|
@@ -91,20 +88,27 @@ const args = {
|
|
|
91
88
|
]
|
|
92
89
|
};
|
|
93
90
|
|
|
91
|
+
const parameters = {
|
|
92
|
+
chromatic: { diffThreshold: 0.1 }
|
|
93
|
+
};
|
|
94
|
+
|
|
94
95
|
export const BasicTimePeriod: Story = {
|
|
95
96
|
...Template,
|
|
96
|
-
argTypes
|
|
97
|
+
argTypes,
|
|
98
|
+
parameters
|
|
97
99
|
};
|
|
98
100
|
|
|
99
101
|
export const WithExtraTimePeriods: Story = {
|
|
100
102
|
...Template,
|
|
101
103
|
argTypes,
|
|
102
|
-
args
|
|
104
|
+
args,
|
|
105
|
+
parameters
|
|
103
106
|
};
|
|
104
107
|
|
|
105
108
|
export const WithExternalComponent: Story = {
|
|
106
109
|
...TemplateWithExternalComponent,
|
|
107
|
-
argTypes
|
|
110
|
+
argTypes,
|
|
111
|
+
parameters
|
|
108
112
|
};
|
|
109
113
|
|
|
110
114
|
export const SimpleTimePeriod: StorySimpleTimePeriod = {
|
|
@@ -112,5 +116,6 @@ export const SimpleTimePeriod: StorySimpleTimePeriod = {
|
|
|
112
116
|
args: {
|
|
113
117
|
endDate: dayjs(Date.now()).toDate(),
|
|
114
118
|
startDate: dayjs(Date.now()).subtract(29, 'day').toDate()
|
|
115
|
-
}
|
|
119
|
+
},
|
|
120
|
+
parameters
|
|
116
121
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
2
|
|
|
3
3
|
import { makeStyles } from 'tss-react/mui';
|
|
4
4
|
|
|
5
|
-
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
|
6
5
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
7
|
-
import
|
|
6
|
+
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
|
8
7
|
import { Badge, ClickAwayListener } from '@mui/material';
|
|
8
|
+
import type { SvgIcon } from '@mui/material';
|
|
9
9
|
|
|
10
10
|
import useCloseOnLegacyPage from './useCloseOnLegacyPage';
|
|
11
11
|
|
|
@@ -115,6 +115,7 @@ const TopCounterLayout = ({
|
|
|
115
115
|
}: TopCounterLayoutProps): JSX.Element => {
|
|
116
116
|
const { classes, cx } = useStyles();
|
|
117
117
|
const [toggled, setToggled] = useState(false);
|
|
118
|
+
|
|
118
119
|
const subMenuId = title.replace(/[^A-Za-z]/, '-');
|
|
119
120
|
useCloseOnLegacyPage({ setToggled });
|
|
120
121
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { renderHook, waitFor, RenderHookResult } from '@testing-library/react';
|
|
2
2
|
import fetchMock from 'jest-fetch-mock';
|
|
3
|
+
import anyLogger from 'anylogger';
|
|
3
4
|
|
|
4
5
|
import TestQueryProvider from '../TestQueryProvider';
|
|
5
6
|
|
|
@@ -76,6 +77,8 @@ describe('useFetchQuery', () => {
|
|
|
76
77
|
expect(mockedShowErrorMessage).toHaveBeenCalledWith('custom message');
|
|
77
78
|
});
|
|
78
79
|
|
|
80
|
+
expect(anyLogger().error).toHaveBeenCalledWith('custom message');
|
|
81
|
+
|
|
79
82
|
await waitFor(() => {
|
|
80
83
|
expect(result.current.error).toStrictEqual({
|
|
81
84
|
additionalInformation: {
|
|
@@ -99,6 +102,8 @@ describe('useFetchQuery', () => {
|
|
|
99
102
|
await waitFor(() => {
|
|
100
103
|
expect(mockedShowErrorMessage).toHaveBeenCalledWith('error');
|
|
101
104
|
});
|
|
105
|
+
|
|
106
|
+
expect(anyLogger().error).toHaveBeenCalledWith('error');
|
|
102
107
|
});
|
|
103
108
|
|
|
104
109
|
it('shows a default failure message via the Snackbar as fallback', async () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
|
|
3
|
+
import 'ulog';
|
|
3
4
|
import {
|
|
4
5
|
QueryKey,
|
|
5
6
|
QueryObserverBaseResult,
|
|
@@ -8,12 +9,12 @@ import {
|
|
|
8
9
|
UseQueryOptions
|
|
9
10
|
} from '@tanstack/react-query';
|
|
10
11
|
import { JsonDecoder } from 'ts.data.json';
|
|
11
|
-
import
|
|
12
|
+
import anylogger from 'anylogger';
|
|
13
|
+
import { has, includes, isNil, not, omit } from 'ramda';
|
|
12
14
|
|
|
13
15
|
import { CatchErrorProps, customFetch, ResponseError } from '../customFetch';
|
|
14
16
|
import useSnackbar from '../../Snackbar/useSnackbar';
|
|
15
17
|
import { useDeepCompare } from '../../utils';
|
|
16
|
-
import { errorLog } from '../logger';
|
|
17
18
|
|
|
18
19
|
export interface UseFetchQueryProps<T> {
|
|
19
20
|
baseEndpoint?: string;
|
|
@@ -32,7 +33,6 @@ export interface UseFetchQueryProps<T> {
|
|
|
32
33
|
UseQueryOptions<T | ResponseError, Error, T | ResponseError, QueryKey>,
|
|
33
34
|
'queryKey' | 'queryFn'
|
|
34
35
|
>;
|
|
35
|
-
useLongCache?: boolean;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export type UseFetchQueryState<T> = {
|
|
@@ -48,6 +48,8 @@ export interface PrefetchEndpointParams {
|
|
|
48
48
|
page: number;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
const log = anylogger('API Request');
|
|
52
|
+
|
|
51
53
|
const useFetchQuery = <T extends object>({
|
|
52
54
|
getEndpoint,
|
|
53
55
|
getQueryKey,
|
|
@@ -59,18 +61,12 @@ const useFetchQuery = <T extends object>({
|
|
|
59
61
|
queryOptions,
|
|
60
62
|
httpCodesBypassErrorSnackbar = [],
|
|
61
63
|
baseEndpoint,
|
|
62
|
-
doNotCancelCallsOnUnmount = false
|
|
63
|
-
useLongCache
|
|
64
|
+
doNotCancelCallsOnUnmount = false
|
|
64
65
|
}: UseFetchQueryProps<T>): UseFetchQueryState<T> => {
|
|
65
66
|
const dataRef = useRef<T | undefined>(undefined);
|
|
66
67
|
|
|
67
68
|
const { showErrorMessage } = useSnackbar();
|
|
68
69
|
|
|
69
|
-
const isCypressTest = equals(window.Cypress?.testingType, 'component');
|
|
70
|
-
|
|
71
|
-
const cacheOptions =
|
|
72
|
-
!isCypressTest && useLongCache ? { gcTime: 60 * 1000 } : {};
|
|
73
|
-
|
|
74
70
|
const queryData = useQuery<T | ResponseError, Error>({
|
|
75
71
|
queryFn: ({ signal }): Promise<T | ResponseError> =>
|
|
76
72
|
customFetch<T>({
|
|
@@ -83,7 +79,6 @@ const useFetchQuery = <T extends object>({
|
|
|
83
79
|
signal
|
|
84
80
|
}),
|
|
85
81
|
queryKey: getQueryKey(),
|
|
86
|
-
...cacheOptions,
|
|
87
82
|
...queryOptions
|
|
88
83
|
});
|
|
89
84
|
|
|
@@ -92,7 +87,7 @@ const useFetchQuery = <T extends object>({
|
|
|
92
87
|
const manageError = (): void => {
|
|
93
88
|
const data = queryData.data as ResponseError | undefined;
|
|
94
89
|
if (data?.isError) {
|
|
95
|
-
|
|
90
|
+
log.error(data.message);
|
|
96
91
|
const hasACorrespondingHttpCode = includes(
|
|
97
92
|
data?.statusCode || 0,
|
|
98
93
|
httpCodesBypassErrorSnackbar
|
|
@@ -24,7 +24,6 @@ interface CustomTimePeriod {
|
|
|
24
24
|
interface UseMetricsQueryProps {
|
|
25
25
|
baseEndpoint: string;
|
|
26
26
|
bypassMetricsExclusion?: boolean;
|
|
27
|
-
bypassQueryParams?: boolean;
|
|
28
27
|
includeAllResources?: boolean;
|
|
29
28
|
metrics: Array<Metric>;
|
|
30
29
|
refreshCount?: number;
|
|
@@ -91,8 +90,7 @@ const useGraphQuery = ({
|
|
|
91
90
|
timePeriodType: 1
|
|
92
91
|
},
|
|
93
92
|
refreshInterval = false,
|
|
94
|
-
refreshCount
|
|
95
|
-
bypassQueryParams = false
|
|
93
|
+
refreshCount
|
|
96
94
|
}: UseMetricsQueryProps): UseMetricsQueryState => {
|
|
97
95
|
const timePeriodToUse = equals(timePeriod?.timePeriodType, -1)
|
|
98
96
|
? {
|
|
@@ -116,10 +114,6 @@ const useGraphQuery = ({
|
|
|
116
114
|
isLoading
|
|
117
115
|
} = useFetchQuery<PerformanceGraphData>({
|
|
118
116
|
getEndpoint: () => {
|
|
119
|
-
if (bypassQueryParams) {
|
|
120
|
-
return baseEndpoint;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
117
|
const endpoint = buildListingEndpoint({
|
|
124
118
|
baseEndpoint,
|
|
125
119
|
parameters: {
|
|
@@ -149,8 +143,7 @@ const useGraphQuery = ({
|
|
|
149
143
|
enabled: areResourcesFullfilled(resources) && !isEmpty(definedMetrics),
|
|
150
144
|
refetchInterval: refreshInterval,
|
|
151
145
|
suspense: false
|
|
152
|
-
}
|
|
153
|
-
useLongCache: true
|
|
146
|
+
}
|
|
154
147
|
});
|
|
155
148
|
|
|
156
149
|
const data = useRef<PerformanceGraphData | undefined>(undefined);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import 'ulog';
|
|
1
2
|
import { useEffect } from 'react';
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -6,12 +7,12 @@ import {
|
|
|
6
7
|
UseMutationResult
|
|
7
8
|
} from '@tanstack/react-query';
|
|
8
9
|
import { JsonDecoder } from 'ts.data.json';
|
|
10
|
+
import anylogger from 'anylogger';
|
|
9
11
|
import { includes, omit } from 'ramda';
|
|
10
12
|
|
|
11
13
|
import { CatchErrorProps, customFetch, ResponseError } from '../customFetch';
|
|
12
14
|
import useSnackbar from '../../Snackbar/useSnackbar';
|
|
13
15
|
import { useDeepCompare } from '../../utils';
|
|
14
|
-
import { errorLog } from '../logger';
|
|
15
16
|
|
|
16
17
|
export enum Method {
|
|
17
18
|
DELETE = 'DELETE',
|
|
@@ -51,6 +52,8 @@ export type UseMutationQueryProps<T, TMeta> = {
|
|
|
51
52
|
'mutationFn' | 'onError' | 'onMutate' | 'onSuccess' | 'mutateAsync' | 'mutate'
|
|
52
53
|
>;
|
|
53
54
|
|
|
55
|
+
const log = anylogger('API Request');
|
|
56
|
+
|
|
54
57
|
export type UseMutationQueryState<T, TMeta> = Omit<
|
|
55
58
|
UseMutationResult<T | ResponseError>,
|
|
56
59
|
'isError' | 'mutate' | 'mutateAsync'
|
|
@@ -124,7 +127,7 @@ const useMutationQuery = <T extends object, TMeta>({
|
|
|
124
127
|
const manageError = (): void => {
|
|
125
128
|
const data = queryData.data as ResponseError | undefined;
|
|
126
129
|
if (data?.isError) {
|
|
127
|
-
|
|
130
|
+
log.error(data.message);
|
|
128
131
|
const hasACorrespondingHttpCode = includes(
|
|
129
132
|
data?.statusCode || 0,
|
|
130
133
|
httpCodesBypassErrorSnackbar
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
+
import anyLogger from 'anylogger';
|
|
2
3
|
import { RenderHookResult, renderHook, act } from '@testing-library/react';
|
|
3
4
|
|
|
4
5
|
import useRequest, { RequestResult, RequestParams } from '.';
|
|
@@ -76,6 +77,8 @@ describe(useRequest, () => {
|
|
|
76
77
|
});
|
|
77
78
|
});
|
|
78
79
|
|
|
80
|
+
expect(anyLogger().error).toHaveBeenCalledWith(response);
|
|
81
|
+
|
|
79
82
|
expect(mockedShowErrorMessage).toHaveBeenCalledWith('failure');
|
|
80
83
|
});
|
|
81
84
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
+
import 'ulog';
|
|
3
4
|
import axios from 'axios';
|
|
4
5
|
import { pathOr, defaultTo, path, includes, or } from 'ramda';
|
|
6
|
+
import anylogger from 'anylogger';
|
|
5
7
|
import { JsonDecoder } from 'ts.data.json';
|
|
6
8
|
|
|
7
9
|
import useCancelTokenSource from '../useCancelTokenSource';
|
|
8
10
|
import useSnackbar from '../../Snackbar/useSnackbar';
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
const log = anylogger('API Request');
|
|
10
13
|
|
|
11
14
|
export interface RequestParams<TResult> {
|
|
12
15
|
decoder?: JsonDecoder.Decoder<TResult>;
|
|
@@ -38,7 +41,7 @@ const useRequest = <TResult>({
|
|
|
38
41
|
}, []);
|
|
39
42
|
|
|
40
43
|
const showRequestErrorMessage = (error): void => {
|
|
41
|
-
|
|
44
|
+
log.error(error);
|
|
42
45
|
|
|
43
46
|
const message = or(
|
|
44
47
|
pathOr(undefined, ['response', 'data', 'message'], error),
|
|
@@ -65,7 +68,7 @@ const useRequest = <TResult>({
|
|
|
65
68
|
.catch((error) => {
|
|
66
69
|
setSending(false);
|
|
67
70
|
if (axios.isCancel(error)) {
|
|
68
|
-
|
|
71
|
+
log.warn(error);
|
|
69
72
|
|
|
70
73
|
throw error;
|
|
71
74
|
}
|
|
@@ -15,11 +15,11 @@ import {
|
|
|
15
15
|
|
|
16
16
|
const initialize = ({
|
|
17
17
|
initialValues = simpleAccessRights,
|
|
18
|
-
loading = false
|
|
18
|
+
loading = false,
|
|
19
|
+
link = 'link'
|
|
19
20
|
}): unknown => {
|
|
20
21
|
const cancel = cy.stub();
|
|
21
22
|
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}
|
|
50
51
|
loading={loading}
|
|
51
52
|
roles={roles}
|
|
52
53
|
submit={save}
|
|
53
|
-
onChange={change}
|
|
54
54
|
/>
|
|
55
55
|
</Provider>
|
|
56
56
|
</TestQueryProvider>
|
|
@@ -60,7 +60,6 @@ const initialize = ({
|
|
|
60
60
|
|
|
61
61
|
return {
|
|
62
62
|
cancel,
|
|
63
|
-
change,
|
|
64
63
|
save
|
|
65
64
|
};
|
|
66
65
|
};
|
|
@@ -75,12 +74,21 @@ describe('Access rights', () => {
|
|
|
75
74
|
cy.findByLabelText('Add a contact').should('be.visible');
|
|
76
75
|
cy.findByTestId('add_role').should('be.disabled');
|
|
77
76
|
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
|
+
|
|
84
92
|
it('displays the access rights with an empty list', () => {
|
|
85
93
|
initialize({ initialValues: emptyAccessRights });
|
|
86
94
|
|
|
@@ -89,7 +97,7 @@ describe('Access rights', () => {
|
|
|
89
97
|
cy.makeSnapshot();
|
|
90
98
|
});
|
|
91
99
|
|
|
92
|
-
it('displays the access rights list', () => {
|
|
100
|
+
it('displays the access rights with an empty list', () => {
|
|
93
101
|
initialize({});
|
|
94
102
|
|
|
95
103
|
simpleAccessRights.forEach(({ name, email, isContactGroup, role }) => {
|
|
@@ -362,26 +370,4 @@ describe('Access rights', () => {
|
|
|
362
370
|
|
|
363
371
|
cy.makeSnapshot();
|
|
364
372
|
});
|
|
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
|
-
});
|
|
387
373
|
});
|
|
@@ -47,6 +47,7 @@ export const Default: Story = {
|
|
|
47
47
|
},
|
|
48
48
|
initialValues: defaultAccessRights,
|
|
49
49
|
labels,
|
|
50
|
+
link: 'link',
|
|
50
51
|
roles,
|
|
51
52
|
submit: () => undefined
|
|
52
53
|
},
|
|
@@ -62,6 +63,7 @@ export const AccessRightsWithStates: Story = {
|
|
|
62
63
|
},
|
|
63
64
|
initialValues: accessRightsWithStates,
|
|
64
65
|
labels,
|
|
66
|
+
link: 'link',
|
|
65
67
|
roles,
|
|
66
68
|
submit: () => undefined
|
|
67
69
|
},
|
|
@@ -77,6 +79,22 @@ export const withEmptyState: Story = {
|
|
|
77
79
|
},
|
|
78
80
|
initialValues: emptyAccessRights,
|
|
79
81
|
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,
|
|
80
98
|
roles,
|
|
81
99
|
submit: () => undefined
|
|
82
100
|
},
|
|
@@ -92,6 +110,7 @@ export const loading: Story = {
|
|
|
92
110
|
},
|
|
93
111
|
initialValues: emptyAccessRights,
|
|
94
112
|
labels,
|
|
113
|
+
link: 'link',
|
|
95
114
|
loading: true,
|
|
96
115
|
roles,
|
|
97
116
|
submit: () => undefined
|
|
@@ -8,17 +8,16 @@ 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';
|
|
12
11
|
import { useAccessRightsInitValues } from './useAccessRightsInitValues';
|
|
13
12
|
|
|
14
13
|
interface Props {
|
|
15
|
-
cancel
|
|
14
|
+
cancel: ({ dirty, values }) => void;
|
|
16
15
|
endpoints: Endpoints;
|
|
17
16
|
initialValues: Array<AccessRightInitialValues>;
|
|
18
17
|
isSubmitting?: boolean;
|
|
19
18
|
labels: Labels;
|
|
19
|
+
link?: string;
|
|
20
20
|
loading?: boolean;
|
|
21
|
-
onChange?: (values: Array<AccessRightInitialValues>) => void;
|
|
22
21
|
roles: Array<SelectEntry>;
|
|
23
22
|
submit: (values: Array<AccessRightInitialValues>) => Promise<void>;
|
|
24
23
|
}
|
|
@@ -29,14 +28,13 @@ export const AccessRights = ({
|
|
|
29
28
|
endpoints,
|
|
30
29
|
submit,
|
|
31
30
|
cancel,
|
|
31
|
+
link,
|
|
32
32
|
loading,
|
|
33
33
|
labels,
|
|
34
|
-
isSubmitting
|
|
35
|
-
onChange
|
|
34
|
+
isSubmitting
|
|
36
35
|
}: Props): JSX.Element => {
|
|
37
36
|
const { classes } = useAccessRightsStyles();
|
|
38
37
|
const clear = useAccessRightsInitValues({ initialValues });
|
|
39
|
-
useAccessRightsChange(onChange);
|
|
40
38
|
|
|
41
39
|
return (
|
|
42
40
|
<div className={classes.container}>
|
|
@@ -48,6 +46,7 @@ export const AccessRights = ({
|
|
|
48
46
|
clear={clear}
|
|
49
47
|
isSubmitting={isSubmitting}
|
|
50
48
|
labels={labels.actions}
|
|
49
|
+
link={link}
|
|
51
50
|
submit={submit}
|
|
52
51
|
/>
|
|
53
52
|
</div>
|
|
@@ -1,10 +1,14 @@
|
|
|
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
|
+
},
|
|
4
9
|
cancelAndSave: {
|
|
5
10
|
display: 'flex',
|
|
6
|
-
|
|
7
|
-
gap: theme.spacing(2)
|
|
8
|
-
justifyContent: 'flex-end'
|
|
11
|
+
flex: 'row',
|
|
12
|
+
gap: theme.spacing(2)
|
|
9
13
|
}
|
|
10
14
|
}));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useTranslation } from 'react-i18next';
|
|
2
2
|
|
|
3
|
+
import LinkIcon from '@mui/icons-material/Link';
|
|
3
4
|
import { CircularProgress } from '@mui/material';
|
|
4
5
|
|
|
5
6
|
import { Button } from '../../..';
|
|
@@ -9,10 +10,11 @@ import { useActions } from './useActions';
|
|
|
9
10
|
import { useActionsStyles } from './Actions.styles';
|
|
10
11
|
|
|
11
12
|
interface Props {
|
|
12
|
-
cancel
|
|
13
|
+
cancel: ({ dirty, values }) => void;
|
|
13
14
|
clear: () => void;
|
|
14
15
|
isSubmitting?: boolean;
|
|
15
16
|
labels: Labels['actions'];
|
|
17
|
+
link?: string;
|
|
16
18
|
submit: (values: Array<AccessRightInitialValues>) => Promise<void>;
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -20,15 +22,17 @@ const Actions = ({
|
|
|
20
22
|
labels,
|
|
21
23
|
cancel,
|
|
22
24
|
submit,
|
|
25
|
+
link,
|
|
23
26
|
isSubmitting,
|
|
24
27
|
clear
|
|
25
28
|
}: Props): JSX.Element => {
|
|
26
29
|
const { t } = useTranslation();
|
|
27
30
|
const { classes } = useActionsStyles();
|
|
28
31
|
|
|
29
|
-
const { dirty, save, formattedValues } = useActions({
|
|
32
|
+
const { dirty, copyLink, save, formattedValues } = useActions({
|
|
30
33
|
clear,
|
|
31
34
|
labels,
|
|
35
|
+
link,
|
|
32
36
|
submit
|
|
33
37
|
});
|
|
34
38
|
|
|
@@ -37,8 +41,21 @@ const Actions = ({
|
|
|
37
41
|
};
|
|
38
42
|
|
|
39
43
|
return (
|
|
40
|
-
<div className={classes.
|
|
41
|
-
{
|
|
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}>
|
|
42
59
|
<Button
|
|
43
60
|
aria-label={t(labels.cancel)}
|
|
44
61
|
variant="secondary"
|
|
@@ -46,17 +63,17 @@ const Actions = ({
|
|
|
46
63
|
>
|
|
47
64
|
{t(labels.cancel)}
|
|
48
65
|
</Button>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
</
|
|
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>
|
|
60
77
|
</div>
|
|
61
78
|
);
|
|
62
79
|
};
|