mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
A11y: Fix fastpass issues for /org/teams pages (#39848)
* A11y: Fix fastpass issues for /org/teams pages See #39429
This commit is contained in:
parent
b711bc00b9
commit
451d023c79
@ -10,9 +10,10 @@ export interface Props {
|
||||
size?: ComponentSize;
|
||||
/** Disable button click action */
|
||||
disabled?: boolean;
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
export const DeleteButton: FC<Props> = ({ size, disabled, onConfirm }) => {
|
||||
export const DeleteButton: FC<Props> = ({ size, disabled, onConfirm, 'aria-label': ariaLabel }) => {
|
||||
return (
|
||||
<ConfirmButton
|
||||
confirmText="Delete"
|
||||
@ -21,7 +22,7 @@ export const DeleteButton: FC<Props> = ({ size, disabled, onConfirm }) => {
|
||||
disabled={disabled}
|
||||
onConfirm={onConfirm}
|
||||
>
|
||||
<Button variant="destructive" icon="times" size={size || 'sm'} />
|
||||
<Button aria-label={ariaLabel} variant="destructive" icon="times" size={size || 'sm'} />
|
||||
</ConfirmButton>
|
||||
);
|
||||
};
|
||||
|
@ -308,7 +308,7 @@ $checkboxImageUrl: '../img/checkbox_white.png';
|
||||
$info-box-border-color: $blue-base;
|
||||
|
||||
// footer
|
||||
$footer-link-color: $gray-3;
|
||||
$footer-link-color: $gray-1;
|
||||
$footer-link-hover: $dark-2;
|
||||
|
||||
// json explorer
|
||||
|
@ -5,11 +5,12 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
type Props = {
|
||||
onClick: () => void;
|
||||
'aria-label'?: string;
|
||||
};
|
||||
|
||||
export const CloseButton: React.FC<Props> = ({ onClick }) => {
|
||||
export const CloseButton: React.FC<Props> = ({ onClick, 'aria-label': ariaLabel }) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
return <IconButton className={styles} name="times" onClick={onClick} />;
|
||||
return <IconButton aria-label={ariaLabel ?? 'Close'} className={styles} name="times" onClick={onClick} />;
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) =>
|
||||
|
@ -48,9 +48,11 @@ const EmptyListCTA: React.FunctionComponent<Props> = ({
|
||||
<span key="proTipFooter">
|
||||
<Icon name="rocket" />
|
||||
<> ProTip: {proTip} </>
|
||||
<a href={proTipLink} target={proTipTarget} className="text-link">
|
||||
{proTipLinkTitle}
|
||||
</a>
|
||||
{proTipLink && (
|
||||
<a href={proTipLink} target={proTipTarget} className="text-link">
|
||||
{proTipLinkTitle}
|
||||
</a>
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
|
@ -15,6 +15,7 @@ import { SelectableValue } from '@grafana/data';
|
||||
export interface Props {
|
||||
onSelected: (user: SelectableValue<OrgUser['userId']>) => void;
|
||||
className?: string;
|
||||
inputId?: string;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
@ -59,7 +60,7 @@ export class UserPicker extends Component<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, onSelected } = this.props;
|
||||
const { className, onSelected, inputId } = this.props;
|
||||
const { isLoading } = this.state;
|
||||
|
||||
return (
|
||||
@ -68,6 +69,7 @@ export class UserPicker extends Component<Props, State> {
|
||||
menuShouldPortal
|
||||
isClearable
|
||||
className={className}
|
||||
inputId={inputId}
|
||||
isLoading={isLoading}
|
||||
defaultOptions={true}
|
||||
loadOptions={this.debouncedSearch}
|
||||
|
@ -135,7 +135,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
|
||||
|
||||
<Field
|
||||
label={
|
||||
<Label>
|
||||
<Label htmlFor="home-dashboard-select">
|
||||
<span className={styles.labelText}>Home Dashboard</span>
|
||||
<Tooltip content="Not finding the dashboard you want? Star it first, then it should appear in this select box.">
|
||||
<Icon name="info-circle" />
|
||||
@ -154,6 +154,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
|
||||
}
|
||||
options={dashboards}
|
||||
placeholder="Choose default dashboard"
|
||||
inputId="home-dashboard-select"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
|
@ -33,7 +33,7 @@ export class CreateTeam extends PureComponent<Props> {
|
||||
{({ register }) => (
|
||||
<FieldSet label="New Team">
|
||||
<Field label="Name">
|
||||
<Input {...register('name', { required: true })} width={60} />
|
||||
<Input {...register('name', { required: true })} id="team-name" width={60} />
|
||||
</Field>
|
||||
<Field
|
||||
label={
|
||||
|
@ -52,20 +52,27 @@ export class TeamList extends PureComponent<Props, any> {
|
||||
<tr key={team.id}>
|
||||
<td className="width-4 text-center link-td">
|
||||
<a href={teamUrl}>
|
||||
<img className="filter-table__avatar" src={team.avatarUrl} />
|
||||
<img className="filter-table__avatar" src={team.avatarUrl} alt="Team avatar" />
|
||||
</a>
|
||||
</td>
|
||||
<td className="link-td">
|
||||
<a href={teamUrl}>{team.name}</a>
|
||||
</td>
|
||||
<td className="link-td">
|
||||
<a href={teamUrl}>{team.email}</a>
|
||||
<a href={teamUrl} aria-label={team.email?.length > 0 ? undefined : 'Empty email cell'}>
|
||||
{team.email}
|
||||
</a>
|
||||
</td>
|
||||
<td className="link-td">
|
||||
<a href={teamUrl}>{team.memberCount}</a>
|
||||
</td>
|
||||
<td className="text-right">
|
||||
<DeleteButton size="sm" disabled={!canDelete} onConfirm={() => this.deleteTeam(team)} />
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
size="sm"
|
||||
disabled={!canDelete}
|
||||
onConfirm={() => this.deleteTeam(team)}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
@ -89,7 +89,11 @@ export class TeamMemberRow extends PureComponent<Props> {
|
||||
return (
|
||||
<tr key={member.userId}>
|
||||
<td className="width-4 text-center">
|
||||
<img className="filter-table__avatar" src={member.avatarUrl} />
|
||||
<img
|
||||
aria-label={`Avatar for team member "${member.name}"`}
|
||||
className="filter-table__avatar"
|
||||
src={member.avatarUrl}
|
||||
/>
|
||||
</td>
|
||||
<td>{member.login}</td>
|
||||
<td>{member.email}</td>
|
||||
@ -97,7 +101,12 @@ export class TeamMemberRow extends PureComponent<Props> {
|
||||
{this.renderPermissions(member)}
|
||||
{syncEnabled && this.renderLabels(member.labels)}
|
||||
<td className="text-right">
|
||||
<DeleteButton size="sm" disabled={!signedInUserIsTeamAdmin} onConfirm={() => this.onRemoveMember(member)} />
|
||||
<DeleteButton
|
||||
aria-label="Remove team member"
|
||||
size="sm"
|
||||
disabled={!signedInUserIsTeamAdmin}
|
||||
onConfirm={() => this.onRemoveMember(member)}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
@ -12,7 +12,7 @@ import { contextSrv } from 'app/core/services/context_srv';
|
||||
import TeamMemberRow from './TeamMemberRow';
|
||||
import { setSearchMemberQuery } from './state/reducers';
|
||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
||||
import { Button, FilterInput } from '@grafana/ui';
|
||||
import { Button, FilterInput, Label } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
function mapStateToProps(state: any) {
|
||||
@ -97,10 +97,10 @@ export class TeamMembers extends PureComponent<Props, State> {
|
||||
|
||||
<SlideDown in={isAdding}>
|
||||
<div className="cta-form">
|
||||
<CloseButton onClick={this.onToggleAdding} />
|
||||
<h5>Add team member</h5>
|
||||
<CloseButton aria-label="Close 'Add team member' dialogue" onClick={this.onToggleAdding} />
|
||||
<Label htmlFor="user-picker">Add team member</Label>
|
||||
<div className="gf-form-inline">
|
||||
<UserPicker onSelected={this.onUserSelected} className="min-width-30" />
|
||||
<UserPicker inputId="user-picker" onSelected={this.onUserSelected} className="min-width-30" />
|
||||
{this.state.newTeamMember && (
|
||||
<Button type="submit" onClick={this.onAddUserToTeam}>
|
||||
Add to team
|
||||
|
@ -30,14 +30,14 @@ export const TeamSettings: FC<Props> = ({ team, updateTeam }) => {
|
||||
{({ register }) => (
|
||||
<>
|
||||
<Field label="Name">
|
||||
<Input {...register('name', { required: true })} />
|
||||
<Input {...register('name', { required: true })} id="name-input" />
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="Email"
|
||||
description="This is optional and is primarily used to set the team profile avatar (via gravatar service)."
|
||||
>
|
||||
<Input {...register('email')} placeholder="team@email.com" type="email" />
|
||||
<Input {...register('email')} placeholder="team@email.com" type="email" id="email-input" />
|
||||
</Field>
|
||||
<Button type="submit">Update</Button>
|
||||
</>
|
||||
|
@ -92,6 +92,7 @@ exports[`Render should render teams table 1`] = `
|
||||
href="org/teams/edit/1"
|
||||
>
|
||||
<img
|
||||
alt="Team avatar"
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -128,6 +129,7 @@ exports[`Render should render teams table 1`] = `
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
disabled={false}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -144,6 +146,7 @@ exports[`Render should render teams table 1`] = `
|
||||
href="org/teams/edit/2"
|
||||
>
|
||||
<img
|
||||
alt="Team avatar"
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -180,6 +183,7 @@ exports[`Render should render teams table 1`] = `
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
disabled={false}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -196,6 +200,7 @@ exports[`Render should render teams table 1`] = `
|
||||
href="org/teams/edit/3"
|
||||
>
|
||||
<img
|
||||
alt="Team avatar"
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -232,6 +237,7 @@ exports[`Render should render teams table 1`] = `
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
disabled={false}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -248,6 +254,7 @@ exports[`Render should render teams table 1`] = `
|
||||
href="org/teams/edit/4"
|
||||
>
|
||||
<img
|
||||
alt="Team avatar"
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -284,6 +291,7 @@ exports[`Render should render teams table 1`] = `
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
disabled={false}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -300,6 +308,7 @@ exports[`Render should render teams table 1`] = `
|
||||
href="org/teams/edit/5"
|
||||
>
|
||||
<img
|
||||
alt="Team avatar"
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -336,6 +345,7 @@ exports[`Render should render teams table 1`] = `
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
disabled={false}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -422,6 +432,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on and signedin us
|
||||
href="org/teams/edit/1"
|
||||
>
|
||||
<img
|
||||
alt="Team avatar"
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -458,6 +469,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on and signedin us
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
disabled={true}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -544,6 +556,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on and signedin us
|
||||
href="org/teams/edit/1"
|
||||
>
|
||||
<img
|
||||
alt="Team avatar"
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -580,6 +593,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on and signedin us
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Delete team"
|
||||
disabled={true}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
|
@ -8,6 +8,7 @@ exports[`Render should render team members when sync enabled 1`] = `
|
||||
className="width-4 text-center"
|
||||
>
|
||||
<img
|
||||
aria-label="Avatar for team member \\"testName\\""
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -49,6 +50,7 @@ exports[`Render should render team members when sync enabled 1`] = `
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Remove team member"
|
||||
disabled={true}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -65,6 +67,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned off should not ren
|
||||
className="width-4 text-center"
|
||||
>
|
||||
<img
|
||||
aria-label="Avatar for team member \\"testName\\""
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -140,6 +143,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned off should not ren
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Remove team member"
|
||||
disabled={false}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -156,6 +160,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render p
|
||||
className="width-4 text-center"
|
||||
>
|
||||
<img
|
||||
aria-label="Avatar for team member \\"testName\\""
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -231,6 +236,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render p
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Remove team member"
|
||||
disabled={false}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
@ -247,6 +253,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render s
|
||||
className="width-4 text-center"
|
||||
>
|
||||
<img
|
||||
aria-label="Avatar for team member \\"testName\\""
|
||||
className="filter-table__avatar"
|
||||
src="some/url/"
|
||||
/>
|
||||
@ -279,6 +286,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render s
|
||||
className="text-right"
|
||||
>
|
||||
<DeleteButton
|
||||
aria-label="Remove team member"
|
||||
disabled={true}
|
||||
onConfirm={[Function]}
|
||||
size="sm"
|
||||
|
@ -29,16 +29,20 @@ exports[`Render should render component 1`] = `
|
||||
className="cta-form"
|
||||
>
|
||||
<CloseButton
|
||||
aria-label="Close 'Add team member' dialogue"
|
||||
onClick={[Function]}
|
||||
/>
|
||||
<h5>
|
||||
<Label
|
||||
htmlFor="user-picker"
|
||||
>
|
||||
Add team member
|
||||
</h5>
|
||||
</Label>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<UserPicker
|
||||
className="min-width-30"
|
||||
inputId="user-picker"
|
||||
onSelected={[Function]}
|
||||
/>
|
||||
</div>
|
||||
@ -113,16 +117,20 @@ exports[`Render should render team members 1`] = `
|
||||
className="cta-form"
|
||||
>
|
||||
<CloseButton
|
||||
aria-label="Close 'Add team member' dialogue"
|
||||
onClick={[Function]}
|
||||
/>
|
||||
<h5>
|
||||
<Label
|
||||
htmlFor="user-picker"
|
||||
>
|
||||
Add team member
|
||||
</h5>
|
||||
</Label>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
<UserPicker
|
||||
className="min-width-30"
|
||||
inputId="user-picker"
|
||||
onSelected={[Function]}
|
||||
/>
|
||||
</div>
|
||||
|
@ -101,7 +101,7 @@ $text-color-strong: #fff;
|
||||
$text-color: rgb(204, 204, 220);
|
||||
$text-color-semi-weak: rgba(204, 204, 220, 0.65);
|
||||
$text-color-weak: rgba(204, 204, 220, 0.65);
|
||||
$text-color-faint: rgba(204, 204, 220, 0.40);
|
||||
$text-color-faint: rgba(204, 204, 220, 0.57);
|
||||
$text-color-emphasis: #fff;
|
||||
$text-blue: #6E9FFF;
|
||||
|
||||
@ -115,7 +115,7 @@ $brand-gradient-vertical: linear-gradient(#f05a28 30%, #fbca0a 99%);
|
||||
// Links
|
||||
// -------------------------
|
||||
$link-color: rgb(204, 204, 220);
|
||||
$link-color-disabled: rgba(204, 204, 220, 0.40);
|
||||
$link-color-disabled: rgba(204, 204, 220, 0.57);
|
||||
$link-hover-color: #fff;
|
||||
$external-link-color: #6E9FFF;
|
||||
|
||||
@ -216,7 +216,7 @@ $input-border-color: rgba(204, 204, 220, 0.15);
|
||||
$input-box-shadow: none;
|
||||
$input-border-focus: #6E9FFF;
|
||||
$input-box-shadow-focus: #6E9FFF !default;
|
||||
$input-color-placeholder: rgba(204, 204, 220, 0.40);
|
||||
$input-color-placeholder: rgba(204, 204, 220, 0.57);
|
||||
$input-label-bg: #22252b;
|
||||
$input-color-select-arrow: $white;
|
||||
|
||||
|
@ -310,7 +310,7 @@ $checkboxImageUrl: '../img/checkbox_white.png';
|
||||
$info-box-border-color: $blue-base;
|
||||
|
||||
// footer
|
||||
$footer-link-color: $gray-3;
|
||||
$footer-link-color: $gray-1;
|
||||
$footer-link-hover: $dark-2;
|
||||
|
||||
// json explorer
|
||||
|
@ -53,7 +53,8 @@
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: $space-inset-squish-md;
|
||||
padding: 0px $space-sm;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user