Git Sync UI a11y finding fixes (#112751)

* ProgressBar: progressbar nodes must have accsible name fix

* BrowseActions: Bulk move and delete drawwer a11y fix

* FolderActionsButton: Move and delete drawer a11y fix

* ConfigForm: a11y fix missing id

* GettingStarted: Skip img alt since its decorative

* JobContent: heading a11y fix

* StatusBadge: add displayOnly prop to avoid cursor pointer display when its not necessary

* RepositoryTypeCards: Card missing discernible text

* i18n

* input id fix
This commit is contained in:
Yunwen Zheng
2025-10-23 11:25:26 -04:00
committed by GitHub
parent 62c5df36d6
commit ddc5ae6f4d
10 changed files with 81 additions and 39 deletions
@@ -2,7 +2,7 @@ import { useState } from 'react';
import { Trans, t } from '@grafana/i18n';
import { config, reportInteraction } from '@grafana/runtime';
import { Button, Drawer, Stack } from '@grafana/ui';
import { Button, Drawer, Stack, Text } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { ManagerKind } from 'app/features/apiserver/types';
import { BulkDeleteProvisionedResource } from 'app/features/provisioning/components/BulkActions/BulkDeleteProvisionedResource';
@@ -152,7 +152,12 @@ export function BrowseActions({ folderDTO }: Props) {
{/* bulk delete */}
{showBulkDeleteProvisionedResource && (
<Drawer
title={t('browse-dashboards.action.bulk-delete-provisioned-resources', 'Bulk Delete Provisioned Resources')}
title={
// Heading levels should only increase by one (a11y)
<Text variant="h3" element="h2">
{t('browse-dashboards.action.bulk-delete-provisioned-resources', 'Bulk Delete Provisioned Resources')}
</Text>
}
onClose={() => setShowBulkDeleteProvisionedResource(false)}
size="md"
>
@@ -169,7 +174,12 @@ export function BrowseActions({ folderDTO }: Props) {
{/* bulk move */}
{showBulkMoveProvisionedResource && (
<Drawer
title={t('browse-dashboards.action.bulk-move-provisioned-resources', 'Bulk Move Provisioned Resources')}
title={
// Heading levels should only increase by one (a11y)
<Text variant="h3" element="h2">
{t('browse-dashboards.action.bulk-move-provisioned-resources', 'Bulk Move Provisioned Resources')}
</Text>
}
onClose={() => setShowBulkMoveProvisionedResource(false)}
size="md"
>
@@ -3,7 +3,7 @@ import { useState } from 'react';
import { AppEvents } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { locationService, reportInteraction } from '@grafana/runtime';
import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
import { Button, Drawer, Dropdown, Icon, Menu, MenuItem, Text } from '@grafana/ui';
import { Permissions } from 'app/core/components/AccessControl/Permissions';
import { appEvents } from 'app/core/core';
import { RepoType } from 'app/features/provisioning/Wizard/types';
@@ -180,7 +180,11 @@ export function FolderActionsButton({ folder, repoType, isReadOnlyRepo }: Props)
)}
{showDeleteProvisionedFolderDrawer && (
<Drawer
title={t('browse-dashboards.action.delete-provisioned-folder', 'Delete provisioned folder')}
title={
<Text variant="h3" element="h2">
{t('browse-dashboards.action.delete-provisioned-folder', 'Delete provisioned folder')}
</Text>
}
subtitle={folder.title}
onClose={() => setShowDeleteProvisionedFolderDrawer(false)}
>
@@ -192,7 +196,11 @@ export function FolderActionsButton({ folder, repoType, isReadOnlyRepo }: Props)
)}
{showMoveProvisionedFolderDrawer && (
<Drawer
title={t('browse-dashboards.action.move-provisioned-folder', 'Move provisioned folder')}
title={
<Text variant="h3" element="h2">
{t('browse-dashboards.action.move-provisioned-folder', 'Move provisioned folder')}
</Text>
}
subtitle={folder.title}
onClose={() => setShowMoveProvisionedFolderDrawer(false)}
>
@@ -162,7 +162,7 @@ export function ConfigForm({ data }: ConfigFormProps) {
<FormPrompt onDiscard={reset} confirmRedirect={isDirty} />
<Stack direction="column" gap={2}>
<Field noMargin label={t('provisioning.config-form.label-repository-type', 'Repository type')}>
<Input value={getRepositoryTypeConfig(type)?.label || type} disabled />
<Input id="repository-type" value={getRepositoryTypeConfig(type)?.label || type} disabled />
</Field>
<Field
noMargin
@@ -274,7 +274,7 @@ export function ConfigForm({ data }: ConfigFormProps) {
/>
</Field>
<Field noMargin label={gitFields.pathConfig.label} description={gitFields.pathConfig.description}>
<Input {...register('path')} />
<Input id="repository-path" {...register('path')} />
</Field>
</>
)}
@@ -153,7 +153,8 @@ export default function GettingStarted({ items }: Props) {
<Stack direction="column" gap={6} wrap="wrap">
<Stack gap={10} alignItems="center">
<div className={styles.imageContainer}>
<img src={provisioningSvg} className={styles.image} alt={'Grafana provisioning'} />
{/* decorative img, use empty str to skip alt*/}
<img src={provisioningSvg} className={styles.image} alt="" />
</div>
<FeaturesList
hasRequiredFeatures={hasRequiredFeatures}
@@ -79,7 +79,7 @@ export function JobContent({ jobType, job, isFinishedJob = false, onStatusChange
<Stack direction="column" alignItems="center">
<Stack direction="row" alignItems="center" justifyContent="center" gap={2}>
<Spinner size={24} />
<Text element="h5" color="secondary">
<Text element="h3" variant="h5" color="secondary">
{message ?? state ?? t('provisioning.job-status.starting', 'Starting...')}
</Text>
</Stack>
@@ -27,7 +27,7 @@ export function RepositoryActions({ repository }: RepositoryActionsProps) {
return (
<Stack wrap="wrap">
{isReadOnlyRepo && <Badge color="darkgrey" text={t('folder-repo.read-only-badge', 'Read only')} />}
<StatusBadge repo={repository} />
<StatusBadge repo={repository} displayOnly />
{repoHref && (
<Button variant="secondary" icon={providerIcon} onClick={() => window.open(repoHref, '_blank')}>
<Trans i18nKey="provisioning.repository-actions.source-code">Source code</Trans>
@@ -2,6 +2,7 @@ import { css } from '@emotion/css';
import { useRef, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { t } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui';
interface ProgressBarProps {
@@ -24,7 +25,14 @@ const ProgressBar = ({ progress, topBottomSpacing }: ProgressBarProps) => {
}
return (
<div className={styles.container}>
<div
className={styles.container}
aria-label={t('provisioning.shared.progress-bar.aria-label', 'Progress Bar')}
role="progressbar"
aria-valuenow={progress}
aria-valuemin={0}
aria-valuemax={100}
>
<div className={shouldAnimate ? styles.fillerAnimated : styles.filler} style={{ width: `${progress}%` }} />
</div>
);
@@ -27,15 +27,17 @@ export function RepositoryTypeCards() {
<Stack direction="row" gap={1} wrap>
{gitProviders.map((config) => (
<Card key={config.type} href={`${CONNECT_URL}/${config.type}`} className={styles.card} noMargin>
<Stack gap={2} alignItems="center">
<RepoIcon type={config.type} />
<Trans
i18nKey="provisioning.repository-type-cards.configure-with-provider"
values={{ provider: config.label }}
>
Configure with {'{{ provider }}'}
</Trans>
</Stack>
<Card.Heading>
<Stack gap={2} alignItems="center">
<RepoIcon type={config.type} />
<Trans
i18nKey="provisioning.repository-type-cards.configure-with-provider"
values={{ provider: config.label }}
>
Configure with {'{{ provider }}'}
</Trans>
</Stack>
</Card.Heading>
</Card>
))}
</Stack>
@@ -53,21 +55,23 @@ export function RepositoryTypeCards() {
<Stack direction="row" gap={1} wrap>
{otherProviders.map((config) => (
<Card key={config.type} href={`${CONNECT_URL}/${config.type}`} className={styles.card} noMargin>
<Stack gap={2} alignItems="center">
<RepoIcon type={config.type} />
{config.type === 'local' ? (
<Trans i18nKey="provisioning.repository-type-cards.configure-file">
Configure file provisioning
</Trans>
) : (
<Trans
i18nKey="provisioning.repository-type-cards.configure-with-provider"
values={{ provider: config.label }}
>
Configure with {'{{ provider }}'}
</Trans>
)}
</Stack>
<Card.Heading>
<Stack gap={2} alignItems="center">
<RepoIcon type={config.type} />
{config.type === 'local' ? (
<Trans i18nKey="provisioning.repository-type-cards.configure-file">
Configure file provisioning
</Trans>
) : (
<Trans
i18nKey="provisioning.repository-type-cards.configure-with-provider"
values={{ provider: config.label }}
>
Configure with {'{{ provider }}'}
</Trans>
)}
</Stack>
</Card.Heading>
</Card>
))}
</Stack>
@@ -7,9 +7,13 @@ import { PROVISIONING_URL } from '../constants';
interface StatusBadgeProps {
repo?: Repository;
displayOnly?: boolean; // if true, disable click action and cursor will be default
}
export function StatusBadge({ repo }: StatusBadgeProps) {
/**
* @description Displays a status badge for the given provisioned repository.
*/
export function StatusBadge({ repo, displayOnly = false }: StatusBadgeProps) {
if (!repo) {
return null;
}
@@ -86,10 +90,12 @@ export function StatusBadge({ repo }: StatusBadgeProps) {
color={color}
icon={icon}
text={text}
style={{ cursor: 'pointer' }}
style={{ cursor: displayOnly ? 'default' : 'pointer' }}
tooltip={tooltip}
onClick={() => {
locationService.push(`${PROVISIONING_URL}/${repo.metadata?.name}/?tab=overview`);
if (!displayOnly) {
locationService.push(`${PROVISIONING_URL}/${repo.metadata?.name}/?tab=overview`);
}
}}
/>
);
+5
View File
@@ -11810,6 +11810,11 @@
"next": "Next",
"previous": "Previous"
},
"shared": {
"progress-bar": {
"aria-label": "Progress Bar"
}
},
"sidebar-item": {
"label-completed-step": "Completed step",
"label-current-step": "Current step",