Skip to content

Commit 21c4dac

Browse files
authored
Merge pull request #1068 from equinor/fix/use-correct-faq-endpoint
👽 Use new FAQ endpoint to fetch faqs
2 parents c0d8112 + 76bca1c commit 21c4dac

File tree

10 files changed

+105
-51
lines changed

10 files changed

+105
-51
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@equinor/amplify-component-lib",
3-
"version": "9.8.4",
3+
"version": "9.9.0",
44
"description": "Frontend Typescript components for the Amplify team",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/atoms/hooks/useFaqsInApplication.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export function useFaqsInApplication() {
77
return useQuery({
88
queryKey: ['GET_FAQ_IN_APP'], // This is hard-coded on purpose, assuming we never have to update cache manually
99
queryFn: async () => {
10-
const data = await FaqService.getFaqCategoriesFromApplicationId(
10+
const data = await FaqService.getCategoriesWithFaqsFromApplicationName(
1111
environment.getAppName(import.meta.env.VITE_NAME)
1212
);
1313

src/organisms/Faq/Faq.test.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ test('Able to open FAQ', async () => {
207207

208208
test('Renders expected content when empty', async ({ worker }) => {
209209
worker.use(
210-
http.get('*/api/v1/Faq/faqcategories/:appName', () => {
210+
http.get('*/api/v1/Faq/faqcategorieswithfaqs/:appName', () => {
211211
return HttpResponse.json([]);
212212
})
213213
);

src/organisms/TopBar/Account/Account.tsx

+12-23
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import {
22
FC,
3-
MutableRefObject,
43
ReactElement,
54
ReactNode,
5+
RefObject,
66
useCallback,
77
useEffect,
88
useMemo,
99
useRef,
1010
useState,
1111
} from 'react';
1212

13-
import { AccountInfo } from '@azure/msal-common';
1413
import { Button, Icon, Typography } from '@equinor/eds-core-react';
1514
import { log_out } from '@equinor/eds-icons';
1615

1716
import { TopBarMenu } from '../TopBarMenu';
1817
import { useActiveImpersonationUser } from './ImpersonateMenu/hooks/useActiveImpersonationUser';
1918
import { useCanImpersonate } from './ImpersonateMenu/hooks/useCanImpersonate';
19+
import { useMappedRoles } from './ImpersonateMenu/hooks/useMappedRoles';
2020
import { useStopImpersonation } from './ImpersonateMenu/hooks/useStopImpersonation';
2121
import { ImpersonateMenu } from './ImpersonateMenu/ImpersonateMenu';
2222
import {
@@ -36,33 +36,19 @@ import { impersonateUserDtoToFullName } from 'src/organisms/TopBar/Account/Imper
3636
import { useAuth } from 'src/providers/AuthProvider/AuthProvider';
3737

3838
export interface AccountProps {
39-
/**
40-
* @deprecated logout - Not needed anymore
41-
*/
42-
logout?: () => void;
43-
/**
44-
* @deprecated account - Not needed anymore
45-
*/
46-
account?: AccountInfo | undefined;
47-
/**
48-
* @deprecated photo - Not needed anymore
49-
*/
50-
photo?: string | undefined;
51-
/**
52-
* @deprecated roles - Not needed anymore
53-
*/
54-
roles?: string[] | undefined;
5539
renderCustomButton?: (
56-
buttonRef: MutableRefObject<HTMLButtonElement | null>,
40+
buttonRef: RefObject<HTMLButtonElement | null>,
5741
handleToggle: () => void
5842
) => ReactElement;
5943
hideRoleChips?: boolean;
44+
useDisplayNameForRole?: boolean;
6045
children?: ReactNode;
6146
}
6247

6348
export const Account: FC<AccountProps> = ({
6449
renderCustomButton,
6550
hideRoleChips = false,
51+
useDisplayNameForRole = false,
6652
children,
6753
}) => {
6854
const ACTIVE_ENVIRONMENT = environment.getEnvironmentName(
@@ -79,13 +65,16 @@ export const Account: FC<AccountProps> = ({
7965
const { data: canImpersonate = true } = useCanImpersonate();
8066
const { data: activeImpersonationUser } = useActiveImpersonationUser();
8167
const { mutate: endImpersonation } = useStopImpersonation();
68+
const activeRoles = useMappedRoles(
69+
// Wasn't able to test the (roles ?? []) part, because roles are always defined from useAuth when we are logged in
70+
/* v8 ignore next */
71+
activeImpersonationUser ? activeImpersonationUser.roles : (roles ?? []),
72+
useDisplayNameForRole
73+
);
8274

8375
const fullName = activeImpersonationUser
8476
? impersonateUserDtoToFullName(activeImpersonationUser)
8577
: account?.name;
86-
const activeRoles = activeImpersonationUser
87-
? activeImpersonationUser.roles
88-
: roles;
8978
const username = activeImpersonationUser
9079
? activeImpersonationUser.uniqueName
9180
: account?.username;
@@ -145,7 +134,7 @@ export const Account: FC<AccountProps> = ({
145134
{activeRoles && !hideRoleChips && (
146135
<RolesContainer>
147136
{activeRoles.map((role) => (
148-
<RoleChip key={role}>{role}</RoleChip>
137+
<RoleChip key={role.value}>{role.label}</RoleChip>
149138
))}
150139
</RolesContainer>
151140
)}

src/organisms/TopBar/Account/ImpersonateMenu/CreateOrEditUser/CreateOrEditUser.test.tsx

+43-3
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ test.each(['email', 'no-email'])(
131131

132132
await user.click(screen.getByRole('button', { name: /edit user/i }));
133133

134+
await waitForElementToBeRemoved(() => screen.getAllByRole('progressbar'));
135+
134136
const textBox = screen.getByRole('textbox', { name: /first name/i });
135137
await user.clear(textBox);
136138

@@ -148,15 +150,51 @@ test.each(['email', 'no-email'])(
148150

149151
await user.click(screen.getByRole('button', { name: /save/i }));
150152

151-
await waitForElementToBeRemoved(() => screen.getAllByRole('progressbar'));
152-
153153
expect(
154154
await screen.findByText(new RegExp(newFirstName))
155155
).toBeInTheDocument();
156156
},
157157
{ timeout: 8000 }
158158
);
159159

160+
test('Edit another user clears the form as expected', async () => {
161+
renderWithProviders(<Account />);
162+
const user = userEvent.setup();
163+
const button = screen.getByRole('button');
164+
165+
await user.click(button);
166+
167+
await user.click(await screen.findByRole('button', { name: 'Impersonate' }));
168+
169+
const menuItems = await screen.findAllByTestId('impersonation-user');
170+
expect(menuItems.length).toBeGreaterThan(0);
171+
172+
// Click edit on the first one
173+
await user.click(within(menuItems[0]).getByRole('button'));
174+
175+
await user.click(screen.getByRole('button', { name: /edit user/i }));
176+
177+
await waitForElementToBeRemoved(() => screen.getAllByRole('progressbar'));
178+
179+
const textBox = screen.getByRole('textbox', {
180+
name: /first name/i,
181+
}) as HTMLInputElement;
182+
const firstName = textBox.value;
183+
184+
await user.click(screen.getByRole('button', { name: /cancel/i }));
185+
186+
const newMenuItems = await screen.findAllByTestId('impersonation-user');
187+
await user.click(within(newMenuItems[1]).getByRole('button'));
188+
189+
await user.click(screen.getByRole('button', { name: /edit user/i }));
190+
191+
const otherName = (
192+
screen.getByRole('textbox', { name: /first name/i }) as HTMLInputElement
193+
).value;
194+
195+
expect(otherName).not.toBe(firstName);
196+
});
197+
160198
test.each(['email', 'no-email'])(
161199
'Able to create new impersonation user - %s',
162200
async (testCase) => {
@@ -172,6 +210,8 @@ test.each(['email', 'no-email'])(
172210

173211
await user.click(screen.getByRole('button', { name: /create users/i }));
174212

213+
await waitForElementToBeRemoved(() => screen.getAllByRole('progressbar'));
214+
175215
const createButton = screen.getByRole('button', {
176216
name: /create/i,
177217
});
@@ -204,7 +244,7 @@ test.each(['email', 'no-email'])(
204244
min: 2,
205245
max: FAKE_ROLES.length - 1,
206246
})
207-
.map((role) => role.value)
247+
.map((role) => role.displayName)
208248
.sort();
209249

210250
await user.click(screen.getByRole('combobox'));

src/organisms/TopBar/Account/ImpersonateMenu/CreateOrEditUser/CreateOrEditUser.tsx

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import { ChangeEvent, FC, useEffect, useMemo, useState } from 'react';
1+
import { ChangeEvent, FC, useEffect, useMemo, useRef, useState } from 'react';
22

33
import { Button, DotProgress, Icon, Typography } from '@equinor/eds-core-react';
44
import { arrow_back } from '@equinor/eds-icons';
55
import { ImpersonateUserDto } from '@equinor/subsurface-app-management';
66

7-
import { useAllAppRoles } from '../hooks/useAllAppRoles';
87
import { useCreateImpersonation } from '../hooks/useCreateImpersonation';
98
import { useEditImpersonation } from '../hooks/useEditImpersonation';
109
import { Header } from '../Impersonate.styles';
1110
import { Container, Section } from './CreateOrEditUser.styles';
12-
import { usePrevious } from 'src/atoms/hooks/usePrevious';
1311
import { environment } from 'src/atoms/utils/auth_environment';
1412
import { ComboBox, SelectOptionRequired } from 'src/molecules';
1513
import { TextField } from 'src/molecules/TextField/TextField';
14+
import { useAllAppRoles } from 'src/organisms/TopBar/Account/ImpersonateMenu/hooks/useAllAppRoles';
1615

1716
interface CreateOrEditUserProps {
1817
editingUser?: ImpersonateUserDto;
@@ -23,32 +22,34 @@ export const CreateOrEditUser: FC<CreateOrEditUserProps> = ({
2322
editingUser,
2423
onBack,
2524
}) => {
26-
const previousEditingUser = usePrevious(editingUser);
25+
const initializedEditUser = useRef<boolean>(false);
2726
const [roles, setRoles] = useState<SelectOptionRequired[]>([]);
2827
const [firstName, setFirstName] = useState('');
2928
const [lastName, setLastName] = useState('');
3029
const [email, setEmail] = useState('');
31-
3230
const { data, isLoading: isLoadingRoles } = useAllAppRoles();
3331

3432
useEffect(() => {
35-
if (
36-
editingUser &&
37-
(previousEditingUser === undefined ||
38-
previousEditingUser.uniqueName !== editingUser.uniqueName)
39-
) {
40-
setRoles(editingUser.roles.map((role) => ({ value: role, label: role })));
33+
if (editingUser && data && !initializedEditUser.current) {
34+
initializedEditUser.current = true;
35+
setRoles(
36+
editingUser.roles.map((role) => {
37+
const mapped = data.find((item) => item.value === role);
38+
if (mapped) return { value: role, label: mapped.displayName };
39+
return { value: role, label: role };
40+
})
41+
);
4142
setFirstName(editingUser.firstName);
4243
setLastName(editingUser.lastName);
4344
setEmail(editingUser.email ?? '');
4445
}
45-
}, [editingUser, previousEditingUser]);
46+
}, [data, editingUser, initializedEditUser]);
4647

4748
const availableRoles = useMemo(
4849
() =>
4950
data?.map((item) => ({
5051
value: item.value,
51-
label: item.value,
52+
label: item.displayName,
5253
})) ?? [],
5354
[data]
5455
);

src/organisms/TopBar/Account/ImpersonateMenu/UserImpersonation.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from '@equinor/eds-icons';
1111
import { ImpersonateUserDto } from '@equinor/subsurface-app-management';
1212

13+
import { useMappedRoles } from './hooks/useMappedRoles';
1314
import {
1415
Container,
1516
RoleChip,
@@ -60,8 +61,7 @@ export const UserImpersonation: FC<UserImpersonationProps> = ({
6061
const [open, setOpen] = useState(false);
6162
const buttonRef = useRef<HTMLButtonElement | null>(null);
6263
const fullName = impersonateUserDtoToFullName({ firstName, lastName });
63-
64-
const sortedRoles = [...roles].sort();
64+
const activeRoles = useMappedRoles(roles);
6565

6666
const handleOnToggleMenu = () => setOpen((prev) => !prev);
6767
const handleOnClose = () => setOpen(false);
@@ -95,11 +95,11 @@ export const UserImpersonation: FC<UserImpersonationProps> = ({
9595
/>
9696
<Typography data-testid="name">{fullName}</Typography>
9797
<RoleChipContainer $selected={selected}>
98-
<RoleChip data-testid="role">{sortedRoles[0]}</RoleChip>
99-
{sortedRoles.length > 1 && (
100-
<OptionalTooltip title={sortedRoles.slice(1).join(', ')}>
98+
<RoleChip data-testid="role">{activeRoles[0].label}</RoleChip>
99+
{activeRoles.length > 1 && (
100+
<OptionalTooltip title={activeRoles.slice(1).join(', ')}>
101101
<RoleChip data-testid="additional-roles">
102-
{`+${sortedRoles.length - 1}`}
102+
{`+${activeRoles.length - 1}`}
103103
</RoleChip>
104104
</OptionalTooltip>
105105
)}

src/organisms/TopBar/Account/ImpersonateMenu/hooks/useAllAppRoles.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import { useQuery } from '@tanstack/react-query';
44
import { AVAILABLE_ROLES } from '../Impersonate.constants';
55
import { environment } from 'src/atoms/utils/auth_environment';
66

7-
export function useAllAppRoles() {
7+
export function useAllAppRoles(enabled = true) {
88
return useQuery({
99
queryKey: [AVAILABLE_ROLES],
1010
queryFn: () =>
1111
AmplifyApplicationService.getAllAppRoles(
1212
environment.getApiClientId(import.meta.env.VITE_API_CLIENT_ID)
1313
),
14+
enabled,
15+
staleTime: Infinity,
16+
gcTime: Infinity,
1417
});
1518
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useMemo } from 'react';
2+
3+
import { useAllAppRoles } from './useAllAppRoles';
4+
5+
export function useMappedRoles(roles: string[], enabled = true) {
6+
const { data: allAppRoles = [] } = useAllAppRoles(enabled);
7+
8+
return useMemo(() => {
9+
return roles.toSorted().map((role) => {
10+
const currentRole = allAppRoles.find((item) => item.value === role);
11+
12+
if (currentRole)
13+
return { value: currentRole.value, label: currentRole.displayName };
14+
15+
return {
16+
value: role,
17+
label: role,
18+
};
19+
});
20+
}, [allAppRoles, roles]);
21+
}

src/tests/mockHandlers.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ function fakeUser(): ImpersonateUserDto {
8585
lastName,
8686
email,
8787
uniqueName,
88-
roles,
88+
roles: [...roles, 'other'],
8989
appName: environment.getAppName(import.meta.env.VITE_NAME),
9090
activeUsers: [],
9191
};
@@ -382,7 +382,7 @@ export const handlers = [
382382
await delay('real');
383383
return HttpResponse.text('failed', { status: 500 });
384384
}),
385-
http.get('*/v1/Faq/faqcategories/:appName', async () => {
385+
http.get('*/v1/Faq/faqcategorieswithfaqs/:appName', async () => {
386386
await delay('real');
387387
return HttpResponse.json(FAKE_FAQ_CATEGORIES);
388388
}),

0 commit comments

Comments
 (0)