A11y: Fix fastpass issues for /org/ pages (#39902)

* A11y: Fix fastpass issues for /org/ pages
See #39429
This commit is contained in:
kay delaney 2021-10-01 15:58:18 +01:00 committed by GitHub
parent 54afe20b44
commit 816d70a7e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 34 deletions

View File

@ -80,7 +80,7 @@ export function Modal(props: PropsWithChildren<Props>) {
{typeof title === 'string' && <DefaultModalHeader {...props} title={title} />}
{typeof title !== 'string' && title}
<div className={styles.modalHeaderClose}>
<IconButton surface="header" name="times" size="xl" onClick={onDismiss} />
<IconButton aria-label="Close dialogue" surface="header" name="times" size="xl" onClick={onDismiss} />
</div>
</div>
<div className={cx(styles.modalContent, contentClassName)}>{children}</div>

View File

@ -1,11 +1,15 @@
import React, { ChangeEvent, FC, FormEvent, useEffect, useState } from 'react';
import { EventsWithValidation, InlineFormLabel, LegacyForms, ValidationEvents, Button } from '@grafana/ui';
import { EventsWithValidation, LegacyForms, ValidationEvents, Button, Select, InlineField } from '@grafana/ui';
import { NewApiKey, OrgRole } from '../../types';
import { rangeUtil } from '@grafana/data';
import { rangeUtil, SelectableValue } from '@grafana/data';
import { SlideDown } from '../../core/components/Animations/SlideDown';
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
const { Input } = LegacyForms;
const ROLE_OPTIONS: Array<SelectableValue<OrgRole>> = Object.keys(OrgRole).map((role) => ({
label: role,
value: role as OrgRole,
}));
interface Props {
show: boolean;
@ -56,8 +60,8 @@ export const ApiKeysForm: FC<Props> = ({ show, onClose, onKeyAdded }) => {
const onNameChange = (event: ChangeEvent<HTMLInputElement>) => {
setName(event.currentTarget.value);
};
const onRoleChange = (event: ChangeEvent<HTMLSelectElement>) => {
setRole(event.currentTarget.value as OrgRole);
const onRoleChange = (role: SelectableValue<OrgRole>) => {
setRole(role.value!);
};
const onSecondsToLiveChange = (event: ChangeEvent<HTMLInputElement>) => {
setSecondsToLive(event.currentTarget.value);
@ -75,29 +79,27 @@ export const ApiKeysForm: FC<Props> = ({ show, onClose, onKeyAdded }) => {
<Input type="text" className="gf-form-input" value={name} placeholder="Name" onChange={onNameChange} />
</div>
<div className="gf-form">
<span className="gf-form-label">Role</span>
<span className="gf-form-select-wrapper">
<select className="gf-form-input gf-size-auto" value={role} onChange={onRoleChange}>
{Object.keys(OrgRole).map((role) => {
return (
<option key={role} label={role} value={role}>
{role}
</option>
);
})}
</select>
</span>
<InlineField label="Role">
<Select
inputId="role-select"
value={role}
onChange={onRoleChange}
options={ROLE_OPTIONS}
menuShouldPortal
/>
</InlineField>
</div>
<div className="gf-form max-width-21">
<InlineFormLabel tooltip={tooltipText}>Time to live</InlineFormLabel>
<Input
type="text"
className="gf-form-input"
placeholder="1d"
validationEvents={timeRangeValidationEvents}
value={secondsToLive}
onChange={onSecondsToLiveChange}
/>
<InlineField tooltip={tooltipText} label="Time to live">
<Input
id="time-to-live-input"
type="text"
placeholder="1d"
validationEvents={timeRangeValidationEvents}
value={secondsToLive}
onChange={onSecondsToLiveChange}
/>
</InlineField>
</div>
<div className="gf-form">
<Button>Add</Button>

View File

@ -124,8 +124,8 @@ describe('ApiKeysPage', () => {
deleteApiKeyMock.mockClear();
expect(within(firstRow).getByRole('cell', { name: /cancel delete/i })).toBeInTheDocument();
userEvent.click(within(firstRow).getByRole('cell', { name: /cancel delete/i }));
expect(within(firstRow).getByRole('button', { name: /delete/i })).toBeInTheDocument();
userEvent.click(within(firstRow).getByRole('button', { name: /delete/i }));
expect(within(firstRow).getByRole('button', { name: /delete$/i })).toBeInTheDocument();
userEvent.click(within(firstRow).getByRole('button', { name: /delete$/i }));
expect(deleteApiKeyMock).toHaveBeenCalledTimes(1);
expect(deleteApiKeyMock).toHaveBeenCalledWith(1, false);
@ -134,8 +134,8 @@ describe('ApiKeysPage', () => {
deleteApiKeyMock.mockClear();
expect(within(secondRow).getByRole('cell', { name: /cancel delete/i })).toBeInTheDocument();
userEvent.click(within(secondRow).getByRole('cell', { name: /cancel delete/i }));
expect(within(secondRow).getByRole('button', { name: /delete/i })).toBeInTheDocument();
userEvent.click(within(secondRow).getByRole('button', { name: /delete/i }));
expect(within(secondRow).getByRole('button', { name: /delete$/i })).toBeInTheDocument();
userEvent.click(within(secondRow).getByRole('button', { name: /delete$/i }));
expect(deleteApiKeyMock).toHaveBeenCalledTimes(1);
expect(deleteApiKeyMock).toHaveBeenCalledWith(2, true);
});
@ -194,7 +194,6 @@ function toggleShowExpired() {
async function addAndVerifyApiKey(addApiKeyMock: jest.Mock, includeExpired: boolean) {
expect(screen.getByRole('heading', { name: /add api key/i })).toBeInTheDocument();
expect(screen.getByPlaceholderText(/name/i)).toBeInTheDocument();
expect(screen.getByRole('combobox')).toBeInTheDocument();
expect(screen.getByPlaceholderText(/1d/i)).toBeInTheDocument();
expect(screen.getByRole('button', { name: /^add$/i })).toBeInTheDocument();

View File

@ -30,7 +30,7 @@ export const ApiKeysTable: FC<Props> = ({ apiKeys, timeZone, onDelete }) => {
<td>{key.role}</td>
<td>{formatDate(key.expiration, timeZone)}</td>
<td>
<DeleteButton size="sm" onConfirm={() => onDelete(key)} />
<DeleteButton aria-label="Delete API key" size="sm" onConfirm={() => onDelete(key)} />
</td>
</tr>
);

View File

@ -16,7 +16,7 @@ const OrgProfile: FC<Props> = ({ onSubmit, orgName }) => {
{({ register }) => (
<FieldSet label="Organization profile">
<Field label="Organization name">
<Input type="text" {...register('orgName', { required: true })} />
<Input id="org-name-input" type="text" {...register('orgName', { required: true })} />
</Field>
<Button type="submit">Update organization name</Button>

View File

@ -72,7 +72,7 @@ export const UserInviteForm: FC<Props> = ({}) => {
/>
</Field>
<Field label="Send invite email">
<Switch {...register('sendEmail')} />
<Switch id="send-email-switch" {...register('sendEmail')} />
</Field>
<HorizontalGroup>
<Button type="submit">Submit</Button>