Catalog page accessibility fixes
- Fix user picker heading level / menu item role - Add label to Action buttons - Fix filter control label issues - Change table header level - Add aria-label to select component - Add fallback presentation role - Add screenreader text for logo link Signed-off-by: Eric Voshall <6836155+ericvoshall@users.noreply.github.com>
This commit is contained in:
@@ -77,6 +77,7 @@ const SidebarLogo = () => {
|
||||
to="/"
|
||||
underline="none"
|
||||
className={classes.link}
|
||||
aria-label="Home"
|
||||
>
|
||||
{isOpen ? <LogoFull /> : <LogoIcon />}
|
||||
</Link>
|
||||
|
||||
@@ -199,6 +199,7 @@ export function SelectComponent(props: SelectProps) {
|
||||
<FormControl className={classes.formControl}>
|
||||
<InputLabel className={classes.formLabel}>{label}</InputLabel>
|
||||
<Select
|
||||
aria-label={label}
|
||||
value={value}
|
||||
native={native}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -499,7 +499,7 @@ export function Table<T extends object = {}>(props: TableProps<T>) {
|
||||
icons={tableIcons}
|
||||
title={
|
||||
<>
|
||||
<Typography variant="h5" component="h3">
|
||||
<Typography variant="h5" component="h2">
|
||||
{title}
|
||||
</Typography>
|
||||
{subtitle && (
|
||||
|
||||
+32
-25
@@ -99,31 +99,38 @@ export const EntityLifecyclePicker = () => {
|
||||
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<Typography variant="button">Lifecycle</Typography>
|
||||
<Autocomplete
|
||||
aria-label="Lifecycle"
|
||||
multiple
|
||||
options={availableLifecycles}
|
||||
value={selectedLifecycles}
|
||||
onChange={(_: object, value: string[]) => setSelectedLifecycles(value)}
|
||||
renderOption={(option, { selected }) => (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
icon={icon}
|
||||
checkedIcon={checkedIcon}
|
||||
checked={selected}
|
||||
/>
|
||||
}
|
||||
label={option}
|
||||
/>
|
||||
)}
|
||||
size="small"
|
||||
popupIcon={<ExpandMoreIcon data-testid="lifecycle-picker-expand" />}
|
||||
renderInput={params => (
|
||||
<TextField {...params} className={classes.input} variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
<Typography variant="button" component="label">
|
||||
Lifecycle
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={availableLifecycles}
|
||||
value={selectedLifecycles}
|
||||
onChange={(_: object, value: string[]) =>
|
||||
setSelectedLifecycles(value)
|
||||
}
|
||||
renderOption={(option, { selected }) => (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
icon={icon}
|
||||
checkedIcon={checkedIcon}
|
||||
checked={selected}
|
||||
/>
|
||||
}
|
||||
label={option}
|
||||
/>
|
||||
)}
|
||||
size="small"
|
||||
popupIcon={<ExpandMoreIcon data-testid="lifecycle-picker-expand" />}
|
||||
renderInput={params => (
|
||||
<TextField
|
||||
{...params}
|
||||
className={classes.input}
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -103,31 +103,36 @@ export const EntityOwnerPicker = () => {
|
||||
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<Typography variant="button">Owner</Typography>
|
||||
<Autocomplete
|
||||
multiple
|
||||
aria-label="Owner"
|
||||
options={availableOwners}
|
||||
value={selectedOwners}
|
||||
onChange={(_: object, value: string[]) => setSelectedOwners(value)}
|
||||
renderOption={(option, { selected }) => (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
icon={icon}
|
||||
checkedIcon={checkedIcon}
|
||||
checked={selected}
|
||||
/>
|
||||
}
|
||||
label={option}
|
||||
/>
|
||||
)}
|
||||
size="small"
|
||||
popupIcon={<ExpandMoreIcon data-testid="owner-picker-expand" />}
|
||||
renderInput={params => (
|
||||
<TextField {...params} className={classes.input} variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
<Typography variant="button" component="label">
|
||||
Owner
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={availableOwners}
|
||||
value={selectedOwners}
|
||||
onChange={(_: object, value: string[]) => setSelectedOwners(value)}
|
||||
renderOption={(option, { selected }) => (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
icon={icon}
|
||||
checkedIcon={checkedIcon}
|
||||
checked={selected}
|
||||
/>
|
||||
}
|
||||
label={option}
|
||||
/>
|
||||
)}
|
||||
size="small"
|
||||
popupIcon={<ExpandMoreIcon data-testid="owner-picker-expand" />}
|
||||
renderInput={params => (
|
||||
<TextField
|
||||
{...params}
|
||||
className={classes.input}
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -95,31 +95,36 @@ export const EntityTagPicker = () => {
|
||||
|
||||
return (
|
||||
<Box pb={1} pt={1}>
|
||||
<Typography variant="button">Tags</Typography>
|
||||
<Autocomplete
|
||||
multiple
|
||||
aria-label="Tags"
|
||||
options={availableTags}
|
||||
value={selectedTags}
|
||||
onChange={(_: object, value: string[]) => setSelectedTags(value)}
|
||||
renderOption={(option, { selected }) => (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
icon={icon}
|
||||
checkedIcon={checkedIcon}
|
||||
checked={selected}
|
||||
/>
|
||||
}
|
||||
label={option}
|
||||
/>
|
||||
)}
|
||||
size="small"
|
||||
popupIcon={<ExpandMoreIcon data-testid="tag-picker-expand" />}
|
||||
renderInput={params => (
|
||||
<TextField {...params} className={classes.input} variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
<Typography variant="button" component="label">
|
||||
Tags
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={availableTags}
|
||||
value={selectedTags}
|
||||
onChange={(_: object, value: string[]) => setSelectedTags(value)}
|
||||
renderOption={(option, { selected }) => (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
icon={icon}
|
||||
checkedIcon={checkedIcon}
|
||||
checked={selected}
|
||||
/>
|
||||
}
|
||||
label={option}
|
||||
/>
|
||||
)}
|
||||
size="small"
|
||||
popupIcon={<ExpandMoreIcon data-testid="tag-picker-expand" />}
|
||||
renderInput={params => (
|
||||
<TextField
|
||||
{...params}
|
||||
className={classes.input}
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -238,13 +238,18 @@ export const UserListPicker = (props: UserListPickerProps) => {
|
||||
<Card className={classes.root}>
|
||||
{filterGroups.map(group => (
|
||||
<Fragment key={group.name}>
|
||||
<Typography variant="subtitle2" className={classes.title}>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
component="span"
|
||||
className={classes.title}
|
||||
>
|
||||
{group.name}
|
||||
</Typography>
|
||||
<Card className={classes.groupWrapper}>
|
||||
<List disablePadding dense role="menu">
|
||||
<List disablePadding dense role="menu" aria-label={group.name}>
|
||||
{group.items.map(item => (
|
||||
<MenuItem
|
||||
role="none presentation"
|
||||
key={item.id}
|
||||
button
|
||||
divider
|
||||
@@ -254,6 +259,7 @@ export const UserListPicker = (props: UserListPickerProps) => {
|
||||
disabled={filterCounts[item.id] === 0}
|
||||
data-testid={`user-picker-${item.id}`}
|
||||
tabIndex={0}
|
||||
ContainerProps={{ role: 'menuitem' }}
|
||||
>
|
||||
{item.icon && (
|
||||
<ListItemIcon className={classes.listIcon}>
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
import StarBorder from '@material-ui/icons/StarBorder';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Star from '@material-ui/icons/Star';
|
||||
import { Typography } from '@material-ui/core';
|
||||
|
||||
/**
|
||||
* Props for {@link CatalogTable}.
|
||||
@@ -115,9 +116,16 @@ export const CatalogTable = (props: CatalogTableProps) => {
|
||||
const defaultActions: TableProps<CatalogTableRow>['actions'] = [
|
||||
({ entity }) => {
|
||||
const url = entity.metadata.annotations?.[ANNOTATION_VIEW_URL];
|
||||
const title = 'View';
|
||||
|
||||
return {
|
||||
icon: () => <OpenInNew aria-label="View" fontSize="small" />,
|
||||
tooltip: 'View',
|
||||
icon: () => (
|
||||
<>
|
||||
<Typography variant="srOnly" title={title} />
|
||||
<OpenInNew fontSize="small" />
|
||||
</>
|
||||
),
|
||||
tooltip: title,
|
||||
disabled: !url,
|
||||
onClick: () => {
|
||||
if (!url) return;
|
||||
@@ -127,9 +135,16 @@ export const CatalogTable = (props: CatalogTableProps) => {
|
||||
},
|
||||
({ entity }) => {
|
||||
const url = entity.metadata.annotations?.[ANNOTATION_EDIT_URL];
|
||||
const title = 'Edit';
|
||||
|
||||
return {
|
||||
icon: () => <Edit aria-label="Edit" fontSize="small" />,
|
||||
tooltip: 'Edit',
|
||||
icon: () => (
|
||||
<>
|
||||
<Typography variant="srOnly" title={title} />
|
||||
<Edit fontSize="small" />
|
||||
</>
|
||||
),
|
||||
tooltip: title,
|
||||
disabled: !url,
|
||||
onClick: () => {
|
||||
if (!url) return;
|
||||
@@ -139,10 +154,17 @@ export const CatalogTable = (props: CatalogTableProps) => {
|
||||
},
|
||||
({ entity }) => {
|
||||
const isStarred = isStarredEntity(entity);
|
||||
const title = isStarred ? 'Remove from favorites' : 'Add to favorites';
|
||||
|
||||
return {
|
||||
cellStyle: { paddingLeft: '1em' },
|
||||
icon: () => (isStarred ? <YellowStar /> : <StarBorder />),
|
||||
tooltip: isStarred ? 'Remove from favorites' : 'Add to favorites',
|
||||
icon: () => (
|
||||
<>
|
||||
<Typography variant="srOnly" title={title} />
|
||||
{isStarred ? <YellowStar /> : <StarBorder />}
|
||||
</>
|
||||
),
|
||||
tooltip: title,
|
||||
onClick: () => toggleStarredEntity(entity),
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user