Skip to content

Commit 31f1ab9

Browse files
Merge branch 'develop' into implement-base-authorisation-#1472
2 parents b6563fe + 678342f commit 31f1ab9

22 files changed

+12205
-11980
lines changed

src/App.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
clearFailedAuthRequestsQueue,
2828
retryFailedAuthRequests,
2929
} from './api/api';
30+
import APIConfigProvider from './apiConfigProvider.component';
3031
import { MicroFrontendId } from './app.types';
3132
import CatalogueLayout, {
3233
CatalogueErrorComponent,
@@ -277,14 +278,16 @@ export function Layout() {
277278
<ConfigProvider>
278279
<AuthProvider>
279280
<QueryClientProvider client={queryClient}>
280-
<React.Suspense
281-
fallback={
282-
<Preloader loading={true}>Finished loading</Preloader>
283-
}
284-
>
285-
<ViewTabs />
286-
<ReactQueryDevtools initialIsOpen={false} />
287-
</React.Suspense>
281+
<APIConfigProvider>
282+
<React.Suspense
283+
fallback={
284+
<Preloader loading={true}>Finished loading</Preloader>
285+
}
286+
>
287+
<ViewTabs />
288+
<ReactQueryDevtools initialIsOpen={false} />
289+
</React.Suspense>
290+
</APIConfigProvider>
288291
</QueryClientProvider>
289292
</AuthProvider>
290293
</ConfigProvider>
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import type { RenderResult } from '@testing-library/react';
2+
import { screen, waitFor } from '@testing-library/react';
3+
import { http, HttpResponse } from 'msw';
4+
import * as React from 'react';
5+
import APIConfigProvider, {
6+
APISettingsContext,
7+
} from './apiConfigProvider.component';
8+
import { server } from './mocks/server';
9+
import { renderComponentWithRouterProvider } from './testUtils';
10+
11+
const APIConfigTest: React.FC = (): React.ReactElement => {
12+
const settings = React.useContext(APISettingsContext);
13+
14+
// Return the settings as a string to inspect later in tests.
15+
return <div data-testid="settings">{JSON.stringify(settings)}</div>;
16+
};
17+
18+
describe('APIConfigProvider', () => {
19+
beforeEach(() => {
20+
global.document.dispatchEvent = vi.fn();
21+
global.CustomEvent = vi.fn();
22+
});
23+
24+
afterEach(() => {
25+
vi.clearAllMocks();
26+
});
27+
28+
// Create a wrapper for our settings tests.
29+
const renderComponent = (): RenderResult =>
30+
renderComponentWithRouterProvider(
31+
<APIConfigProvider>
32+
<APIConfigTest />
33+
</APIConfigProvider>
34+
);
35+
36+
it('settings are loaded (with spares)', async () => {
37+
renderComponent();
38+
39+
// Preloader is in a loading state when ConfigProvider is
40+
// loading the configuration.
41+
expect(screen.getByText('Loading...')).toBeInTheDocument();
42+
43+
await waitFor(() => {
44+
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
45+
});
46+
expect(screen.getByTestId('settings')).toBeInTheDocument();
47+
expect(screen.getByTestId('settings')).toHaveTextContent(
48+
JSON.stringify({
49+
spares: {
50+
sparesFilterState:
51+
'?state=N4IgxgYiBcDaoEsAmMQGcCeaAuBTAtgHTYYAOuhAbgIYA2ArriADQg0NNygnmo4BOCAHYBzFmzqNUAZWwB7ftRFMAvgF11KoA',
52+
sparesColumnsFilters: {
53+
cF: [
54+
{
55+
id: 'system.type.value',
56+
value: [{ type: 'string', value: 'Storage' }],
57+
},
58+
],
59+
},
60+
isLoading: false,
61+
sparesDefinition: { system_types: [{ id: '1', value: 'Storage' }] },
62+
},
63+
})
64+
);
65+
});
66+
67+
it('settings are loaded (without spares)', async () => {
68+
server.use(
69+
http.get('/v1/settings/spares-definition', () => {
70+
return HttpResponse.json({ system_types: [] }, { status: 200 });
71+
})
72+
);
73+
renderComponent();
74+
75+
// Preloader is in a loading state when ConfigProvider is
76+
// loading the configuration.
77+
expect(screen.getByText('Loading...')).toBeInTheDocument();
78+
79+
await waitFor(() => {
80+
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
81+
});
82+
expect(screen.getByTestId('settings')).toBeInTheDocument();
83+
expect(screen.getByTestId('settings')).toHaveTextContent(
84+
JSON.stringify({})
85+
);
86+
});
87+
88+
it('settings are loaded (without spares 204 no content)', async () => {
89+
server.use(
90+
http.get('/v1/settings/spares-definition', () => {
91+
return HttpResponse.json(undefined, { status: 204 });
92+
})
93+
);
94+
renderComponent();
95+
96+
// Preloader is in a loading state when ConfigProvider is
97+
// loading the configuration.
98+
expect(screen.getByText('Loading...')).toBeInTheDocument();
99+
100+
await waitFor(() => {
101+
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
102+
});
103+
expect(screen.getByTestId('settings')).toBeInTheDocument();
104+
expect(screen.getByTestId('settings')).toHaveTextContent(
105+
JSON.stringify({})
106+
);
107+
});
108+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import { SparesFilterStateType } from './app.types';
3+
import Preloader from './preloader/preloader.component';
4+
5+
import { useSparesFilterState } from './utils';
6+
7+
interface APISettings {
8+
spares?: SparesFilterStateType;
9+
}
10+
11+
export const APISettingsContext = React.createContext<APISettings>({});
12+
13+
function APIConfigProvider({ children }: { children: React.ReactNode }) {
14+
const [loading, setLoading] = React.useState(true);
15+
const [settings, setSettings] = React.useState<APISettings>({});
16+
17+
const sparesInfo = useSparesFilterState();
18+
19+
React.useEffect(() => {
20+
const updateConfigurationState = async () => {
21+
const isSparesDefinitionDefined =
22+
sparesInfo.sparesDefinition !== '' &&
23+
sparesInfo.sparesDefinition.system_types.length !== 0;
24+
25+
if (!sparesInfo.isLoading) {
26+
setLoading(false);
27+
setSettings({
28+
spares: isSparesDefinitionDefined ? sparesInfo : undefined,
29+
});
30+
}
31+
};
32+
33+
updateConfigurationState();
34+
}, [sparesInfo]);
35+
36+
return (
37+
<Preloader loading={loading}>
38+
<APISettingsContext.Provider value={settings}>
39+
{children}
40+
</APISettingsContext.Provider>
41+
</Preloader>
42+
);
43+
}
44+
45+
export default APIConfigProvider;

src/app.types.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import type { Body, Meta } from '@uppy/core';
2+
import { MRT_ColumnFiltersState } from 'material-react-table';
23
import {
34
CatalogueCategory,
45
CatalogueItem,
56
Item,
67
ItemPost,
8+
SparesDefinition,
79
System,
810
type APIImage,
911
type ObjectFileUploadMetadata,
@@ -224,3 +226,12 @@ export interface AdvancedSerialNumberOptionsType {
224226
export interface UppyImageUploadResponse extends APIImage, Body {}
225227

226228
export interface UppyUploadMetadata extends ObjectFileUploadMetadata, Meta {}
229+
230+
// --------------------------------- SPARES -----------------------------------------------------------
231+
232+
export interface SparesFilterStateType {
233+
sparesDefinition: '' | SparesDefinition;
234+
sparesFilterState: string;
235+
sparesColumnsFilters: { cF: MRT_ColumnFiltersState };
236+
isLoading: boolean;
237+
}

0 commit comments

Comments
 (0)