Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
5 changes: 0 additions & 5 deletions src/Main.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,4 @@ describe('Main', () => {
const { getByTestId } = renderWrapper(<Main />);
expect(getByTestId('authz-module')).toBeInTheDocument();
});

it('wraps the body in an xl container to align it with the header', () => {
const { getByTestId } = renderWrapper(<Main />);
expect(getByTestId('authz-module').closest('.container-mw-xl')).toBeInTheDocument();
});
});
5 changes: 1 addition & 4 deletions src/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CurrentAppProvider, PageWrap, getSiteConfig, useIntl } from '@openedx/frontend-base';
import { Container } from '@openedx/paragon';
import { Helmet } from 'react-helmet';

import { appId } from './constants';
Expand All @@ -20,9 +19,7 @@ const Main = () => {
</title>
</Helmet>
<PageWrap>
<Container size="xl" fluid className="px-0">
<AuthZModule />
</Container>
<AuthZModule />
</PageWrap>
</CurrentAppProvider>
);
Expand Down
18 changes: 5 additions & 13 deletions src/authz-module/audit-user/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import {
useContext, useEffect, useMemo, useState,
} from 'react';
import { SiteContext, useIntl } from '@openedx/frontend-base';
import {
Container, DataTable,
} from '@openedx/paragon';
import { DataTable } from '@openedx/paragon';
import TableFooter from '@src/authz-module/components/TableFooter/TableFooter';
import {
AUTHZ_HOME_PATH, TABLE_DEFAULT_PAGE_SIZE,
Expand Down Expand Up @@ -228,7 +226,7 @@ const AuditUserPage = () => {
};

return (
<div className="authz-module">
<>
<ConfirmDeletionModal
isOpen={showConfirmDeletionModal}
close={handleCloseConfirmDeletionModal}
Expand All @@ -243,11 +241,6 @@ const AuditUserPage = () => {
}}
/>
<AuthZLayout
context={{
id: '',
org: '',
title: '',
}}
navLinks={navLinks}
activeLabel={user?.username || ''}
pageTitle={user?.username || ''}
Expand All @@ -258,7 +251,7 @@ const AuditUserPage = () => {
]
}
>
<Container className="bg-light-200 p-5">
<div className="page-band py-5">
<DataTable
isPaginated
isFilterable
Expand All @@ -283,10 +276,9 @@ const AuditUserPage = () => {
<DataTable.Table />
<TableFooter />
</DataTable>

</Container>
</div>
</AuthZLayout>
</div>
</>
);
};

Expand Down
40 changes: 18 additions & 22 deletions src/authz-module/authz-home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,25 @@ const AuthzHome = () => {
const pageTitle = intl.formatMessage(messages['authz.manage.page.title']);

return (
<div className="authz-module">
<AuthZLayout
context={{ id: '', title: '', org: '' }}
pageTitle={pageTitle}
pageSubtitle=""
actions={
[<AddRoleButton key="add-role-button" />]
}
<AuthZLayout
pageTitle={pageTitle}
actions={
[<AddRoleButton key="add-role-button" />]
}
>
<Tabs
variant="tabs"
defaultActiveKey={hash ? 'permissionsRoles' : 'team'}
className="page-band bg-light-100"
>
<Tabs
variant="tabs"
defaultActiveKey={hash ? 'permissionsRoles' : 'team'}
className="bg-light-100 px-5"
>
<Tab eventKey="team" title={intl.formatMessage(messages['authz.tabs.team'])} className="p-5 bg-light-200">
<TeamMembersTable presetScope={presetScope} />
</Tab>
<Tab id="libraries-permissions-roles-tab" eventKey="permissionsRoles" title={intl.formatMessage(messages['authz.tabs.permissionsRoles'])}>
<RolesPermissions />
</Tab>
</Tabs>
</AuthZLayout>
</div>
<Tab eventKey="team" title={intl.formatMessage(messages['authz.tabs.team'])} className="page-band py-5">
<TeamMembersTable presetScope={presetScope} />
</Tab>
<Tab id="libraries-permissions-roles-tab" eventKey="permissionsRoles" title={intl.formatMessage(messages['authz.tabs.permissionsRoles'])} className="page-band py-5">
<RolesPermissions />
</Tab>
</Tabs>
</AuthZLayout>
);
};

Expand Down
24 changes: 13 additions & 11 deletions src/authz-module/components/AuthZLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ import AuthZTitle, { AuthZTitleProps } from './AuthZTitle';

interface AuthZLayoutProps extends AuthZTitleProps {
children: ReactNode;
context: {
id: string;
org: string;
title: string;
};
}

