mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
Accessibility: enable rule jsx-a11y/label-has-associated-control
(#57964)
* use labels correctly * fix opentsdb labels * fix unit tests * use aria-label instead of data-testid
This commit is contained in:
parent
3770f4f2b7
commit
e5c68f40c2
@ -73,7 +73,6 @@
|
||||
// we should remove the corresponding line and fix them one by one
|
||||
// any marked "error" contain specific overrides we'll need to keep
|
||||
"jsx-a11y/click-events-have-key-events": "off",
|
||||
"jsx-a11y/label-has-associated-control": "off",
|
||||
"jsx-a11y/mouse-events-have-key-events": "off",
|
||||
"jsx-a11y/no-autofocus": [
|
||||
"error",
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { FunctionComponent, PureComponent } from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { withTheme2, useStyles2 } from '../../themes';
|
||||
import { Button } from '../Button';
|
||||
import { Switch } from '../Forms/Legacy/Switch/Switch';
|
||||
import { PopoverContentProps } from '../Tooltip';
|
||||
|
||||
@ -43,52 +42,6 @@ export const SeriesColorPickerPopover: FunctionComponent<SeriesColorPickerPopove
|
||||
return <ColorPickerPopover {...colorPickerProps} color={color || '#000000'} customPickers={customPickers} />;
|
||||
};
|
||||
|
||||
interface AxisSelectorProps {
|
||||
yaxis: number;
|
||||
onToggleAxis?: () => void;
|
||||
}
|
||||
|
||||
interface AxisSelectorState {
|
||||
yaxis: number;
|
||||
}
|
||||
|
||||
export class AxisSelector extends PureComponent<AxisSelectorProps, AxisSelectorState> {
|
||||
constructor(props: AxisSelectorProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
yaxis: this.props.yaxis,
|
||||
};
|
||||
this.onToggleAxis = this.onToggleAxis.bind(this);
|
||||
}
|
||||
|
||||
onToggleAxis() {
|
||||
this.setState({
|
||||
yaxis: this.state.yaxis === 2 ? 1 : 2,
|
||||
});
|
||||
|
||||
if (this.props.onToggleAxis) {
|
||||
this.props.onToggleAxis();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const leftButtonVariant = this.state.yaxis === 1 ? 'primary' : 'secondary';
|
||||
const rightButtonVariant = this.state.yaxis === 2 ? 'primary' : 'secondary';
|
||||
|
||||
return (
|
||||
<div className="p-b-1">
|
||||
<label className="small p-r-1">Y Axis:</label>
|
||||
<Button onClick={this.onToggleAxis} size="sm" variant={leftButtonVariant}>
|
||||
Left
|
||||
</Button>
|
||||
<Button onClick={this.onToggleAxis} size="sm" variant={rightButtonVariant}>
|
||||
Right
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This component is to enable SeriesColorPickerPopover usage via series-color-picker-popover directive
|
||||
export const SeriesColorPickerPopoverWithTheme = withTheme2(SeriesColorPickerPopover);
|
||||
|
||||
|
@ -155,13 +155,14 @@ export const DataSourceHttpSettings: React.FC<HttpSettingsProps> = (props) => {
|
||||
<FormField label="Access" labelWidth={13} inputWidth={20} inputEl={accessSelect} />
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<label
|
||||
<button
|
||||
type="button"
|
||||
className="gf-form-label query-keyword pointer"
|
||||
onClick={() => setIsAccessHelpVisible((isVisible) => !isVisible)}
|
||||
>
|
||||
Help
|
||||
<Icon name={isAccessHelpVisible ? 'angle-down' : 'angle-right'} style={{ marginBottom: 0 }} />
|
||||
</label>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{isAccessHelpVisible && <HttpAccessHelp />}
|
||||
|
@ -14,7 +14,7 @@ export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'value'> {
|
||||
}
|
||||
|
||||
export const Switch = React.forwardRef<HTMLInputElement, Props>(
|
||||
({ value, checked, disabled, onChange, id, ...inputProps }, ref) => {
|
||||
({ value, checked, disabled, onChange, id, label, ...inputProps }, ref) => {
|
||||
if (checked) {
|
||||
deprecationWarning('Switch', 'checked prop', 'value');
|
||||
}
|
||||
@ -36,7 +36,7 @@ export const Switch = React.forwardRef<HTMLInputElement, Props>(
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
/>
|
||||
<label htmlFor={switchIdRef.current} />
|
||||
<label htmlFor={switchIdRef.current} aria-label={label ?? 'Toggle switch'} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ export const SliderValueEditor: React.FC<FieldConfigEditorProps<number, SliderFi
|
||||
<div className={cx(styles.container, styles.slider)}>
|
||||
{/** Slider tooltip's parent component is body and therefore we need Global component to do css overrides for it. */}
|
||||
<Global styles={styles.slider} />
|
||||
<label className={cx(styles.sliderInput, ...sliderInputClassNames)}>
|
||||
<div className={cx(styles.sliderInput, ...sliderInputClassNames)}>
|
||||
<SliderWithTooltip
|
||||
min={min}
|
||||
max={max}
|
||||
@ -113,7 +113,7 @@ export const SliderValueEditor: React.FC<FieldConfigEditorProps<number, SliderFi
|
||||
<span className={stylesSlider.numberInputWrapper} ref={inputRef}>
|
||||
<NumberInput value={sliderValue} onChange={onSliderInputChange} max={max} min={min} step={step} />
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -22,6 +22,6 @@ describe('<BasicSettings>', () => {
|
||||
setup();
|
||||
|
||||
expect(screen.getByRole('textbox', { name: selectors.pages.DataSource.name })).toBeInTheDocument();
|
||||
expect(screen.getByRole('checkbox', { name: 'Default' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('checkbox', { name: /Default/ })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -10,10 +10,10 @@ export type Props = {
|
||||
export function DataSourcePluginState({ state }: Props) {
|
||||
return (
|
||||
<div className="gf-form">
|
||||
<label className="gf-form-label width-10">Plugin state</label>
|
||||
<label className="gf-form-label gf-form-label--transparent">
|
||||
<div className="gf-form-label width-10">Plugin state</div>
|
||||
<div className="gf-form-label gf-form-label--transparent">
|
||||
<PluginStateInfo state={state} />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ export const switchToQueryHistoryTab = async (
|
||||
|
||||
export const selectStarredTabFirst = async (exploreId: ExploreId = ExploreId.left) => {
|
||||
const checkbox = withinExplore(exploreId).getByRole('checkbox', {
|
||||
name: 'Change the default active tab from “Query history” to “Starred”',
|
||||
name: /Change the default active tab from “Query history” to “Starred”/,
|
||||
});
|
||||
await userEvent.click(checkbox);
|
||||
};
|
||||
|
@ -94,10 +94,13 @@ export class FolderSettingsPage extends PureComponent<Props, State> {
|
||||
<div className="section gf-form-group">
|
||||
<form name="folderSettingsForm" onSubmit={this.onSave}>
|
||||
<div className="gf-form">
|
||||
<label className="gf-form-label width-7">Name</label>
|
||||
<label htmlFor="folder-title" className="gf-form-label width-7">
|
||||
Name
|
||||
</label>
|
||||
<Input
|
||||
type="text"
|
||||
className="gf-form-input width-30"
|
||||
id="folder-title"
|
||||
value={folder.title}
|
||||
onChange={this.onTitleChange}
|
||||
/>
|
||||
|
@ -18,7 +18,7 @@ export function Preview({ rawSql }: PreviewProps) {
|
||||
|
||||
const labelElement = (
|
||||
<div className={styles.labelWrapper}>
|
||||
<label className={styles.label}>Preview</label>
|
||||
<span className={styles.label}>Preview</span>
|
||||
<IconButton tooltip="Copy to clipboard" onClick={() => copyToClipboard(rawSql)} name="copy" />
|
||||
</div>
|
||||
);
|
||||
|
@ -19,7 +19,7 @@ export const AnnotationsHelp = () => {
|
||||
<p>
|
||||
Example Result: <code>monitoring.googleapis.com/uptime_check/http_status has this value: 502</code>
|
||||
</p>
|
||||
<label>Patterns:</label>
|
||||
<span>Patterns:</span>
|
||||
<p>
|
||||
<code>{`${'{{metric.value}}'}`}</code> = value of the metric/point
|
||||
</p>
|
||||
|
@ -24,7 +24,7 @@ export default class CloudMonitoringCheatSheet extends PureComponent<
|
||||
Result: <code>cpu/usage_time - server1-europe-west-1</code>
|
||||
<br />
|
||||
<br />
|
||||
<label>Patterns</label>
|
||||
<span>Patterns:</span>
|
||||
<br />
|
||||
<ul
|
||||
className={css`
|
||||
|
@ -53,7 +53,7 @@ describe('FilterSection', () => {
|
||||
describe('filter editor', () => {
|
||||
it('open the editor on clicking +', () => {
|
||||
setup();
|
||||
fireEvent.click(screen.getByTestId(testIds.open));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Add filter/ }));
|
||||
expect(screen.getByText('Group by')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@ -64,7 +64,7 @@ describe('FilterSection', () => {
|
||||
|
||||
it('should call runQuery on adding a filter', () => {
|
||||
setup();
|
||||
fireEvent.click(screen.getByTestId(testIds.open));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Add filter/ }));
|
||||
fireEvent.click(screen.getByText('add filter'));
|
||||
expect(onRunQuery).toHaveBeenCalled();
|
||||
});
|
||||
@ -78,7 +78,7 @@ describe('FilterSection', () => {
|
||||
tags: [{}],
|
||||
};
|
||||
setup({ query });
|
||||
fireEvent.click(screen.getByTestId(testIds.open));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Add filter/ }));
|
||||
fireEvent.click(screen.getByText('add filter'));
|
||||
expect(screen.getByTestId(testIds.error)).toBeInTheDocument();
|
||||
});
|
||||
|
@ -138,11 +138,9 @@ export function FilterSection({
|
||||
);
|
||||
})}
|
||||
{!addFilterMode && (
|
||||
<label className="gf-form-label query-keyword">
|
||||
<button type="button" className={buttonStyles} onClick={changeAddFilterMode} data-testid={testIds.open}>
|
||||
<Icon name={'plus'} />
|
||||
</button>
|
||||
</label>
|
||||
<button className="gf-form-label" type="button" onClick={changeAddFilterMode} aria-label="Add filter">
|
||||
<Icon name={'plus'} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{addFilterMode && (
|
||||
@ -225,19 +223,18 @@ export function FilterSection({
|
||||
/>
|
||||
<div className="gf-form">
|
||||
{errors && (
|
||||
<label className="gf-form-label" title={errors} data-testid={testIds.error}>
|
||||
<div className="gf-form-label" title={errors} data-testid={testIds.error}>
|
||||
<Icon name={'exclamation-triangle'} color={'rgb(229, 189, 28)'} />
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<label className="gf-form-label">
|
||||
<div className="gf-form-label">
|
||||
<button type="button" className={buttonStyles} onClick={addFilter}>
|
||||
add filter
|
||||
</button>
|
||||
<button type="button" className={buttonStyles} onClick={changeAddFilterMode}>
|
||||
<Icon name={'times'} />
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -250,7 +247,6 @@ export function FilterSection({
|
||||
|
||||
export const testIds = {
|
||||
section: 'opentsdb-filter',
|
||||
open: 'opentsdb-filter-editor',
|
||||
list: 'opentsdb-filter-list',
|
||||
error: 'opentsdb-filter-error',
|
||||
remove: 'opentsdb-filter-remove',
|
||||
|
@ -48,7 +48,7 @@ describe('Tag Section', () => {
|
||||
describe('tag editor', () => {
|
||||
it('open the editor on clicking +', () => {
|
||||
setup();
|
||||
fireEvent.click(screen.getByTestId(testIds.open));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Add tag/ }));
|
||||
expect(screen.getByText('add tag')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@ -59,7 +59,7 @@ describe('Tag Section', () => {
|
||||
|
||||
it('should call runQuery on adding a tag', () => {
|
||||
setup();
|
||||
fireEvent.click(screen.getByTestId(testIds.open));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Add tag/ }));
|
||||
fireEvent.click(screen.getByText('add tag'));
|
||||
expect(onRunQuery).toHaveBeenCalled();
|
||||
});
|
||||
@ -80,7 +80,7 @@ describe('Tag Section', () => {
|
||||
],
|
||||
};
|
||||
setup({ query });
|
||||
fireEvent.click(screen.getByTestId(testIds.open));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Add tag/ }));
|
||||
fireEvent.click(screen.getByText('add tag'));
|
||||
expect(screen.getByTestId(testIds.error)).toBeInTheDocument();
|
||||
});
|
||||
|
@ -136,11 +136,9 @@ export function TagSection({
|
||||
);
|
||||
})}
|
||||
{!addTagMode && (
|
||||
<label className="gf-form-label query-keyword">
|
||||
<button type="button" className={buttonStyles} onClick={changeAddTagMode} data-testid={testIds.open}>
|
||||
<Icon name={'plus'} />
|
||||
</button>
|
||||
</label>
|
||||
<button className="gf-form-label" type="button" onClick={changeAddTagMode} aria-label="Add tag">
|
||||
<Icon name={'plus'} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{addTagMode && (
|
||||
@ -196,19 +194,19 @@ export function TagSection({
|
||||
|
||||
<div className="gf-form">
|
||||
{errors && (
|
||||
<label className="gf-form-label" title={errors} data-testid={testIds.error}>
|
||||
<div className="gf-form-label" title={errors} data-testid={testIds.error}>
|
||||
<Icon name={'exclamation-triangle'} color={'rgb(229, 189, 28)'} />
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<label className="gf-form-label">
|
||||
<div className="gf-form-label">
|
||||
<button type="button" className={buttonStyles} onClick={addTag}>
|
||||
add tag
|
||||
</button>
|
||||
<button type="button" className={buttonStyles} onClick={changeAddTagMode}>
|
||||
<Icon name={'times'} />
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -221,7 +219,6 @@ export function TagSection({
|
||||
|
||||
export const testIds = {
|
||||
section: 'opentsdb-tag',
|
||||
open: 'opentsdb-tag-editor',
|
||||
list: 'opentsdb-tag-list',
|
||||
error: 'opentsdb-tag-error',
|
||||
remove: 'opentsdb-tag-remove',
|
||||
|
Loading…
Reference in New Issue
Block a user