@centreon/ui 26.7.1 → 26.7.2
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 +1 -1
- package/src/Dashboard/DashboardLayout.stories.tsx +13 -11
- package/src/InputField/Select/Autocomplete/Connected/index.stories.tsx +1 -0
- package/src/InputField/Select/Autocomplete/Connected/index.test.tsx +110 -109
- package/src/InputField/Text/index.stories.tsx +7 -1
- package/src/api/customFetch.ts +7 -2
- package/src/api/useFetchQuery/index.test.ts +6 -1
package/package.json
CHANGED
|
@@ -72,17 +72,19 @@ const DashboardTemplate = ({
|
|
|
72
72
|
header,
|
|
73
73
|
layout = dashboardLayout
|
|
74
74
|
}: DashboardTemplateProps): ReactElement => (
|
|
75
|
-
<
|
|
76
|
-
{layout
|
|
77
|
-
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
75
|
+
<div className="h-150 overflow-y-auto">
|
|
76
|
+
<DashboardLayout.Layout<CustomLayout> layout={layout}>
|
|
77
|
+
{layout.map(({ i, content, shouldUseFluidTypography }) => (
|
|
78
|
+
<DashboardLayout.Item header={header} id={i} key={i}>
|
|
79
|
+
{shouldUseFluidTypography ? (
|
|
80
|
+
<FluidTypography text={content} />
|
|
81
|
+
) : (
|
|
82
|
+
<Typography>{content}</Typography>
|
|
83
|
+
)}
|
|
84
|
+
</DashboardLayout.Item>
|
|
85
|
+
))}
|
|
86
|
+
</DashboardLayout.Layout>
|
|
87
|
+
</div>
|
|
86
88
|
);
|
|
87
89
|
|
|
88
90
|
const meta: Meta<typeof DashboardTemplate> = {
|
|
@@ -36,6 +36,7 @@ const getEndpoint = ({ endpoint, parameters }): string =>
|
|
|
36
36
|
|
|
37
37
|
const mockSearch = (page: number): object => ({
|
|
38
38
|
delay: 1000,
|
|
39
|
+
headers: { 'Content-Type': 'application/json' },
|
|
39
40
|
method: 'GET',
|
|
40
41
|
response: (request): Listing<SelectEntry> => {
|
|
41
42
|
const { searchParams } = request;
|
|
@@ -1,129 +1,130 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from
|
|
11
|
-
import buildListingEndpoint from
|
|
2
|
+
act,
|
|
3
|
+
fireEvent,
|
|
4
|
+
getFetchCall,
|
|
5
|
+
mockResponse,
|
|
6
|
+
type RenderResult,
|
|
7
|
+
render,
|
|
8
|
+
resetMocks,
|
|
9
|
+
waitFor
|
|
10
|
+
} from '../../../../../test/testRenderer';
|
|
11
|
+
import buildListingEndpoint from '../../../../api/buildListingEndpoint';
|
|
12
12
|
import type {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from
|
|
16
|
-
import TestQueryProvider from
|
|
13
|
+
BuildListingEndpointParameters,
|
|
14
|
+
ConditionsSearchParameter
|
|
15
|
+
} from '../../../../api/buildListingEndpoint/models';
|
|
16
|
+
import TestQueryProvider from '../../../../api/TestQueryProvider';
|
|
17
|
+
import SingleConnectedAutocompleteField from './Single';
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const label = "Connected Autocomplete";
|
|
21
|
-
const placeholder = "Type here...";
|
|
19
|
+
const label = 'Connected Autocomplete';
|
|
20
|
+
const placeholder = 'Type here...';
|
|
22
21
|
|
|
23
22
|
const optionsData = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
meta: {
|
|
24
|
+
limit: 2,
|
|
25
|
+
page: 1,
|
|
26
|
+
total: 20
|
|
27
|
+
},
|
|
28
|
+
result: [
|
|
29
|
+
{ id: 0, name: 'My Option 1' },
|
|
30
|
+
{ id: 1, name: 'My Option 2' }
|
|
31
|
+
]
|
|
33
32
|
};
|
|
34
33
|
|
|
35
|
-
const baseEndpoint =
|
|
34
|
+
const baseEndpoint = 'endpoint';
|
|
36
35
|
|
|
37
36
|
const getEndpoint = (
|
|
38
|
-
|
|
37
|
+
parameters: BuildListingEndpointParameters['parameters']
|
|
39
38
|
): string => {
|
|
40
|
-
|
|
39
|
+
return buildListingEndpoint({ baseEndpoint, parameters });
|
|
41
40
|
};
|
|
42
41
|
|
|
43
42
|
interface Props {
|
|
44
|
-
|
|
43
|
+
searchConditions?: Array<ConditionsSearchParameter>;
|
|
45
44
|
}
|
|
46
45
|
|
|
46
|
+
const mockParams = { headers: { 'Content-Type': 'application/json' } };
|
|
47
|
+
|
|
47
48
|
const renderSingleConnectedAutocompleteField = (
|
|
48
|
-
|
|
49
|
+
{ searchConditions }: Props = { searchConditions: undefined }
|
|
49
50
|
): RenderResult =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
render(
|
|
52
|
+
<TestQueryProvider>
|
|
53
|
+
<SingleConnectedAutocompleteField
|
|
54
|
+
baseEndpoint=""
|
|
55
|
+
field="host.name"
|
|
56
|
+
getEndpoint={getEndpoint}
|
|
57
|
+
label={label}
|
|
58
|
+
placeholder="Type here..."
|
|
59
|
+
searchConditions={searchConditions}
|
|
60
|
+
/>
|
|
61
|
+
</TestQueryProvider>
|
|
62
|
+
);
|
|
62
63
|
|
|
63
64
|
describe(SingleConnectedAutocompleteField, () => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
resetMocks();
|
|
67
|
+
mockResponse({ data: optionsData, options: mockParams });
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('populates options with the first page result from the endpoint request', async () => {
|
|
71
|
+
const { getByLabelText, getByText } =
|
|
72
|
+
renderSingleConnectedAutocompleteField();
|
|
73
|
+
|
|
74
|
+
fireEvent.click(getByLabelText('Open'));
|
|
75
|
+
|
|
76
|
+
expect(getFetchCall(0)).toEqual(`${baseEndpoint}?page=1`);
|
|
77
|
+
|
|
78
|
+
await waitFor(() => {
|
|
79
|
+
expect(getByText('My Option 1')).toBeInTheDocument();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('populates options with the first page result from the endpoint request after typing something in input field', async () => {
|
|
84
|
+
const { getByLabelText, getByPlaceholderText } =
|
|
85
|
+
renderSingleConnectedAutocompleteField();
|
|
86
|
+
|
|
87
|
+
act(() => {
|
|
88
|
+
fireEvent.click(getByLabelText('Open'));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await waitFor(() => {
|
|
92
|
+
expect(getFetchCall(0)).toEqual(`${baseEndpoint}?page=1`);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(getFetchCall(1)).toEqual(`${baseEndpoint}?page=2`);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
fireEvent.change(getByPlaceholderText(placeholder), {
|
|
100
|
+
target: { value: 'My Option 2' }
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await waitFor(() => {
|
|
104
|
+
expect(decodeURIComponent(getFetchCall(2) as string)).toEqual(
|
|
105
|
+
'endpoint?page=1&search={"$and":[{"$and":[{"host.name":{"$lk":"%My Option 2%"}}]}]}'
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('adds search conditions to the endpoint request when the corresponding prop is passed', async () => {
|
|
111
|
+
const { getByLabelText } = renderSingleConnectedAutocompleteField({
|
|
112
|
+
searchConditions: [
|
|
113
|
+
{
|
|
114
|
+
field: 'parent_name',
|
|
115
|
+
value: {
|
|
116
|
+
$eq: 'Centreon-Server'
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
fireEvent.click(getByLabelText('Open'));
|
|
123
|
+
|
|
124
|
+
await waitFor(() => {
|
|
125
|
+
expect(getFetchCall(0)).toEqual(
|
|
126
|
+
`${baseEndpoint}?page=1&search=%7B%22%24and%22%3A%5B%7B%22%24or%22%3A%5B%7B%22parent_name%22%3A%7B%22%24eq%22%3A%22Centreon-Server%22%7D%7D%5D%7D%5D%7D`
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
129
130
|
});
|
|
@@ -104,7 +104,13 @@ export const autoSizeWithEndAdornment = (): JSX.Element => (
|
|
|
104
104
|
autoSize
|
|
105
105
|
autoSizeCustomPadding={10}
|
|
106
106
|
autoSizeDefaultWidth={60}
|
|
107
|
-
EndAdornment={AbcIcon}
|
|
108
107
|
placeholder="Auto size"
|
|
108
|
+
textFieldSlotsAndSlotProps={{
|
|
109
|
+
slotProps: {
|
|
110
|
+
input: {
|
|
111
|
+
endAdornment: <AbcIcon />
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}}
|
|
109
115
|
/>
|
|
110
116
|
);
|
package/src/api/customFetch.ts
CHANGED
|
@@ -74,8 +74,13 @@ export const customFetch = <T>({
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
.
|
|
77
|
+
const responseParsingMethod = response.headers
|
|
78
|
+
.get('Content-Type')
|
|
79
|
+
?.startsWith('text')
|
|
80
|
+
? 'text'
|
|
81
|
+
: 'json';
|
|
82
|
+
|
|
83
|
+
return response[responseParsingMethod]()
|
|
79
84
|
.then((data) => {
|
|
80
85
|
if (!response.ok) {
|
|
81
86
|
const defaultError = {
|
|
@@ -37,6 +37,8 @@ const renderFetchQuery = <T extends object>(
|
|
|
37
37
|
wrapper: TestQueryProvider
|
|
38
38
|
}) as RenderHookResult<UseFetchQueryState<T>, unknown>;
|
|
39
39
|
|
|
40
|
+
const mockParams = { headers: { 'Content-Type': 'application/json' } };
|
|
41
|
+
|
|
40
42
|
describe('useFetchQuery', () => {
|
|
41
43
|
beforeEach(() => {
|
|
42
44
|
mockedShowErrorMessage.mockReset();
|
|
@@ -57,7 +59,7 @@ describe('useFetchQuery', () => {
|
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
it('retrieves data from an endpoint', async () => {
|
|
60
|
-
fetchMock.once(JSON.stringify(user));
|
|
62
|
+
fetchMock.once(JSON.stringify(user), mockParams);
|
|
61
63
|
const { result } = renderFetchQuery<User>({
|
|
62
64
|
getEndpoint: () => '/endpoint',
|
|
63
65
|
getQueryKey: () => ['queryKey']
|
|
@@ -70,6 +72,7 @@ describe('useFetchQuery', () => {
|
|
|
70
72
|
|
|
71
73
|
it("shows an error from the API via the Snackbar and inside the browser's console", async () => {
|
|
72
74
|
fetchMock.once(JSON.stringify({ code: 2, message: 'custom message' }), {
|
|
75
|
+
...mockParams,
|
|
73
76
|
status: 400
|
|
74
77
|
});
|
|
75
78
|
|
|
@@ -109,6 +112,7 @@ describe('useFetchQuery', () => {
|
|
|
109
112
|
|
|
110
113
|
it('shows a default failure message via the Snackbar as fallback', async () => {
|
|
111
114
|
fetchMock.once(JSON.stringify({}), {
|
|
115
|
+
...mockParams,
|
|
112
116
|
status: 400
|
|
113
117
|
});
|
|
114
118
|
|
|
@@ -134,6 +138,7 @@ describe('useFetchQuery', () => {
|
|
|
134
138
|
|
|
135
139
|
it('does not show any message via the Snackbar when the httpCodesBypassErrorSnackbar is passed', async () => {
|
|
136
140
|
fetchMock.once(JSON.stringify({}), {
|
|
141
|
+
...mockParams,
|
|
137
142
|
status: 400
|
|
138
143
|
});
|
|
139
144
|
|