const AuthZLayout = ({ children, ...props }: AuthZLayoutProps) => (
<>
<AuthZTitle {...props} />
{children}
</>

/**
* Page chrome for the authz module: the title band, then the body below it.
* The body only paints its colour, edge to edge. Each page marks the parts of its
* content that should line up with the header using `page-band`, so anything meant
* to bleed across the full width -- a stepper header, a toolbar -- simply omits it.
*/
const AuthZLayout = ({ children, ...titleProps }: AuthZLayoutProps) => (
<div className="authz-module">
<AuthZTitle {...titleProps} />
<div className="bg-light-200">
{children}
</div>
</div>
);

export default AuthZLayout;
2 changes: 0 additions & 2 deletions src/authz-module/components/AuthZTitle.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ describe('AuthZTitle', () => {
const defaultProps = {
activeLabel: 'Current Page',
pageTitle: 'Page Title',
pageSubtitle: 'Page Subtitle',
};

it('renders without optional fields', () => {
render(<AuthZTitle {...defaultProps} />);
expect(screen.getByText(defaultProps.activeLabel)).toBeInTheDocument();
expect(screen.getByText(defaultProps.pageTitle)).toBeInTheDocument();
expect(screen.getByText(defaultProps.pageSubtitle as string)).toBeInTheDocument();
});

it('renders breadcrumb with links and active label', () => {
Expand Down
16 changes: 8 additions & 8 deletions src/authz-module/components/AuthZTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
} from 'react';
import { Link } from 'react-router-dom';
import {
Breadcrumb, Col, Container, Row, Button,
Breadcrumb, Col, Row, Button,
Stack,
useMediaQuery,
breakpoints,
Expand All @@ -23,7 +23,7 @@ interface Action {
export interface AuthZTitleProps {
activeLabel?: string;
pageTitle: string;
pageSubtitle: string | ReactNode;
pageSubtitle?: string | ReactNode;
navLinks?: BreadcrumbLink[];
actions?: (Action | ReactNode)[];
}
Expand All @@ -38,11 +38,11 @@ export const ActionButton = ({ label, icon, onClick }: Action) => (
);

const AuthZTitle = ({
activeLabel, navLinks = [], pageTitle, pageSubtitle, actions = [],
activeLabel, navLinks = [], pageTitle, pageSubtitle = '', actions = [],
}: AuthZTitleProps) => {
const isDesktop = useMediaQuery({ minWidth: breakpoints.large.minWidth });
return (
<Container className="p-5 bg-light-100">
<div className="page-band py-5 bg-light-100">
<Breadcrumb
linkAs={Link}
links={navLinks}
Expand All @@ -53,8 +53,8 @@ const AuthZTitle = ({
<div className="d-flex align-items-center flex-column-sm">
<h2 className="text-primary mb-0">{pageTitle}</h2>
{typeof pageSubtitle === 'string'
? <> { pageSubtitle !== '' && <hr className="mx-lg-3" /> }<h3 className="mb-0 py-2 font-weight-light text-gray-700">{pageSubtitle}</h3></>
: <>{ pageSubtitle !== '' && <hr className="mx-lg-3" /> } <div className="mb-0">{pageSubtitle}</div></>}
? <> { pageSubtitle !== '' && <hr className="authz-action-divider mx-lg-3" /> }<h3 className="mb-0 py-2 font-weight-light text-gray-700">{pageSubtitle}</h3></>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: with no subtitle this still renders an empty <h3> (axe empty-heading). Consider rendering nothing when pageSubtitle is falsy.

: <>{ pageSubtitle !== '' && <hr className="authz-action-divider mx-lg-3" /> } <div className="mb-0">{pageSubtitle}</div></>}

</div>
</Col>
Expand All @@ -72,15 +72,15 @@ const AuthZTitle = ({
<Fragment key={`authz-header-action-${key}`}>
{content}
{(index === actions.length - 1) ? null
: (<hr className="mx-lg-5" />)}
: (<hr className="authz-action-divider mx-lg-5" />)}
</Fragment>
);
})
}
</Stack>
</Col>
</Row>
</Container>
</div>
);
};

Expand Down
4 changes: 3 additions & 1 deletion src/authz-module/components/PermissionTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ interface PermissionTableProps {
const PermissionTable = ({ permissionsTable, roles, title }: PermissionTableProps) => {
const { formatMessage } = useIntl();
return (
<Card>
// The matrix is wider than a narrow viewport once it has a few role columns, so the
// card scrolls rather than letting the table overflow with no way to reach it.
<Card className="overflow-auto">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overflow-auto makes the Card the scroll container for the sticky-top headers below, so they no longer pin to the viewport at any width. Scope the scroll to small breakpoints with a media query, or drop sticky-top.

<table className="permission-table w-100">
<thead>
<tr>
Expand Down
11 changes: 2 additions & 9 deletions src/authz-module/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,12 @@
min-height: 700px;
}

hr {
.authz-action-divider {
border-right: var(--pgn-size-border-width) solid var(--pgn-color-border);
height: var(--height-action-divider);
width: 0;
}

.tab-content {
background-color: var(--pgn-color-light-200);
}

.collapsible-card {
border: none;

Expand Down Expand Up @@ -71,7 +67,7 @@
.flex-column-sm {
flex-direction: column;
}
hr {
.authz-action-divider {
border-top: var(--pgn-size-border-width) solid var(--pgn-color-border);
border-right: none;
width: 100%;
Expand Down Expand Up @@ -126,6 +122,3 @@
max-height: 500px;
}

.scope-search-input {
width: 18.75rem; // 300px
}
4 changes: 2 additions & 2 deletions src/authz-module/role-assignation-wizard/AssignRoleWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ const AssignRoleWizard = ({
<Stepper activeKey={activeStep}>
<Stepper.Header className="bg-info-100" />

<div className="bg-light-200 p-5">
<div className="page-band py-5">
<Stepper.Step
eventKey={STEPS.SELECT_USERS_AND_ROLE}
title={intl.formatMessage(messages['wizard.step.selectUsersAndRole.title'])}
Expand Down Expand Up @@ -191,7 +191,7 @@ const AssignRoleWizard = ({
</Stepper.Step>
</div>

<div className="p-5">
<div className="page-band py-5">
<Stepper.ActionRow eventKey={STEPS.SELECT_USERS_AND_ROLE}>
<Button variant="outline-primary" onClick={handleClose}>
{intl.formatMessage(messages['wizard.button.cancel'])}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,9 @@ const AssignRoleWizardPage = () => {

return (
<AuthZLayout
context={{ id: '', title: '', org: '' }}
navLinks={[{ label: intl.formatMessage(messages['wizard.page.breadcrumb']), to: returnTo }]}
activeLabel={intl.formatMessage(messages['wizard.page.title'])}
pageTitle={intl.formatMessage(messages['wizard.page.title'])}
pageSubtitle=""
actions={[]}
>
<AssignRoleWizard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,16 @@ const ScopeFilterBar = ({
return (
<>
<div className="d-flex align-items-center justify-content-between gap-3 mb-2 flex-wrap">
<div className="d-flex align-items-center gap-3">
<div className="scope-search-input">
<Form.Group controlId="scope-search" className="mb-0">
<Form.Control
type="text"
value={search}
onChange={(e: ChangeEvent<HTMLInputElement>) => onSearchChange(e.target.value)}
placeholder={intl.formatMessage(messages['wizard.step2.search.placeholder'])}
trailingElement={<Icon src={Search} />}
/>
</Form.Group>
</div>
<div className="d-flex align-items-center gap-3 flex-wrap">
<Form.Group controlId="scope-search" className="mb-0">
<Form.Control
type="text"
value={search}
onChange={(e: ChangeEvent<HTMLInputElement>) => onSearchChange(e.target.value)}
placeholder={intl.formatMessage(messages['wizard.step2.search.placeholder'])}
trailingElement={<Icon src={Search} />}
/>
</Form.Group>

<OrgFilter
filterButtonText={intl.formatMessage(messages['wizard.step2.filter.org.label'])}
Expand Down
10 changes: 5 additions & 5 deletions src/authz-module/roles-permissions/RolesPermissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const RolesPermissions = () => {
}, [intl]);

return (
<Container className="p-5">
<>
<Container className="pb-5">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the outer Container gone, this one is centred with Paragon's breakpoint max-widths, so the toggle drifts up to ~100px right of the table at tablet widths. A plain <div className="pb-5"> fixes it.

<ButtonGroup size="lg" className="mb-2">
<Button
Expand Down Expand Up @@ -80,15 +80,15 @@ const RolesPermissions = () => {
variant="info"
className="mt-5"
>
<div className="row align-items-center">
<div className="col col-7">
<div className="row align-items-center flex-wrap">
<div className="col col-md-7">
<p className="text-primary font-weight-bold h4">{intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.title'])}</p>
<span>
<span className="font-weight-bold">{intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.note'])}</span>
{intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.description'])}
</span>
</div>
<div className="col col-5">
<div className="col col-md-5 mt-3 mt-md-0">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.col is flex: 1 0 0, so these still sit 50/50 below md (and flex-wrap is already the .row default). col-12 col-md-7 / col-12 col-md-5 will stack them.

<Hyperlink className="d-block text-right h5 font-weight-normal" destination="https://docs.openedx.org/en/latest/educators/references/course_development/course_team_roles.html" target="_blank" showLaunchIcon={false} isInline>
{intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.link'])}
</Hyperlink>
Expand All @@ -106,7 +106,7 @@ const RolesPermissions = () => {
/>
)}
<AnchorButton />
</Container>
</>
);
};

Expand Down
Loading
Loading