diff --git a/src/authz-module/components/RoleCard/PermissionsRow.tsx b/src/authz-module/components/RoleCard/PermissionsRow.tsx index 7c1a007..aad0ebb 100644 --- a/src/authz-module/components/RoleCard/PermissionsRow.tsx +++ b/src/authz-module/components/RoleCard/PermissionsRow.tsx @@ -17,21 +17,25 @@ interface PermissionRowProps { const PermissionRow = ({ resourceLabel, actions }: PermissionRowProps) => ( - + {resourceLabel} -
- {actions.map(action => ( - - {action.label} - +
+ {actions.map((action, index) => ( + <> + + {action.label} + + {(index === actions.length - 1) ? null + : (
)} + ))}
diff --git a/src/authz-module/components/RoleCard/index.tsx b/src/authz-module/components/RoleCard/index.tsx index 9b2f9f3..1c15466 100644 --- a/src/authz-module/components/RoleCard/index.tsx +++ b/src/authz-module/components/RoleCard/index.tsx @@ -18,7 +18,7 @@ interface RoleCardProps extends CardTitleProps { permissions: any[]; } -const CardTitle = ({ title, userCounter }: CardTitleProps) => ( +const CardTitle = ({ title, userCounter = null }: CardTitleProps) => (
{title} {userCounter !== null && ( diff --git a/src/authz-module/index.scss b/src/authz-module/index.scss index ab98fc3..790adc8 100644 --- a/src/authz-module/index.scss +++ b/src/authz-module/index.scss @@ -29,7 +29,7 @@ font-weight: var(--pgn-typography-font-weight-base); } - svg { + .pgn__icon { width: var(--pgn-size-icon-xs); height: var(--pgn-size-icon-xs); } diff --git a/src/authz-module/libraries-manager/LibrariesTeamManager.test.tsx b/src/authz-module/libraries-manager/LibrariesTeamManager.test.tsx index bbbb7ff..be558e3 100644 --- a/src/authz-module/libraries-manager/LibrariesTeamManager.test.tsx +++ b/src/authz-module/libraries-manager/LibrariesTeamManager.test.tsx @@ -1,4 +1,5 @@ import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { renderWrapper } from '@src/setupTest'; import { initializeMockApp } from '@edx/frontend-platform/testing'; import { useLibrary } from '@src/authz-module/data/hooks'; @@ -29,6 +30,17 @@ jest.mock('./components/AddNewTeamMemberModal', () => ({ AddNewTeamMemberTrigger: () =>
MockAddNewTeamMemberTrigger
, })); +jest.mock('../components/RoleCard', () => ({ + __esModule: true, + default: ({ title, description, permissions }: { title: string, description: string, permissions: any[] }) => ( +
+
{title}
+
{description}
+
{permissions.length} permissions
+
+ ), +})); + describe('LibrariesTeamManager', () => { beforeEach(() => { initializeMockApp({ @@ -41,8 +53,19 @@ describe('LibrariesTeamManager', () => { libraryName: 'Mock Library', libraryOrg: 'MockOrg', username: 'mockuser', - roles: ['admin'], - permissions: [], + roles: [ + { + name: 'Instructor', + description: 'Can manage content.', + userCount: 3, + permissions: ['view', 'edit'], + }, + ], + permissions: [ + { key: 'view_library', label: 'view', resource: 'library' }, + { key: 'edit_library', name: 'edit', resource: 'library' }, + ], + resources: [{ key: 'library', displayName: 'Library' }], canManageTeam: true, }); @@ -72,4 +95,21 @@ describe('LibrariesTeamManager', () => { // AddNewTeamMemberTrigger is rendered expect(screen.getByTestId('add-team-member-trigger')).toBeInTheDocument(); }); + + it('renders role cards when "Roles" tab is selected', async () => { + const user = userEvent.setup(); + + renderWrapper(); + + // Click on "Roles" tab + const rolesTab = await screen.findByRole('tab', { name: /roles/i }); + await user.click(rolesTab); + + const roleCards = await screen.findAllByTestId('role-card'); + + expect(roleCards.length).toBeGreaterThan(0); + expect(screen.getByText('Instructor')).toBeInTheDocument(); + expect(screen.getByText(/Can manage content/i)).toBeInTheDocument(); + expect(screen.getByText(/1 permissions/i)).toBeInTheDocument(); + }); }); diff --git a/src/authz-module/libraries-manager/LibrariesTeamManager.tsx b/src/authz-module/libraries-manager/LibrariesTeamManager.tsx index 9595ce8..dd9fc2c 100644 --- a/src/authz-module/libraries-manager/LibrariesTeamManager.tsx +++ b/src/authz-module/libraries-manager/LibrariesTeamManager.tsx @@ -1,21 +1,35 @@ +import { useMemo } from 'react'; import { useIntl } from '@edx/frontend-platform/i18n'; -import { Tab, Tabs } from '@openedx/paragon'; +import { + Container, Skeleton, Tab, Tabs, +} from '@openedx/paragon'; import { useLibrary } from '@src/authz-module/data/hooks'; import { useLocation } from 'react-router-dom'; import TeamTable from './components/TeamTable'; import AuthZLayout from '../components/AuthZLayout'; +import RoleCard from '../components/RoleCard'; import { useLibraryAuthZ } from './context'; import { AddNewTeamMemberTrigger } from './components/AddNewTeamMemberModal'; +import { buildPermissionsByRoleMatrix } from './utils'; import messages from './messages'; const LibrariesTeamManager = () => { const intl = useIntl(); const { hash } = useLocation(); - const { libraryId, canManageTeam } = useLibraryAuthZ(); + const { + libraryId, canManageTeam, roles, permissions, resources, + } = useLibraryAuthZ(); const { data: library } = useLibrary(libraryId); const rootBradecrumb = intl.formatMessage(messages['library.authz.breadcrumb.root']) || ''; const pageTitle = intl.formatMessage(messages['library.authz.manage.page.title']); + const libraryRoles = useMemo(() => roles.map(role => ({ + ...role, + permissions: buildPermissionsByRoleMatrix({ + rolePermissions: role.permissions, permissions, resources, intl, + }), + })), [roles, permissions, resources, intl]); + return (
{ - Role tab. + + {!libraryRoles ? : null} + {libraryRoles && libraryRoles.map(role => ( + + ))} + Permissions tab.