1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00

fix: improve HTML landmarks (#886)

* fix: improve HTML landmarks

* refactor: footer headers should use h2

* refactor: fix header order on the feature overview page

* fix: make drawer logo clickable

* fix: wrap header links in <nav>

* fix: label breadcrumbs nav element

* refactor: remove unused breadcrumb.jsx

* fix: add search role to SearchField

* fix: correct heading order on form pages
This commit is contained in:
olav 2022-04-21 09:52:43 +02:00 committed by GitHub
parent 73c601cc7b
commit ff0d55b6cc
25 changed files with 331 additions and 408 deletions

View File

@ -40,7 +40,10 @@ const BreadcrumbNav = () => {
<ConditionallyRender <ConditionallyRender
condition={paths.length > 1} condition={paths.length > 1}
show={ show={
<Breadcrumbs className={styles.breadcrumbNav}> <Breadcrumbs
className={styles.breadcrumbNav}
aria-label="Breadcrumbs"
>
{paths.map((path, index) => { {paths.map((path, index) => {
const lastItem = index === paths.length - 1; const lastItem = index === paths.length - 1;
if (lastItem) { if (lastItem) {

View File

@ -84,7 +84,7 @@ const FormTemplate: React.FC<ICreateProps> = ({
show={<Loader />} show={<Loader />}
elseShow={ elseShow={
<> <>
<h2 className={styles.title}>{title}</h2> <h1 className={styles.title}>{title}</h1>
{children} {children}
</> </>
} }
@ -98,14 +98,14 @@ const FormTemplate: React.FC<ICreateProps> = ({
documentationLink={documentationLink} documentationLink={documentationLink}
documentationLinkLabel={documentationLinkLabel} documentationLinkLabel={documentationLinkLabel}
> >
<h3 className={styles.subtitle}> <h2 className={styles.subtitle}>
API Command{' '} API Command{' '}
<Tooltip title="Copy command"> <Tooltip title="Copy command">
<IconButton onClick={copyCommand}> <IconButton onClick={copyCommand}>
<FileCopy className={styles.icon} /> <FileCopy className={styles.icon} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</h3> </h2>
<Codebox text={formatApiCode()} /> <Codebox text={formatApiCode()} />
</Guidance> </Guidance>
} }

View File

@ -22,7 +22,7 @@ const HeaderTitle = ({
<div className={styles.headerTitleContainer}> <div className={styles.headerTitleContainer}>
<div className={headerClasses} data-loading> <div className={headerClasses} data-loading>
<Typography <Typography
variant={variant || 'h2'} variant={variant || 'h1'}
className={classnames(styles.headerTitle, className)} className={classnames(styles.headerTitle, className)}
> >
{title} {title}

View File

@ -46,7 +46,7 @@ export const SearchField = ({
}; };
return ( return (
<div className={styles.container}> <form className={styles.container} role="search">
<div className={classnames(styles.search, className)}> <div className={classnames(styles.search, className)}>
<SearchIcon className={styles.searchIcon} /> <SearchIcon className={styles.searchIcon} />
<InputBase <InputBase
@ -57,6 +57,7 @@ export const SearchField = ({
onChange={handleChange} onChange={handleChange}
onBlur={updateNow} onBlur={updateNow}
onKeyPress={handleKeyPress} onKeyPress={handleKeyPress}
type="search"
/> />
</div> </div>
<ConditionallyRender <ConditionallyRender
@ -69,6 +70,6 @@ export const SearchField = ({
/> />
} }
/> />
</div> </form>
); );
}; };

View File

@ -5,8 +5,9 @@ exports[`renders correctly with one feature 1`] = `
<div <div
className="makeStyles-searchBarContainer-3" className="makeStyles-searchBarContainer-3"
> >
<div <form
className="makeStyles-container-6" className="makeStyles-container-6"
role="search"
> >
<div <div
className="makeStyles-search-7 makeStyles-searchBar-4" className="makeStyles-search-7 makeStyles-searchBar-4"
@ -28,18 +29,18 @@ exports[`renders correctly with one feature 1`] = `
> >
<input <input
aria-label="search" aria-label="search"
className="MuiInputBase-input" className="MuiInputBase-input MuiInputBase-inputTypeSearch"
onAnimationStart={[Function]} onAnimationStart={[Function]}
onBlur={[Function]} onBlur={[Function]}
onChange={[Function]} onChange={[Function]}
onFocus={[Function]} onFocus={[Function]}
placeholder="Search..." placeholder="Search..."
type="text" type="search"
value="" value=""
/> />
</div> </div>
</div> </div>
</div> </form>
<a <a
href="/archive" href="/archive"
onClick={[Function]} onClick={[Function]}
@ -66,11 +67,11 @@ exports[`renders correctly with one feature 1`] = `
className="" className=""
data-loading={true} data-loading={true}
> >
<h2 <h1
className="MuiTypography-root makeStyles-headerTitle-15 MuiTypography-h2" className="MuiTypography-root makeStyles-headerTitle-15 MuiTypography-h1"
> >
Features Features
</h2> </h1>
</div> </div>
<div <div
className="makeStyles-headerActions-16" className="makeStyles-headerActions-16"
@ -176,8 +177,9 @@ exports[`renders correctly with one feature without permissions 1`] = `
<div <div
className="makeStyles-searchBarContainer-3" className="makeStyles-searchBarContainer-3"
> >
<div <form
className="makeStyles-container-6" className="makeStyles-container-6"
role="search"
> >
<div <div
className="makeStyles-search-7 makeStyles-searchBar-4" className="makeStyles-search-7 makeStyles-searchBar-4"
@ -199,18 +201,18 @@ exports[`renders correctly with one feature without permissions 1`] = `
> >
<input <input
aria-label="search" aria-label="search"
className="MuiInputBase-input" className="MuiInputBase-input MuiInputBase-inputTypeSearch"
onAnimationStart={[Function]} onAnimationStart={[Function]}
onBlur={[Function]} onBlur={[Function]}
onChange={[Function]} onChange={[Function]}
onFocus={[Function]} onFocus={[Function]}
placeholder="Search..." placeholder="Search..."
type="text" type="search"
value="" value=""
/> />
</div> </div>
</div> </div>
</div> </form>
<a <a
href="/archive" href="/archive"
onClick={[Function]} onClick={[Function]}
@ -237,11 +239,11 @@ exports[`renders correctly with one feature without permissions 1`] = `
className="" className=""
data-loading={true} data-loading={true}
> >
<h2 <h1
className="MuiTypography-root makeStyles-headerTitle-15 MuiTypography-h2" className="MuiTypography-root makeStyles-headerTitle-15 MuiTypography-h1"
> >
Features Features
</h2> </h1>
</div> </div>
<div <div
className="makeStyles-headerActions-16" className="makeStyles-headerActions-16"

View File

@ -30,9 +30,9 @@ const FeatureOverviewMetaData = () => {
<div className={styles.paddingContainerTop}> <div className={styles.paddingContainerTop}>
<div className={styles.metaDataHeader} data-loading> <div className={styles.metaDataHeader} data-loading>
<IconComponent className={styles.headerIcon} />{' '} <IconComponent className={styles.headerIcon} />{' '}
<h3 className={styles.header}> <h2 className={styles.header}>
{capitalize(type || '')} toggle {capitalize(type || '')} toggle
</h3> </h2>
</div> </div>
<div className={styles.body}> <div className={styles.body}>
<span className={styles.bodyItem} data-loading> <span className={styles.bodyItem} data-loading>

View File

@ -119,12 +119,12 @@ export const FeatureView = () => {
<div className={styles.header}> <div className={styles.header}>
<div className={styles.innerContainer}> <div className={styles.innerContainer}>
<div className={styles.toggleInfoContainer}> <div className={styles.toggleInfoContainer}>
<h2 <h1
className={styles.featureViewHeader} className={styles.featureViewHeader}
data-loading data-loading
> >
{feature.name}{' '} {feature.name}{' '}
</h2> </h1>
<ConditionallyRender <ConditionallyRender
condition={!smallScreen} condition={!smallScreen}
show={<StatusChip stale={feature?.stale} />} show={<StatusChip stale={feature?.stale} />}

View File

@ -37,7 +37,7 @@ export const MainLayout = ({ children }: IMainLayoutProps) => {
<> <>
<Header /> <Header />
<Grid container className={muiStyles.container}> <Grid container className={muiStyles.container}>
<div className={classnames(styles.contentWrapper)}> <main className={classnames(styles.contentWrapper)}>
<Grid item className={styles.content} xs={12} sm={12}> <Grid item className={styles.content} xs={12} sm={12}>
<div <div
className={muiStyles.contentContainer} className={muiStyles.contentContainer}
@ -61,7 +61,7 @@ export const MainLayout = ({ children }: IMainLayoutProps) => {
}} }}
/> />
</div> </div>
</div> </main>
<Footer /> <Footer />
</Grid> </Grid>
</> </>

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import renderer from 'react-test-renderer'; import { ApiDetails } from 'component/menu/Footer/ApiDetails/ApiDetails';
import { ApiDetails } from '../Footer/ApiDetails/ApiDetails'; import { render } from 'utils/testRenderer';
test('renders correctly with empty version', () => { test('renders correctly with empty version', () => {
const uiConfig = { const uiConfig = {
@ -10,8 +10,8 @@ test('renders correctly with empty version', () => {
version: '', version: '',
}; };
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON(); render(<ApiDetails uiConfig={uiConfig} />);
expect(tree).toMatchSnapshot(); expect(document.body).toMatchSnapshot();
}); });
test('renders correctly with ui-config', () => { test('renders correctly with ui-config', () => {
@ -22,8 +22,8 @@ test('renders correctly with ui-config', () => {
version: '1.1.0', version: '1.1.0',
}; };
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON(); render(<ApiDetails uiConfig={uiConfig} />);
expect(tree).toMatchSnapshot(); expect(document.body).toMatchSnapshot();
}); });
test('renders correctly without uiConfig', () => { test('renders correctly without uiConfig', () => {
@ -32,8 +32,8 @@ test('renders correctly without uiConfig', () => {
version: '1.1.0', version: '1.1.0',
}; };
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON(); render(<ApiDetails uiConfig={uiConfig} />);
expect(tree).toMatchSnapshot(); expect(document.body).toMatchSnapshot();
}); });
test('renders correctly with versionInfo', () => { test('renders correctly with versionInfo', () => {
@ -48,6 +48,6 @@ test('renders correctly with versionInfo', () => {
}, },
}; };
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON(); render(<ApiDetails uiConfig={uiConfig} />);
expect(tree).toMatchSnapshot(); expect(document.body).toMatchSnapshot();
}); });

View File

@ -5,6 +5,7 @@ import {
formatUpdateNotification, formatUpdateNotification,
IPartialUiConfig, IPartialUiConfig,
} from './apidetails.helpers'; } from './apidetails.helpers';
import { FooterTitle } from 'component/menu/Footer/FooterTitle';
interface IApiDetailsProps { interface IApiDetailsProps {
uiConfig: IPartialUiConfig; uiConfig: IPartialUiConfig;
@ -18,13 +19,13 @@ export const ApiDetails = (props: IApiDetailsProps): ReactElement => {
return ( return (
<section title="API details"> <section title="API details">
<h4> <FooterTitle>
{currentVersion}{' '} {currentVersion}{' '}
<ConditionallyRender <ConditionallyRender
condition={Boolean(environment)} condition={Boolean(environment)}
show={<small>({environment})</small>} show={<small>({environment})</small>}
/> />
</h4> </FooterTitle>
<ConditionallyRender <ConditionallyRender
condition={Boolean(updateNotification)} condition={Boolean(updateNotification)}
show={ show={

View File

@ -0,0 +1,102 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly with empty version 1`] = `
<body>
<div>
<section
title="API details"
>
<h2
class="makeStyles-title-1"
>
Unleash
<small>
(
test
)
</small>
</h2>
<br />
<small>
We are the best!
</small>
<br />
</section>
</div>
</body>
`;
exports[`renders correctly with ui-config 1`] = `
<body>
<div>
<section
title="API details"
>
<h2
class="makeStyles-title-2"
>
Unleash 1.1.0
<small>
(
test
)
</small>
</h2>
<br />
<small>
We are the best!
</small>
<br />
</section>
</div>
</body>
`;
exports[`renders correctly with versionInfo 1`] = `
<body>
<div>
<section
title="API details"
>
<h2
class="makeStyles-title-4"
>
Unleash 1.2.3
</h2>
<small>
Upgrade available - Latest Enterprise release: 1.2.4
<br />
</small>
<br />
<small />
<br />
<small>
1
</small>
</section>
</div>
</body>
`;
exports[`renders correctly without uiConfig 1`] = `
<body>
<div>
<section
title="API details"
>
<h2
class="makeStyles-title-3"
>
Unleash 1.1.0
</h2>
<br />
<small />
<br />
</section>
</div>
</body>
`;

View File

@ -4,6 +4,7 @@ import { List, ListItem, ListItemText, Grid } from '@material-ui/core';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ApiDetails } from './ApiDetails/ApiDetails'; import { ApiDetails } from './ApiDetails/ApiDetails';
import { useStyles } from './Footer.styles'; import { useStyles } from './Footer.styles';
import { FooterTitle } from './FooterTitle';
export const Footer = () => { export const Footer = () => {
const styles = useStyles(); const styles = useStyles();
@ -24,7 +25,7 @@ export const Footer = () => {
<Grid container spacing={7} direction="row"> <Grid container spacing={7} direction="row">
<Grid item> <Grid item>
<section title="Unleash SDK"> <section title="Unleash SDK">
<h4>Server SDKs</h4> <FooterTitle>Server SDKs</FooterTitle>
<List className={styles.list} dense> <List className={styles.list} dense>
<ListItem className={styles.listItem}> <ListItem className={styles.listItem}>
<ListItemText <ListItemText
@ -135,7 +136,7 @@ export const Footer = () => {
</Grid> </Grid>
<Grid item> <Grid item>
<section title="Unleash SDK"> <section title="Unleash SDK">
<h4>Frontend SDKs</h4> <FooterTitle>Frontend SDKs</FooterTitle>
<List className={styles.list} dense> <List className={styles.list} dense>
<ListItem className={styles.listItem}> <ListItem className={styles.listItem}>
<ListItemText <ListItemText
@ -207,7 +208,7 @@ export const Footer = () => {
</Grid> </Grid>
<Grid item> <Grid item>
<section> <section>
<h4>About</h4> <FooterTitle>About</FooterTitle>
<List className={styles.list} dense> <List className={styles.list} dense>
<ListItem className={styles.listItem}> <ListItem className={styles.listItem}>
<ListItemText <ListItemText

View File

@ -0,0 +1,11 @@
import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({
title: {
all: 'unset',
display: 'block',
margin: '1rem 0',
fontSize: '1rem',
fontWeight: theme.fontWeight.bold,
},
}));

View File

@ -0,0 +1,12 @@
import { ReactNode } from 'react';
import { useStyles } from 'component/menu/Footer/FooterTitle.styles';
interface IFooterTitleProps {
children: ReactNode;
}
export const FooterTitle = ({ children }: IFooterTitleProps) => {
const styles = useStyles();
return <h2 className={styles.title}>{children}</h2>;
};

View File

@ -28,6 +28,11 @@ export const useStyles = makeStyles(theme => ({
padding: '0', padding: '0',
}, },
}, },
nav: {
display: 'flex',
alignItems: 'center',
flexGrow: 1,
},
drawerButton: { drawerButton: {
color: '#000', color: '#000',
}, },

View File

@ -59,123 +59,107 @@ const Header = () => {
adminRoutes: routes.adminRoutes.filter(filterByFlags(flags)), adminRoutes: routes.adminRoutes.filter(filterByFlags(flags)),
}; };
return ( if (smallScreen) {
<> return (
<AppBar className={styles.header} position="static"> <>
<Container className={styles.container}> <AppBar className={styles.header} position="static">
<ConditionallyRender <Container className={styles.container}>
condition={smallScreen} <Tooltip title="Menu">
show={ <IconButton
<Tooltip title="Menu"> className={styles.drawerButton}
<IconButton onClick={toggleDrawer}
className={styles.drawerButton} aria-controls="header-drawer"
onClick={toggleDrawer} aria-expanded={openDrawer}
>
<MenuIcon />
</IconButton>
</Tooltip>
}
elseShow={
<Link
to="/"
className={commonStyles.flexRow}
aria-label="Home"
> >
<UnleashLogo <MenuIcon />
className={styles.logo} </IconButton>
aria-label="Unleash logo" </Tooltip>
/> <DrawerMenu
</Link> title={name}
} flags={flags}
/> links={links}
open={openDrawer}
toggleDrawer={toggleDrawer}
admin={admin}
routes={filteredMainRoutes}
/>
<div className={styles.userContainer}>
<UserProfile />
</div>
</Container>
</AppBar>
</>
);
}
<DrawerMenu return (
title={name} <AppBar className={styles.header} position="static">
flags={flags} <Container className={styles.container}>
links={links} <Link to="/" className={commonStyles.flexRow} aria-label="Home">
open={openDrawer} <UnleashLogo
toggleDrawer={toggleDrawer} className={styles.logo}
admin={admin} aria-label="Unleash logo"
routes={filteredMainRoutes}
/> />
<ConditionallyRender </Link>
condition={!smallScreen} <nav className={styles.nav}>
show={ <div className={styles.links}>
<div className={styles.links}> <Link to="/projects">Projects</Link>
<Link to="/projects">Projects</Link> <Link to="/features">Feature toggles</Link>
<Link to="/features">Feature toggles</Link>
<button <button
className={styles.advancedNavButton} className={styles.advancedNavButton}
onClick={e => onClick={e => setAnchorElAdvanced(e.currentTarget)}
setAnchorElAdvanced(e.currentTarget) >
} Configure
> <KeyboardArrowDown />
Configure </button>
<KeyboardArrowDown /> <NavigationMenu
</button> id="settings-navigation"
<NavigationMenu options={filteredMainRoutes.mainNavRoutes}
id="settings-navigation" anchorEl={anchorElAdvanced}
options={filteredMainRoutes.mainNavRoutes} handleClose={handleCloseAdvanced}
anchorEl={anchorElAdvanced} style={{ top: '30px', left: '-55px' }}
handleClose={handleCloseAdvanced} />
style={{ top: '30px', left: '-55px' }} </div>
/>
</div>
}
/>
<div className={styles.userContainer}> <div className={styles.userContainer}>
<Tooltip title="Go to the documentation">
<a
href="https://docs.getunleash.io/"
target="_blank"
rel="noopener noreferrer"
className={styles.docsLink}
>
<MenuBookIcon className={styles.docsIcon} />
</a>
</Tooltip>
<ConditionallyRender <ConditionallyRender
condition={!smallScreen} condition={admin}
show={ show={
<> <Tooltip title="Settings">
<Tooltip title="Go to the documentation"> <IconButton
<a onClick={e =>
href="https://docs.getunleash.io/" setAnchorEl(e.currentTarget)
target="_blank"
rel="noopener noreferrer"
className={styles.docsLink}
>
<MenuBookIcon
className={styles.docsIcon}
/>
</a>
</Tooltip>
<ConditionallyRender
condition={admin}
show={
<Tooltip title="Settings">
<IconButton
onClick={e =>
setAnchorEl(
e.currentTarget
)
}
>
<SettingsIcon
className={
styles.docsIcon
}
/>
</IconButton>
</Tooltip>
} }
/> >
<NavigationMenu <SettingsIcon
id="admin-navigation" className={styles.docsIcon}
options={filteredMainRoutes.adminRoutes} />
anchorEl={anchorEl} </IconButton>
handleClose={handleClose} </Tooltip>
style={{ top: '40px', left: '-125px' }}
/>
</>
} }
/> />
<NavigationMenu
id="admin-navigation"
options={filteredMainRoutes.adminRoutes}
anchorEl={anchorEl}
handleClose={handleClose}
style={{ top: '40px', left: '-125px' }}
/>{' '}
<UserProfile /> <UserProfile />
</div> </div>
</Container> </nav>
</AppBar> </Container>
</> </AppBar>
); );
}; };

View File

@ -1,78 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly with empty version 1`] = `
<section
title="API details"
>
<h4>
Unleash
<small>
(
test
)
</small>
</h4>
<br />
<small>
We are the best!
</small>
<br />
</section>
`;
exports[`renders correctly with ui-config 1`] = `
<section
title="API details"
>
<h4>
Unleash 1.1.0
<small>
(
test
)
</small>
</h4>
<br />
<small>
We are the best!
</small>
<br />
</section>
`;
exports[`renders correctly with versionInfo 1`] = `
<section
title="API details"
>
<h4>
Unleash 1.2.3
</h4>
<small>
Upgrade available - Latest Enterprise release: 1.2.4
<br />
</small>
<br />
<small />
<br />
<small>
1
</small>
</section>
`;
exports[`renders correctly without uiConfig 1`] = `
<section
title="API details"
>
<h4>
Unleash 1.1.0
</h4>
<br />
<small />
<br />
</section>
`;

View File

@ -1,43 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`breadcrumb for /features 1`] = `
<span>
<span
className="headerTitleLink"
>
Feature Toggles
</span>
</span>
`;
exports[`breadcrumb for /features/view/Demo 1`] = `
<span>
<a
className="headerTitleLink"
href="/features"
onClick={[Function]}
>
Feature Toggles
</a>
<span>
<span>
</span>
<span
className="headerTitleLink"
>
Demo
</span>
</span>
</span>
`;
exports[`breadcrumb for /strategies 1`] = `
<span>
<span
className="headerTitleLink"
>
Strategies
</span>
</span>
`;

View File

@ -18,10 +18,12 @@ exports[`should render DrawerMenu 1`] = `
<section <section
title="API details" title="API details"
> >
<h4> <h2
className="makeStyles-title-4"
>
Unleash 3.x Unleash 3.x
</h4> </h2>
<br /> <br />
<small> <small>
The enterprise ready feature toggle service. The enterprise ready feature toggle service.
@ -41,9 +43,11 @@ exports[`should render DrawerMenu 1`] = `
<section <section
title="Unleash SDK" title="Unleash SDK"
> >
<h4> <h2
className="makeStyles-title-4"
>
Server SDKs Server SDKs
</h4> </h2>
<ul <ul
className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding" className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding"
> >
@ -210,9 +214,11 @@ exports[`should render DrawerMenu 1`] = `
<section <section
title="Unleash SDK" title="Unleash SDK"
> >
<h4> <h2
className="makeStyles-title-4"
>
Frontend SDKs Frontend SDKs
</h4> </h2>
<ul <ul
className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding" className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding"
> >
@ -318,9 +324,11 @@ exports[`should render DrawerMenu 1`] = `
className="MuiGrid-root MuiGrid-item" className="MuiGrid-root MuiGrid-item"
> >
<section> <section>
<h4> <h2
className="makeStyles-title-4"
>
About About
</h4> </h2>
<ul <ul
className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding" className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding"
> >
@ -446,10 +454,12 @@ exports[`should render DrawerMenu with "features" selected 1`] = `
<section <section
title="API details" title="API details"
> >
<h4> <h2
className="makeStyles-title-4"
>
Unleash 3.x Unleash 3.x
</h4> </h2>
<br /> <br />
<small> <small>
The enterprise ready feature toggle service. The enterprise ready feature toggle service.
@ -469,9 +479,11 @@ exports[`should render DrawerMenu with "features" selected 1`] = `
<section <section
title="Unleash SDK" title="Unleash SDK"
> >
<h4> <h2
className="makeStyles-title-4"
>
Server SDKs Server SDKs
</h4> </h2>
<ul <ul
className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding" className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding"
> >
@ -638,9 +650,11 @@ exports[`should render DrawerMenu with "features" selected 1`] = `
<section <section
title="Unleash SDK" title="Unleash SDK"
> >
<h4> <h2
className="makeStyles-title-4"
>
Frontend SDKs Frontend SDKs
</h4> </h2>
<ul <ul
className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding" className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding"
> >
@ -746,9 +760,11 @@ exports[`should render DrawerMenu with "features" selected 1`] = `
className="MuiGrid-root MuiGrid-item" className="MuiGrid-root MuiGrid-item"
> >
<section> <section>
<h4> <h2
className="makeStyles-title-4"
>
About About
</h4> </h2>
<ul <ul
className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding" className="MuiList-root makeStyles-list-2 MuiList-dense MuiList-padding"
> >

View File

@ -1,34 +0,0 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { MemoryRouter } from 'react-router-dom';
import Breadcrumb from '../breadcrumb';
test('breadcrumb for /features', () => {
const tree = renderer.create(
<MemoryRouter initialEntries={['/features']}>
<Breadcrumb />
</MemoryRouter>
);
expect(tree).toMatchSnapshot();
});
test('breadcrumb for /features/view/Demo', () => {
const tree = renderer.create(
<MemoryRouter initialEntries={['/features/view/Demo']}>
<Breadcrumb />
</MemoryRouter>
);
expect(tree).toMatchSnapshot();
});
test('breadcrumb for /strategies', () => {
const tree = renderer.create(
<MemoryRouter initialEntries={['/strategies']}>
<Breadcrumb />
</MemoryRouter>
);
expect(tree).toMatchSnapshot();
});

View File

@ -1,68 +0,0 @@
import React from 'react';
import { Link, Route, Switch } from 'react-router-dom';
import { routes, getRoute } from './routes';
import styles from '../styles.module.scss';
const renderDoubleBread = (currentTitle, parentRoute) => {
document.title = `${currentTitle} - ${parentRoute.title} - Unleash`;
return (
<span>
<Link className={styles.headerTitleLink} to={parentRoute.path}>
{parentRoute.title}
</Link>
<span>
<span> </span>
<span className={styles.headerTitleLink}>{currentTitle}</span>
</span>
</span>
);
};
const renderBread = route => {
document.title = `${route.title} - Unleash`;
return (
<span>
<span className={styles.headerTitleLink}>{route.title}</span>
</span>
);
};
const renderRoute = (params, route) => {
if (!route) {
return null;
}
const title = route.title.startsWith(':')
? params[route.title.substring(1)]
: route.title;
return route.parent
? renderDoubleBread(title, getRoute(route.parent))
: renderBread(route);
};
/*
Render the breadcrumb.
We only support two levels.
Examples:
- Features
- Features > Create
- Features > SomeToggle
*/
const Breadcrumb = () => (
<Switch>
{routes.map(route => (
<Route
key={route.path}
path={route.path}
render={({ match: { params } } = this.props) =>
renderRoute(params, route)
}
/>
))}
</Switch>
);
export default Breadcrumb;

View File

@ -4,9 +4,8 @@ import PropTypes from 'prop-types';
import GitHubIcon from '@material-ui/icons/GitHub'; import GitHubIcon from '@material-ui/icons/GitHub';
import LibraryBooksIcon from '@material-ui/icons/LibraryBooks'; import LibraryBooksIcon from '@material-ui/icons/LibraryBooks';
import ExitToApp from '@material-ui/icons/ExitToApp'; import ExitToApp from '@material-ui/icons/ExitToApp';
import { Link } from 'react-router-dom';
import styles from './drawer.module.scss'; import styles from './drawer.module.scss';
import { ReactComponent as LogoIcon } from 'assets/icons/logoBg.svg'; import { ReactComponent as LogoIcon } from 'assets/icons/logoBg.svg';
import NavigationLink from './Header/NavigationLink/NavigationLink'; import NavigationLink from './Header/NavigationLink/NavigationLink';
import ConditionallyRender from 'component/common/ConditionallyRender'; import ConditionallyRender from 'component/common/ConditionallyRender';
@ -49,16 +48,23 @@ export const DrawerMenu = ({
<Drawer <Drawer
className={styles.drawer} className={styles.drawer}
open={open} open={open}
anchor={'left'} anchor="left"
onClose={() => toggleDrawer()} onClose={toggleDrawer}
> >
<div className={styles.drawerContainer}> <nav id="header-drawer" className={styles.drawerContainer}>
<div> <div>
<span className={[styles.drawerTitle].join(' ')}> <Link
<LogoIcon className={styles.drawerTitleLogo} /> to="/"
className={styles.drawerTitle}
aria-label="Home"
onClick={() => toggleDrawer()}
>
<LogoIcon
className={styles.drawerTitleLogo}
aria-label="Unleash logo"
/>
<span className={styles.drawerTitleText}>{title}</span> <span className={styles.drawerTitleText}>{title}</span>
</span> </Link>
</div> </div>
<Divider /> <Divider />
<List className={styles.drawerList}> <List className={styles.drawerList}>
@ -101,7 +107,7 @@ export const DrawerMenu = ({
Sign out Sign out
</a> </a>
</div> </div>
</div> </nav>
</Drawer> </Drawer>
); );
}; };

View File

@ -6,6 +6,8 @@
.drawerTitle { .drawerTitle {
display: flex; display: flex;
align-items: center; align-items: center;
color: inherit;
text-decoration: none;
} }
.drawerContainer { .drawerContainer {

View File

@ -20,11 +20,11 @@ exports[`renders correctly with one strategy 1`] = `
className="" className=""
data-loading={true} data-loading={true}
> >
<h2 <h1
className="MuiTypography-root makeStyles-headerTitle-7 MuiTypography-h2" className="MuiTypography-root makeStyles-headerTitle-7 MuiTypography-h1"
> >
Strategies Strategies
</h2> </h1>
</div> </div>
<div <div
className="makeStyles-headerActions-8" className="makeStyles-headerActions-8"
@ -290,11 +290,11 @@ exports[`renders correctly with one strategy without permissions 1`] = `
className="" className=""
data-loading={true} data-loading={true}
> >
<h2 <h1
className="MuiTypography-root makeStyles-headerTitle-7 MuiTypography-h2" className="MuiTypography-root makeStyles-headerTitle-7 MuiTypography-h1"
> >
Strategies Strategies
</h2> </h1>
</div> </div>
<div <div
className="makeStyles-headerActions-8" className="makeStyles-headerActions-8"

View File

@ -20,11 +20,11 @@ exports[`renders a list with elements correctly 1`] = `
className="" className=""
data-loading={true} data-loading={true}
> >
<h2 <h1
className="MuiTypography-root makeStyles-headerTitle-6 MuiTypography-h2" className="MuiTypography-root makeStyles-headerTitle-6 MuiTypography-h1"
> >
Tag Types Tag Types
</h2> </h1>
</div> </div>
<div <div
className="makeStyles-headerActions-7" className="makeStyles-headerActions-7"
@ -96,11 +96,11 @@ exports[`renders an empty list correctly 1`] = `
className="" className=""
data-loading={true} data-loading={true}
> >
<h2 <h1
className="MuiTypography-root makeStyles-headerTitle-6 MuiTypography-h2" className="MuiTypography-root makeStyles-headerTitle-6 MuiTypography-h1"
> >
Tag Types Tag Types
</h2> </h1>
</div> </div>
<div <div
className="makeStyles-headerActions-7" className="makeStyles-headerActions-7"