mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
A11y: Fix misc. fastpass issues (#41088)
This commit is contained in:
parent
d98cb8274c
commit
124c3f537f
@ -96,7 +96,7 @@ class DarkColors implements ThemeColorsBase<Partial<ThemeRichColor>> {
|
|||||||
text = {
|
text = {
|
||||||
primary: `rgb(${this.whiteBase})`,
|
primary: `rgb(${this.whiteBase})`,
|
||||||
secondary: `rgba(${this.whiteBase}, 0.65)`,
|
secondary: `rgba(${this.whiteBase}, 0.65)`,
|
||||||
disabled: `rgba(${this.whiteBase}, 0.57)`,
|
disabled: `rgba(${this.whiteBase}, 0.58)`,
|
||||||
link: palette.blueDarkText,
|
link: palette.blueDarkText,
|
||||||
maxContrast: palette.white,
|
maxContrast: palette.white,
|
||||||
};
|
};
|
||||||
|
@ -60,7 +60,7 @@ export const Alert = React.forwardRef<HTMLDivElement, Props>(
|
|||||||
{/* If onRemove is specified, giving preference to onRemove */}
|
{/* If onRemove is specified, giving preference to onRemove */}
|
||||||
{onRemove && !buttonContent && (
|
{onRemove && !buttonContent && (
|
||||||
<div className={styles.close}>
|
<div className={styles.close}>
|
||||||
<IconButton name="times" onClick={onRemove} size="lg" type="button" />
|
<IconButton aria-label="Close alert" name="times" onClick={onRemove} size="lg" type="button" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{onRemove && buttonContent && (
|
{onRemove && buttonContent && (
|
||||||
|
@ -135,7 +135,7 @@ const DateTimeInput: FC<InputProps> = ({ date, label, onChange, isFullscreen, on
|
|||||||
}
|
}
|
||||||
}, [internalDate.value, onChange]);
|
}, [internalDate.value, onChange]);
|
||||||
|
|
||||||
const icon = <Button icon="calendar-alt" variant="secondary" onClick={onOpen} />;
|
const icon = <Button aria-label="Time picker" icon="calendar-alt" variant="secondary" onClick={onOpen} />;
|
||||||
return (
|
return (
|
||||||
<InlineField
|
<InlineField
|
||||||
label={label}
|
label={label}
|
||||||
@ -195,7 +195,9 @@ const DateTimeCalendar: FC<DateTimeCalendarProps> = ({ date, onClose, onChange,
|
|||||||
prev2Label={null}
|
prev2Label={null}
|
||||||
value={internalDate}
|
value={internalDate}
|
||||||
nextLabel={<Icon name="angle-right" />}
|
nextLabel={<Icon name="angle-right" />}
|
||||||
|
nextAriaLabel="Next month"
|
||||||
prevLabel={<Icon name="angle-left" />}
|
prevLabel={<Icon name="angle-left" />}
|
||||||
|
prevAriaLabel="Previous month"
|
||||||
onChange={onChangeDate}
|
onChange={onChangeDate}
|
||||||
locale="en"
|
locale="en"
|
||||||
className={calendarStyles.body}
|
className={calendarStyles.body}
|
||||||
|
@ -5,7 +5,7 @@ import { Select } from '../Select/Select';
|
|||||||
import { useFieldDisplayNames, useSelectOptions, frameHasName } from './utils';
|
import { useFieldDisplayNames, useSelectOptions, frameHasName } from './utils';
|
||||||
|
|
||||||
export const FieldNameMatcherEditor = memo<MatcherUIProps<string>>((props) => {
|
export const FieldNameMatcherEditor = memo<MatcherUIProps<string>>((props) => {
|
||||||
const { data, options, onChange: onChangeFromProps } = props;
|
const { data, options, onChange: onChangeFromProps, id } = props;
|
||||||
const names = useFieldDisplayNames(data);
|
const names = useFieldDisplayNames(data);
|
||||||
const selectOptions = useSelectOptions(names, options);
|
const selectOptions = useSelectOptions(names, options);
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ export const FieldNameMatcherEditor = memo<MatcherUIProps<string>>((props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectedOption = selectOptions.find((v) => v.value === options);
|
const selectedOption = selectOptions.find((v) => v.value === options);
|
||||||
return <Select menuShouldPortal value={selectedOption} options={selectOptions} onChange={onChange} />;
|
return <Select menuShouldPortal value={selectedOption} options={selectOptions} onChange={onChange} inputId={id} />;
|
||||||
});
|
});
|
||||||
FieldNameMatcherEditor.displayName = 'FieldNameMatcherEditor';
|
FieldNameMatcherEditor.displayName = 'FieldNameMatcherEditor';
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { FieldMatcherID, fieldMatchers, SelectableValue, FieldType, DataFrame }
|
|||||||
import { Select } from '../Select/Select';
|
import { Select } from '../Select/Select';
|
||||||
|
|
||||||
export const FieldTypeMatcherEditor = memo<MatcherUIProps<string>>((props) => {
|
export const FieldTypeMatcherEditor = memo<MatcherUIProps<string>>((props) => {
|
||||||
const { data, options, onChange: onChangeFromProps } = props;
|
const { data, options, onChange: onChangeFromProps, id } = props;
|
||||||
const counts = useFieldCounts(data);
|
const counts = useFieldCounts(data);
|
||||||
const selectOptions = useSelectOptions(counts, options);
|
const selectOptions = useSelectOptions(counts, options);
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ export const FieldTypeMatcherEditor = memo<MatcherUIProps<string>>((props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectedOption = selectOptions.find((v) => v.value === options);
|
const selectedOption = selectOptions.find((v) => v.value === options);
|
||||||
return <Select menuShouldPortal value={selectedOption} options={selectOptions} onChange={onChange} />;
|
return <Select inputId={id} value={selectedOption} options={selectOptions} onChange={onChange} menuShouldPortal />;
|
||||||
});
|
});
|
||||||
FieldTypeMatcherEditor.displayName = 'FieldTypeMatcherEditor';
|
FieldTypeMatcherEditor.displayName = 'FieldTypeMatcherEditor';
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ export interface FieldMatcherUIRegistryItem<TOptions> extends RegistryItem {
|
|||||||
|
|
||||||
export interface MatcherUIProps<T> {
|
export interface MatcherUIProps<T> {
|
||||||
matcher: FieldMatcherInfo<T>;
|
matcher: FieldMatcherInfo<T>;
|
||||||
|
id?: string;
|
||||||
data: DataFrame[];
|
data: DataFrame[];
|
||||||
options: T;
|
options: T;
|
||||||
onChange: (options: T) => void;
|
onChange: (options: T) => void;
|
||||||
|
@ -3,6 +3,7 @@ import { cx } from '@emotion/css';
|
|||||||
|
|
||||||
export interface CardProps {
|
export interface CardProps {
|
||||||
logoUrl?: string;
|
logoUrl?: string;
|
||||||
|
logoAlt?: string;
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
labels?: React.ReactNode;
|
labels?: React.ReactNode;
|
||||||
@ -14,6 +15,7 @@ export interface CardProps {
|
|||||||
|
|
||||||
export const Card: React.FC<CardProps> = ({
|
export const Card: React.FC<CardProps> = ({
|
||||||
logoUrl,
|
logoUrl,
|
||||||
|
logoAlt,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
labels,
|
labels,
|
||||||
@ -26,7 +28,7 @@ export const Card: React.FC<CardProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={mainClassName} onClick={onClick} aria-label={ariaLabel}>
|
<div className={mainClassName} onClick={onClick} aria-label={ariaLabel}>
|
||||||
{logoUrl && <img className="add-data-source-item-logo" src={logoUrl} />}
|
{logoUrl && <img className="add-data-source-item-logo" src={logoUrl} alt={logoAlt ?? ''} />}
|
||||||
<div className="add-data-source-item-text-wrapper">
|
<div className="add-data-source-item-text-wrapper">
|
||||||
<span className="add-data-source-item-text">{title}</span>
|
<span className="add-data-source-item-text">{title}</span>
|
||||||
{description && <span className="add-data-source-item-desc">{description}</span>}
|
{description && <span className="add-data-source-item-desc">{description}</span>}
|
||||||
|
@ -9,6 +9,7 @@ export type OrgSelectItem = SelectableValue<Organization>;
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
onSelected: (org: OrgSelectItem) => void;
|
onSelected: (org: OrgSelectItem) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
inputId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
@ -43,12 +44,13 @@ export class OrgPicker extends PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { className, onSelected } = this.props;
|
const { className, onSelected, inputId } = this.props;
|
||||||
const { isLoading } = this.state;
|
const { isLoading } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncSelect
|
<AsyncSelect
|
||||||
menuShouldPortal
|
menuShouldPortal
|
||||||
|
inputId={inputId}
|
||||||
className={className}
|
className={className}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
defaultOptions={true}
|
defaultOptions={true}
|
||||||
|
@ -121,6 +121,7 @@ export function getFieldOverrideCategories(props: OptionPaneRenderProps): Option
|
|||||||
render: function renderMatcherUI() {
|
render: function renderMatcherUI() {
|
||||||
return (
|
return (
|
||||||
<matcherUi.component
|
<matcherUi.component
|
||||||
|
id={`${matcherUi.matcher.id}-${idx}`}
|
||||||
matcher={matcherUi.matcher}
|
matcher={matcherUi.matcher}
|
||||||
data={props.data?.series ?? []}
|
data={props.data?.series ?? []}
|
||||||
options={override.matcher.options}
|
options={override.matcher.options}
|
||||||
|
@ -132,13 +132,14 @@ export const InspectDataOptions: FC<Props> = ({
|
|||||||
description="Table data is formatted with options defined in the Field and Override tabs."
|
description="Table data is formatted with options defined in the Field and Override tabs."
|
||||||
>
|
>
|
||||||
<Switch
|
<Switch
|
||||||
|
id="formatted-data-toggle"
|
||||||
value={!!options.withFieldConfig}
|
value={!!options.withFieldConfig}
|
||||||
onChange={() => onOptionsChange({ ...options, withFieldConfig: !options.withFieldConfig })}
|
onChange={() => onOptionsChange({ ...options, withFieldConfig: !options.withFieldConfig })}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
)}
|
)}
|
||||||
<Field label="Download for Excel" description="Adds header to CSV for use with Excel">
|
<Field label="Download for Excel" description="Adds header to CSV for use with Excel">
|
||||||
<Switch value={downloadForExcel} onChange={toggleDownloadForExcel} />
|
<Switch id="excel-toggle" value={downloadForExcel} onChange={toggleDownloadForExcel} />
|
||||||
</Field>
|
</Field>
|
||||||
</HorizontalGroup>
|
</HorizontalGroup>
|
||||||
</VerticalGroup>
|
</VerticalGroup>
|
||||||
|
@ -132,7 +132,13 @@ export class InspectJSONTab extends PureComponent<Props, State> {
|
|||||||
<>
|
<>
|
||||||
<div className={styles.toolbar} aria-label={selectors.components.PanelInspector.Json.content}>
|
<div className={styles.toolbar} aria-label={selectors.components.PanelInspector.Json.content}>
|
||||||
<Field label="Select source" className="flex-grow-1">
|
<Field label="Select source" className="flex-grow-1">
|
||||||
<Select menuShouldPortal options={jsonOptions} value={selected} onChange={this.onSelectChanged} />
|
<Select
|
||||||
|
inputId="select-source-dropdown"
|
||||||
|
options={jsonOptions}
|
||||||
|
value={selected}
|
||||||
|
onChange={this.onSelectChanged}
|
||||||
|
menuShouldPortal
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
{this.hasPanelJSON && isPanelJSON && canEdit && (
|
{this.hasPanelJSON && isPanelJSON && canEdit && (
|
||||||
<Button className={styles.toolbarItem} onClick={this.onApplyPanelModel}>
|
<Button className={styles.toolbarItem} onClick={this.onApplyPanelModel}>
|
||||||
|
@ -2,6 +2,7 @@ import React, { PropsWithChildren, ReactElement } from 'react';
|
|||||||
import { InlineFormLabel, Select, useStyles } from '@grafana/ui';
|
import { InlineFormLabel, Select, useStyles } from '@grafana/ui';
|
||||||
import { GrafanaTheme, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme, SelectableValue } from '@grafana/data';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
import { useUniqueId } from 'app/plugins/datasource/influxdb/components/useUniqueId';
|
||||||
|
|
||||||
interface VariableSelectFieldProps<T> {
|
interface VariableSelectFieldProps<T> {
|
||||||
name: string;
|
name: string;
|
||||||
@ -25,7 +26,8 @@ export function VariableSelectField({
|
|||||||
labelWidth,
|
labelWidth,
|
||||||
}: PropsWithChildren<VariableSelectFieldProps<any>>): ReactElement {
|
}: PropsWithChildren<VariableSelectFieldProps<any>>): ReactElement {
|
||||||
const styles = useStyles(getStyles);
|
const styles = useStyles(getStyles);
|
||||||
const inputId = `variable-select-input-${name}`;
|
const uniqueId = useUniqueId();
|
||||||
|
const inputId = `variable-select-input-${name}-${uniqueId}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { ChangeEvent, PropsWithChildren, ReactElement } from 'react';
|
import React, { ChangeEvent, PropsWithChildren, ReactElement } from 'react';
|
||||||
import { InlineField, InlineSwitch } from '@grafana/ui';
|
import { InlineField, InlineSwitch } from '@grafana/ui';
|
||||||
|
import { useUniqueId } from 'app/plugins/datasource/influxdb/components/useUniqueId';
|
||||||
interface VariableSwitchFieldProps {
|
interface VariableSwitchFieldProps {
|
||||||
value: boolean;
|
value: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
@ -15,9 +16,16 @@ export function VariableSwitchField({
|
|||||||
onChange,
|
onChange,
|
||||||
ariaLabel,
|
ariaLabel,
|
||||||
}: PropsWithChildren<VariableSwitchFieldProps>): ReactElement {
|
}: PropsWithChildren<VariableSwitchFieldProps>): ReactElement {
|
||||||
|
const uniqueId = useUniqueId();
|
||||||
return (
|
return (
|
||||||
<InlineField label={name} labelWidth={20} tooltip={tooltip}>
|
<InlineField label={name} labelWidth={20} tooltip={tooltip}>
|
||||||
<InlineSwitch label={name} value={value} onChange={onChange} aria-label={ariaLabel} />
|
<InlineSwitch
|
||||||
|
id={`var-switch-${uniqueId}`}
|
||||||
|
label={name}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-6">Scale</label>
|
<label for="yaxis-scale-select-{{$index}}" class="gf-form-label width-6">Scale</label>
|
||||||
<div class="gf-form-select-wrapper max-width-20">
|
<div class="gf-form-select-wrapper max-width-20">
|
||||||
<select
|
<select
|
||||||
|
id="yaxis-scale-select-{{$index}}"
|
||||||
class="gf-form-input"
|
class="gf-form-input"
|
||||||
ng-model="yaxis.logBase"
|
ng-model="yaxis.logBase"
|
||||||
ng-options="v as k for (k, v) in ctrl.logScales"
|
ng-options="v as k for (k, v) in ctrl.logScales"
|
||||||
@ -75,8 +76,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-6">Label</label>
|
<label for="yaxis-label-select-{{$index}}" class="gf-form-label width-6">Label</label>
|
||||||
<input
|
<input
|
||||||
|
id="yaxis-label-select-{{$index}}"
|
||||||
type="text"
|
type="text"
|
||||||
class="gf-form-input max-width-20"
|
class="gf-form-input max-width-20"
|
||||||
ng-model="yaxis.label"
|
ng-model="yaxis.label"
|
||||||
@ -125,15 +127,15 @@
|
|||||||
></gf-form-switch>
|
></gf-form-switch>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-6">Mode</label>
|
<label for="xaxis-mode-select" class="gf-form-label width-6">Mode</label>
|
||||||
<div class="gf-form-select-wrapper max-width-15">
|
<div class="gf-form-select-wrapper max-width-15">
|
||||||
<select
|
<select
|
||||||
|
id="xaxis-mode-select"
|
||||||
class="gf-form-input"
|
class="gf-form-input"
|
||||||
ng-model="ctrl.panel.xaxis.mode"
|
ng-model="ctrl.panel.xaxis.mode"
|
||||||
ng-options="v as k for (k, v) in ctrl.xAxisModes"
|
ng-options="v as k for (k, v) in ctrl.xAxisModes"
|
||||||
ng-change="ctrl.xAxisModeChanged()"
|
ng-change="ctrl.xAxisModeChanged()"
|
||||||
>
|
></select>
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ $text-color-strong: #fff;
|
|||||||
$text-color: rgb(204, 204, 220);
|
$text-color: rgb(204, 204, 220);
|
||||||
$text-color-semi-weak: rgba(204, 204, 220, 0.65);
|
$text-color-semi-weak: rgba(204, 204, 220, 0.65);
|
||||||
$text-color-weak: rgba(204, 204, 220, 0.65);
|
$text-color-weak: rgba(204, 204, 220, 0.65);
|
||||||
$text-color-faint: rgba(204, 204, 220, 0.57);
|
$text-color-faint: rgba(204, 204, 220, 0.58);
|
||||||
$text-color-emphasis: #fff;
|
$text-color-emphasis: #fff;
|
||||||
$text-blue: #6E9FFF;
|
$text-blue: #6E9FFF;
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ $brand-gradient-vertical: linear-gradient(#f05a28 30%, #fbca0a 99%);
|
|||||||
// Links
|
// Links
|
||||||
// -------------------------
|
// -------------------------
|
||||||
$link-color: rgb(204, 204, 220);
|
$link-color: rgb(204, 204, 220);
|
||||||
$link-color-disabled: rgba(204, 204, 220, 0.57);
|
$link-color-disabled: rgba(204, 204, 220, 0.58);
|
||||||
$link-hover-color: #fff;
|
$link-hover-color: #fff;
|
||||||
$external-link-color: #6E9FFF;
|
$external-link-color: #6E9FFF;
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ $input-border-color: rgba(204, 204, 220, 0.15);
|
|||||||
$input-box-shadow: none;
|
$input-box-shadow: none;
|
||||||
$input-border-focus: #6E9FFF;
|
$input-border-focus: #6E9FFF;
|
||||||
$input-box-shadow-focus: #6E9FFF !default;
|
$input-box-shadow-focus: #6E9FFF !default;
|
||||||
$input-color-placeholder: rgba(204, 204, 220, 0.57);
|
$input-color-placeholder: rgba(204, 204, 220, 0.58);
|
||||||
$input-label-bg: #22252b;
|
$input-label-bg: #22252b;
|
||||||
$input-color-select-arrow: $white;
|
$input-color-select-arrow: $white;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user