Skip to content

Commit abe5257

Browse files
modifications on the authz title component
Removing the allow public read switch. Updated assign role button text. Title and subtitle appears in the same line.
1 parent 2ac818f commit abe5257

14 files changed

Lines changed: 41 additions & 273 deletions

src/authz-module/components/AuthZTitle.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe('AuthZTitle', () => {
4040

4141
it('renders page title', () => {
4242
render(<AuthZTitle {...defaultProps} />);
43-
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent(defaultProps.pageTitle);
43+
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(defaultProps.pageTitle);
4444
});
4545

4646
it('renders page subtitle as ReactNode', () => {

src/authz-module/components/AuthZTitle.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
} from 'react';
44
import { Link } from 'react-router-dom';
55
import {
6-
Breadcrumb, Col, Container, Row, Button, Badge,
6+
Breadcrumb, Col, Container, Row, Button,
77
Stack,
88
useMediaQuery,
99
breakpoints,
@@ -50,10 +50,13 @@ const AuthZTitle = ({
5050
/>
5151
<Row className="mt-4">
5252
<Col xs={12} md={7} className="mb-4">
53-
<h1 className="text-primary">{pageTitle}</h1>
54-
{typeof pageSubtitle === 'string'
55-
? <h3><Badge className="py-2 px-3 font-weight-normal" variant="light">{pageSubtitle}</Badge></h3>
56-
: pageSubtitle}
53+
<div className="d-flex align-items-center">
54+
<h2 className="text-primary mb-0">{pageTitle}</h2>
55+
{typeof pageSubtitle === 'string'
56+
? <><hr className="mx-lg-3" /><h3 className="mb-0 py-2 font-weight-light text-gray-700">{pageSubtitle}</h3></>
57+
: <><hr className="mx-lg-3" /> <div className="mb-0">{pageSubtitle}</div></>}
58+
59+
</div>
5760
</Col>
5861
<Col xs={12} md={5}>
5962
<Stack className="justify-content-end" direction={isDesktop ? 'horizontal' : 'vertical'}>

src/authz-module/data/api.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
22
import { LibraryMetadata, TeamMember } from '@src/types';
3-
import { camelCaseObject, snakeCaseObject } from '@edx/frontend-platform';
3+
import { camelCaseObject } from '@edx/frontend-platform';
44
import { getApiUrl, getStudioApiUrl } from '@src/data/utils';
55

66
export interface QuerySettings {
@@ -108,17 +108,3 @@ export const revokeUserRoles = async (
108108
const res = await getAuthenticatedHttpClient().delete(url.toString());
109109
return camelCaseObject(res.data);
110110
};
111-
112-
export const updateLibrary = async (libraryId, updatedData): Promise<LibraryMetadata> => {
113-
const { data } = await getAuthenticatedHttpClient().patch(
114-
getStudioApiUrl(`/api/libraries/v2/${libraryId}/`),
115-
snakeCaseObject(updatedData),
116-
);
117-
return {
118-
id: data.id,
119-
org: data.org,
120-
title: data.title,
121-
slug: data.slug,
122-
allowPublicRead: data.allow_public_read,
123-
};
124-
};

src/authz-module/data/hooks.test.tsx

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
44
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
55
import {
66
useLibrary, usePermissionsByRole, useTeamMembers, useAssignTeamMembersRole, useRevokeUserRoles,
7-
useUpdateLibrary,
87
} from './hooks';
98

109
jest.mock('@edx/frontend-platform/auth', () => ({
@@ -341,80 +340,3 @@ describe('useRevokeUserRoles', () => {
341340
expect(calledUrl.searchParams.get('scope')).toBe(revokeRoleData.scope);
342341
});
343342
});
344-
345-
describe('useUpdateLibrary', () => {
346-
const queryKeyTest = ['org.openedx.frontend.app.adminConsole', 'authz', 'library', 'lib:123'];
347-
348-
beforeEach(() => {
349-
jest.clearAllMocks();
350-
});
351-
352-
it('calls updateLibrary with correct params and updates cache', async () => {
353-
const mockData = { id: 'lib:123', title: 'Library Test' };
354-
getAuthenticatedHttpClient.mockReturnValue({
355-
patch: jest.fn().mockResolvedValue({ data: mockData }),
356-
});
357-
const { result } = renderHook(() => useUpdateLibrary(), { wrapper: createWrapper() });
358-
359-
await act(async () => {
360-
await result.current.mutateAsync({
361-
libraryId: 'lib:123',
362-
updatedData: { title: 'Library Test' },
363-
});
364-
});
365-
366-
expect(getAuthenticatedHttpClient).toHaveBeenCalled();
367-
});
368-
369-
it('sets query data on success', async () => {
370-
const mockData = { id: 'lib:123', title: 'Updated Library' };
371-
getAuthenticatedHttpClient.mockReturnValue({
372-
patch: jest.fn().mockResolvedValue({ data: mockData }),
373-
});
374-
375-
const queryClient = new QueryClient();
376-
const wrapper = ({ children }: { children: ReactNode }) => (
377-
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
378-
);
379-
380-
const { result } = renderHook(() => useUpdateLibrary(), { wrapper });
381-
382-
await act(async () => {
383-
await result.current.mutateAsync({
384-
libraryId: 'lib:123',
385-
updatedData: { title: 'Updated Library' },
386-
});
387-
});
388-
389-
// verify cache updated with the returned data
390-
expect(queryClient.getQueryData(queryKeyTest)).toEqual(mockData);
391-
expect(getAuthenticatedHttpClient).toHaveBeenCalled();
392-
});
393-
394-
it('invalidates query on settled', async () => {
395-
const mockData = { id: 'lib:123', title: 'Final Title' };
396-
getAuthenticatedHttpClient.mockReturnValue({
397-
patch: jest.fn().mockResolvedValue({ data: mockData }),
398-
});
399-
const queryClient = new QueryClient();
400-
const invalidateSpy = jest.spyOn(queryClient, 'invalidateQueries');
401-
402-
const wrapper = ({ children }: { children: ReactNode }) => (
403-
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
404-
);
405-
406-
const { result } = renderHook(() => useUpdateLibrary(), { wrapper });
407-
408-
await act(async () => {
409-
await result.current.mutateAsync({
410-
libraryId: 'lib:123',
411-
updatedData: { title: 'Final Title' },
412-
});
413-
});
414-
415-
expect(invalidateSpy).toHaveBeenCalledWith({
416-
queryKey: queryKeyTest,
417-
});
418-
expect(getAuthenticatedHttpClient).toHaveBeenCalled();
419-
});
420-
});

src/authz-module/data/hooks.ts

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { LibraryMetadata } from '@src/types';
66
import {
77
assignTeamMembersRole, AssignTeamMembersRoleRequest, getLibrary, getPermissionsByRole, getTeamMembers,
88
GetTeamMembersResponse, PermissionsByRole, QuerySettings, revokeUserRoles, RevokeUserRolesRequest,
9-
updateLibrary,
109
} from './api';
1110

1211
const authzQueryKeys = {
@@ -111,28 +110,3 @@ export const useRevokeUserRoles = () => {
111110
},
112111
});
113112
};
114-
115-
/**
116-
* React Query hook to update the library metadata.
117-
*
118-
* @example
119-
* const { mutate: updateLibrary } = useUpdateLibrary();
120-
* updateLibrary({ libraryId: 'lib:123', updatedData: { title: 'Library Test' }});
121-
*/
122-
123-
export const useUpdateLibrary = () => {
124-
const queryClient = useQueryClient();
125-
126-
return useMutation({
127-
mutationFn: ({ libraryId, updatedData }: {
128-
libraryId: string;
129-
updatedData: Partial<LibraryMetadata>
130-
}) => updateLibrary(libraryId, updatedData),
131-
onSuccess: (data) => {
132-
queryClient.setQueryData(authzQueryKeys.library(data.id), data);
133-
},
134-
onSettled: (_data, _error, variables) => {
135-
queryClient.invalidateQueries({ queryKey: authzQueryKeys.library(variables.libraryId) });
136-
},
137-
});
138-
};

src/authz-module/libraries-manager/LibrariesTeamManager.test.tsx

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -150,49 +150,6 @@ describe('LibrariesTeamManager', () => {
150150
expect(matrixScope.getByText('view')).toBeInTheDocument();
151151
});
152152

153-
it('renders allow public library read toggle and change the value by user interaction', async () => {
154-
const user = userEvent.setup();
155-
156-
renderTeamManager();
157-
158-
const readPublicToggle = await screen.findByRole('switch', { name: /Allow public read/i });
159-
160-
await user.click(readPublicToggle);
161-
expect(mutate).toHaveBeenCalledWith(
162-
{
163-
libraryId: 'lib-001',
164-
updatedData: { allowPublicRead: !libraryData.allowPublicRead },
165-
},
166-
expect.objectContaining({
167-
onSuccess: expect.any(Function),
168-
}),
169-
);
170-
const { onSuccess } = (mutate as jest.Mock).mock.calls[0][1];
171-
onSuccess?.();
172-
173-
expect(await screen.findByText(/updated successfully/i)).toBeInTheDocument();
174-
});
175-
176-
it('should not render the toggle if the user can not manage team and the Library Public Read is disabled', () => {
177-
(useLibrary as jest.Mock).mockReturnValue({ data: { ...libraryData, allowPublicRead: false } });
178-
(useLibraryAuthZ as jest.Mock).mockReturnValue({ ...libraryAuthZContext, canManageTeam: false });
179-
180-
renderTeamManager();
181-
expect(screen.queryByRole('switch', { name: /Allow public read/i })).not.toBeInTheDocument();
182-
});
183-
184-
it('should render the toggle as disabled if the user can not manage team but the Library Public Read is enabled', async () => {
185-
(useLibrary as jest.Mock).mockReturnValue({ data: { ...libraryData, allowPublicRead: true } });
186-
(useLibraryAuthZ as jest.Mock).mockReturnValue({ ...libraryAuthZContext, canManageTeam: false });
187-
188-
renderTeamManager();
189-
190-
const readPublicToggle = await screen.findByRole('switch', { name: /Allow public read/i });
191-
192-
expect(readPublicToggle).toBeInTheDocument();
193-
expect(readPublicToggle).toBeDisabled();
194-
});
195-
196153
it('renders correct navigation link label and URL on breadcrumb', () => {
197154
renderTeamManager();
198155
const navLink = screen.getByRole('link', { name: 'Manage Access' });

src/authz-module/libraries-manager/LibrariesTeamManager.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { AddNewTeamMemberTrigger } from './components/AddNewTeamMemberModal';
1515
import { buildPermissionMatrixByResource, buildPermissionMatrixByRole } from './utils';
1616

1717
import messages from './messages';
18-
import PublicReadToggle from './components/PublicReadToggle';
1918

2019
const LibrariesTeamManager = () => {
2120
const intl = useIntl();
@@ -51,7 +50,7 @@ const LibrariesTeamManager = () => {
5150
pageTitle={pageTitle}
5251
pageSubtitle={libraryId}
5352
actions={
54-
[<PublicReadToggle libraryId={libraryId} canEditToggle={canManageTeam} key="allow-public-read" />,
53+
[
5554
...(canManageTeam ? [<AddNewTeamMemberTrigger libraryId={libraryId} key="add-new-member" />] : []),
5655
]
5756
}

src/authz-module/libraries-manager/LibrariesUserManager.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ describe('LibrariesUserManager', () => {
133133
expect(screen.getByText('Library Team Management')).toBeInTheDocument();
134134
expect(screen.getByRole('listitem', { current: 'page' })).toHaveTextContent('testuser');
135135
// Page title and subtitle
136-
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('testuser');
137-
expect(screen.getByRole('paragraph')).toHaveTextContent('testuser@example.com');
136+
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent('testuser');
137+
expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('testuser@example.com');
138138

139139
expect(screen.getByText('Admin')).toBeInTheDocument();
140140
expect(screen.getByText('Instructor')).toBeInTheDocument();

src/authz-module/libraries-manager/LibrariesUserManager.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ const LibrariesUserManager = () => {
152152
navLinks={[{ label: rootBreadcrumb, to: teamMembersPath }, { label: pageManageTitle, to: teamMembersPath }]}
153153
activeLabel={user?.username || ''}
154154
pageTitle={user?.username || ''}
155-
pageSubtitle={<p>{user?.email}</p>}
155+
pageSubtitle={user?.email || ''}
156156
actions={user && canManageTeam
157157
? [<AssignNewRoleTrigger
158158
username={user.username}

0 commit comments

Comments
 (0)