Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions src/authz-module/components/RoleCard/PermissionsRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,25 @@ interface PermissionRowProps {

const PermissionRow = ({ resourceLabel, actions }: PermissionRowProps) => (
<Row className="row align-items-center border px-2 py-2">
<Col md={3}>
<Col md={2}>
<span className="small font-weight-bold">{resourceLabel}</span>
</Col>
<Col>
<div className="w-100 d-flex flex-wrap">
{actions.map(action => (
<Chip
key={action.key}
iconBefore={actionsDictionary[action.key as ActionKey] as ComponentType}
disabled={action.disabled}
className="mr-4 my-2 px-3 bg-primary-100 border-0 permission-chip"
variant="light"
>
{action.label}
</Chip>
<div className="w-100 d-flex flex-wrap align-items-center">
{actions.map((action, index) => (
<>
<Chip
key={action.key}
iconBefore={actionsDictionary[action.key as ActionKey] as ComponentType}
disabled={action.disabled}
className="mx-3 my-2 px-3 bg-primary-100 border-0 permission-chip"
variant="light"
>
{action.label}
</Chip>
{(index === actions.length - 1) ? null
: (<hr className="border-right mx-2" style={{ height: '24px' }} />)}
</>
))}
</div>
</Col>
Expand Down
2 changes: 1 addition & 1 deletion src/authz-module/components/RoleCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface RoleCardProps extends CardTitleProps {
permissions: any[];
}

const CardTitle = ({ title, userCounter }: CardTitleProps) => (
const CardTitle = ({ title, userCounter = null }: CardTitleProps) => (
<div className="d-flex align-items-center">
<span className="mr-4 text-primary">{title}</span>
{userCounter !== null && (
Expand Down
2 changes: 1 addition & 1 deletion src/authz-module/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
44 changes: 42 additions & 2 deletions src/authz-module/libraries-manager/LibrariesTeamManager.test.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -29,6 +30,17 @@ jest.mock('./components/AddNewTeamMemberModal', () => ({
AddNewTeamMemberTrigger: () => <div data-testid="add-team-member-trigger">MockAddNewTeamMemberTrigger</div>,
}));

jest.mock('../components/RoleCard', () => ({
__esModule: true,
default: ({ title, description, permissions }: { title: string, description: string, permissions: any[] }) => (
<div data-testid="role-card">
<div>{title}</div>
<div>{description}</div>
<div>{permissions.length} permissions</div>
</div>
),
}));

describe('LibrariesTeamManager', () => {
beforeEach(() => {
initializeMockApp({
Expand All @@ -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,
});

Expand Down Expand Up @@ -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(<LibrariesTeamManager />);

// 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();
});
});
31 changes: 28 additions & 3 deletions src/authz-module/libraries-manager/LibrariesTeamManager.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="authz-libraries">
<AuthZLayout
Expand All @@ -39,7 +53,18 @@ const LibrariesTeamManager = () => {
<TeamTable />
</Tab>
<Tab eventKey="roles" title={intl.formatMessage(messages['library.authz.tabs.roles'])}>
Role tab.
<Container className="p-5">
{!libraryRoles ? <Skeleton count={2} height={200} /> : null}
{libraryRoles && libraryRoles.map(role => (
<RoleCard
key={`${role.role}-description`}
title={role.name}
userCounter={role.userCount}
description={role.description}
permissions={role.permissions as any[]}
/>
))}
</Container>
</Tab>
<Tab id="libraries-permissions-tab" eventKey="permissions" title={intl.formatMessage(messages['library.authz.tabs.permissions'])}>
Permissions tab.
Expand Down