@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Updates the Status component to fix use of color and voice over accessibility issues.
|
||||
@@ -28,52 +28,42 @@ import {
|
||||
|
||||
describe('<StatusOK />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { getByText } = await renderInTestApp(<StatusOK>OK</StatusOK>);
|
||||
expect(getByText('OK')).toBeInTheDocument();
|
||||
const { getByLabelText } = await renderInTestApp(<StatusOK />);
|
||||
expect(getByLabelText('Status ok')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('<StatusWarning />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { getByText } = await renderInTestApp(
|
||||
<StatusWarning>Warning</StatusWarning>,
|
||||
);
|
||||
expect(getByText('Warning')).toBeInTheDocument();
|
||||
const { getByLabelText } = await renderInTestApp(<StatusWarning />);
|
||||
expect(getByLabelText('Status warning')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('<StatusError />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { getByText } = await renderInTestApp(
|
||||
<StatusError>Error</StatusError>,
|
||||
);
|
||||
expect(getByText('Error')).toBeInTheDocument();
|
||||
const { getByLabelText } = await renderInTestApp(<StatusError />);
|
||||
expect(getByLabelText('Status error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('<StatusPending />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { getByText } = await renderInTestApp(
|
||||
<StatusPending>Pending</StatusPending>,
|
||||
);
|
||||
expect(getByText('Pending')).toBeInTheDocument();
|
||||
const { getByLabelText } = await renderInTestApp(<StatusPending />);
|
||||
expect(getByLabelText('Status pending')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('<StatusRunning />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { getByText } = await renderInTestApp(
|
||||
<StatusRunning>Running</StatusRunning>,
|
||||
);
|
||||
expect(getByText('Running')).toBeInTheDocument();
|
||||
const { getByLabelText } = await renderInTestApp(<StatusRunning />);
|
||||
expect(getByLabelText('Status running')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('<StatusAborted />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { getByText } = await renderInTestApp(
|
||||
<StatusAborted>Aborted</StatusAborted>,
|
||||
);
|
||||
expect(getByText('Aborted')).toBeInTheDocument();
|
||||
const { getByLabelText } = await renderInTestApp(<StatusAborted />);
|
||||
expect(getByLabelText('Status aborted')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,13 +19,6 @@ import Typography from '@material-ui/core/Typography';
|
||||
import classNames from 'classnames';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
import CheckIcon from '@material-ui/icons/Check';
|
||||
import WarningIcon from '@material-ui/icons/Warning';
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import HighlightOffIcon from '@material-ui/icons/HighlightOff';
|
||||
import ScheduleIcon from '@material-ui/icons/Schedule';
|
||||
import DirectionsRunIcon from '@material-ui/icons/DirectionsRun';
|
||||
|
||||
export type StatusClassKey =
|
||||
| 'status'
|
||||
| 'ok'
|
||||
@@ -38,43 +31,44 @@ export type StatusClassKey =
|
||||
const useStyles = makeStyles<BackstageTheme>(
|
||||
theme => ({
|
||||
status: {
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexFlow: 'row wrap',
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
|
||||
'& > svg': {
|
||||
'&::before': {
|
||||
width: '0.7em',
|
||||
height: '0.7em',
|
||||
display: 'inline-block',
|
||||
marginRight: theme.spacing(1),
|
||||
borderRadius: '50%',
|
||||
content: '""',
|
||||
},
|
||||
},
|
||||
ok: {
|
||||
'& > svg': {
|
||||
fill: theme.palette.status.ok,
|
||||
'&::before': {
|
||||
backgroundColor: theme.palette.status.ok,
|
||||
},
|
||||
},
|
||||
warning: {
|
||||
'& > svg': {
|
||||
fill: theme.palette.status.warning,
|
||||
'&::before': {
|
||||
backgroundColor: theme.palette.status.warning,
|
||||
},
|
||||
},
|
||||
error: {
|
||||
'& > svg': {
|
||||
fill: theme.palette.status.error,
|
||||
'&::before': {
|
||||
backgroundColor: theme.palette.status.error,
|
||||
},
|
||||
},
|
||||
pending: {
|
||||
'& > svg': {
|
||||
fill: theme.palette.status.pending,
|
||||
'&::before': {
|
||||
backgroundColor: theme.palette.status.pending,
|
||||
},
|
||||
},
|
||||
running: {
|
||||
'& > svg': {
|
||||
fill: theme.palette.status.running,
|
||||
'&::before': {
|
||||
backgroundColor: theme.palette.status.running,
|
||||
},
|
||||
},
|
||||
aborted: {
|
||||
'& > svg': {
|
||||
fill: theme.palette.status.aborted,
|
||||
'&::before': {
|
||||
backgroundColor: theme.palette.status.aborted,
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -83,85 +77,78 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
|
||||
export function StatusOK(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
<div
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.ok)}
|
||||
aria-label={!props.children ? 'Ok' : undefined}
|
||||
role={!props.children ? 'img' : undefined}
|
||||
>
|
||||
<CheckIcon style={{ fontSize: '1rem' }} />
|
||||
<Typography component="span" {...props} />
|
||||
</div>
|
||||
aria-label="Status ok"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function StatusWarning(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<div
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.warning)}
|
||||
aria-label={!props.children ? 'Warning' : undefined}
|
||||
role={!props.children ? 'img' : undefined}
|
||||
>
|
||||
<WarningIcon style={{ fontSize: '1rem' }} />
|
||||
<Typography component="span" {...props} />
|
||||
</div>
|
||||
aria-label="Status warning"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function StatusError(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<div
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.error)}
|
||||
aria-label={!props.children ? 'Error' : undefined}
|
||||
role={!props.children ? 'img' : undefined}
|
||||
>
|
||||
<ErrorIcon style={{ fontSize: '1rem' }} />
|
||||
<Typography component="span" {...props} />
|
||||
</div>
|
||||
aria-label="Status error"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function StatusPending(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<div
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.pending)}
|
||||
aria-label={!props.children ? 'Pending' : undefined}
|
||||
role={!props.children ? 'img' : undefined}
|
||||
>
|
||||
<ScheduleIcon style={{ fontSize: '1rem' }} />
|
||||
<Typography component="span" {...props} />
|
||||
</div>
|
||||
aria-label="Status pending"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function StatusRunning(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<div
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.running)}
|
||||
aria-label={!props.children ? 'Running' : undefined}
|
||||
role={!props.children ? 'img' : undefined}
|
||||
>
|
||||
<DirectionsRunIcon style={{ fontSize: '1rem' }} />
|
||||
<Typography component="span" {...props} />
|
||||
</div>
|
||||
aria-label="Status running"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function StatusAborted(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<div
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.aborted)}
|
||||
aria-label={!props.children ? 'Aborted' : undefined}
|
||||
role={!props.children ? 'img' : undefined}
|
||||
>
|
||||
<HighlightOffIcon style={{ fontSize: '1rem' }} />
|
||||
<Typography component="span" {...props} />
|
||||
</div>
|
||||
aria-label="Status aborted"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,19 +24,19 @@ describe('StatusIcon', () => {
|
||||
let rendered = await renderInTestApp(
|
||||
<StatusIcon buildStatus="succeeded" />,
|
||||
);
|
||||
expect(rendered.getByLabelText('Ok')).toBeInTheDocument();
|
||||
expect(rendered.getByLabelText('Status ok')).toBeInTheDocument();
|
||||
|
||||
rendered = await renderInTestApp(<StatusIcon buildStatus="failed" />);
|
||||
expect(rendered.getByLabelText('Error')).toBeInTheDocument();
|
||||
expect(rendered.getByLabelText('Status error')).toBeInTheDocument();
|
||||
|
||||
rendered = await renderInTestApp(<StatusIcon buildStatus="stopped" />);
|
||||
expect(rendered.getByLabelText('Warning')).toBeInTheDocument();
|
||||
expect(rendered.getByLabelText('Status warning')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render invalid statuses', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<StatusIcon buildStatus={'invalid' as BuildStatus} />,
|
||||
);
|
||||
expect(rendered.getByLabelText('Aborted')).toBeInTheDocument();
|
||||
expect(rendered.getByLabelText('Status aborted')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user