mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix: ESLint errors relating to accessibility in integration section (#50224)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Improving accessibility by adding aria-label. Adding Tooltip for icon only buttons. ## What is the current behavior? Some `aria-label` and `Tooltip` are missing. ## What is the new behavior? Icon-only buttons have now Tooltip and aria-label have been added. ## Additional context No visual changes have been made. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Accessibility Improvements** * Added descriptive tooltips and screen-reader labels to search-clear and close-panel controls. * Added accessible labels and tooltips for managing secrets, showing or hiding secret values, and editing or removing foreign tables. * Improved the lint details panel close control with a descriptive label. * Prevented duplicate tooltip announcements for assistive technologies. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
This commit is contained in:
1 parent
14bda8a5cf
commit
ef7b2a5211
8 files changed
+194
-79
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import { RefreshCw, Search, X } from 'lucide-react'
|
||||
import type { KeyboardEvent, Ref } from 'react'
|
||||
import { Button } from 'ui'
|
||||
import { Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
import { Input } from 'ui-patterns/DataInputs/Input'
|
||||
|
||||
import { EnableCleanupButton } from './CronJobsTab.EnableCleanupButton'
|
||||
@@ -47,14 +47,22 @@ export const CronJobsTabHeader = ({
|
||||
onKeyDown={handleKeyDown}
|
||||
actions={[
|
||||
search && (
|
||||
<Button
|
||||
key="clear-search"
|
||||
size="tiny"
|
||||
variant="text"
|
||||
icon={<X />}
|
||||
onClick={onClearSearch}
|
||||
className="p-0 h-5 w-5"
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
key="clear-search"
|
||||
size="tiny"
|
||||
variant="text"
|
||||
icon={<X />}
|
||||
onClick={onClearSearch}
|
||||
className="p-0 h-5 w-5"
|
||||
aria-label="Clear search"
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Clear search</TooltipContent>
|
||||
</Tooltip>
|
||||
),
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useRouter } from 'next/router'
|
||||
import { parseAsBoolean, parseAsString, useQueryState } from 'nuqs'
|
||||
import { useMemo, useRef, useState } from 'react'
|
||||
import DataGrid, { Row } from 'react-data-grid'
|
||||
import { Button, cn, LoadingLine } from 'ui'
|
||||
import { Button, cn, LoadingLine, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
import { Input } from 'ui-patterns/DataInputs/Input'
|
||||
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
|
||||
|
||||
@@ -96,14 +96,22 @@ export const QueuesTab = () => {
|
||||
}}
|
||||
actions={[
|
||||
search && (
|
||||
<Button
|
||||
key="clear"
|
||||
size="tiny"
|
||||
variant="text"
|
||||
icon={<X />}
|
||||
onClick={clearSearch}
|
||||
className="p-0 h-5 w-5"
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
key="clear"
|
||||
size="tiny"
|
||||
variant="text"
|
||||
icon={<X />}
|
||||
onClick={clearSearch}
|
||||
className="p-0 h-5 w-5"
|
||||
aria-label="Clear search"
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Clear search</TooltipContent>
|
||||
</Tooltip>
|
||||
),
|
||||
]}
|
||||
/>
|
||||
|
||||
+26
-7
@@ -4,7 +4,18 @@ import dayjs from 'dayjs'
|
||||
import { isNil } from 'lodash'
|
||||
import { Archive, Clock12, Trash2, X } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { Button, ResizablePanel, Separator, Tabs, TabsContent, TabsList, TabsTrigger } from 'ui'
|
||||
import {
|
||||
Button,
|
||||
ResizablePanel,
|
||||
Separator,
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from 'ui'
|
||||
|
||||
import { RowAction, RowData } from '@/components/interfaces/Auth/Users/UserOverview'
|
||||
import { CodeEditor } from '@/components/ui/CodeEditor/CodeEditor'
|
||||
@@ -80,12 +91,20 @@ export const MessageDetailsPanel = ({
|
||||
}}
|
||||
className="bg-studio border-t pointer-events-auto"
|
||||
>
|
||||
<Button
|
||||
variant="text"
|
||||
className="absolute top-3 right-3 px-1"
|
||||
icon={<X />}
|
||||
onClick={() => setSelectedMessage(null)}
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="text"
|
||||
className="absolute top-3 right-3 px-1"
|
||||
icon={<X />}
|
||||
onClick={() => setSelectedMessage(null)}
|
||||
aria-label="Close panel"
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Close panel</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tabs
|
||||
value={view}
|
||||
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from 'ui'
|
||||
import { Input } from 'ui-patterns/DataInputs/Input'
|
||||
|
||||
@@ -54,9 +57,22 @@ export const SecretRow = ({ row, col }: SecretRowProps) => {
|
||||
return (
|
||||
<div className="flex items-center justify-end w-full" onClick={(e) => e.stopPropagation()}>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button title="Manage Secret" variant="text" className="px-1" icon={<MoreVertical />} />
|
||||
</DropdownMenuTrigger>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
title="Manage Secret"
|
||||
variant="text"
|
||||
className="px-1"
|
||||
icon={<MoreVertical />}
|
||||
aria-label="Manage secret"
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</DropdownMenuTrigger>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Manage secret</TooltipContent>
|
||||
</Tooltip>
|
||||
<DropdownMenuContent side="bottom" align="end" className="w-40">
|
||||
<DropdownMenuItemTooltip
|
||||
className="gap-x-2"
|
||||
@@ -95,20 +111,30 @@ export const SecretRow = ({ row, col }: SecretRowProps) => {
|
||||
if (col.id === 'secret_value') {
|
||||
return (
|
||||
<div className="flex items-center gap-2 w-full" onClick={(e) => e.stopPropagation()}>
|
||||
<Button
|
||||
variant="text"
|
||||
className="px-1.5"
|
||||
icon={
|
||||
isFetching && revealedValue === undefined ? (
|
||||
<Loader className="animate-spin" size={16} strokeWidth={1.5} />
|
||||
) : !revealSecret ? (
|
||||
<Eye size={16} strokeWidth={1.5} />
|
||||
) : (
|
||||
<EyeOff size={16} strokeWidth={1.5} />
|
||||
)
|
||||
}
|
||||
onClick={() => setRevealSecret(!revealSecret)}
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="text"
|
||||
className="px-1.5"
|
||||
icon={
|
||||
isFetching && revealedValue === undefined ? (
|
||||
<Loader className="animate-spin" size={16} strokeWidth={1.5} />
|
||||
) : !revealSecret ? (
|
||||
<Eye size={16} strokeWidth={1.5} />
|
||||
) : (
|
||||
<EyeOff size={16} strokeWidth={1.5} />
|
||||
)
|
||||
}
|
||||
onClick={() => setRevealSecret(!revealSecret)}
|
||||
aria-label={revealSecret ? 'Hide secret value' : 'Show secret value'}
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
{revealSecret ? 'Hide secret value' : 'Show secret value'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="grow min-w-0">
|
||||
{revealSecret && revealedValue !== undefined ? (
|
||||
<Input copy readOnly size="tiny" className="font-mono" value={revealedValue} />
|
||||
|
||||
@@ -14,6 +14,9 @@ import {
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from 'ui'
|
||||
import { Input } from 'ui-patterns/DataInputs/Input'
|
||||
|
||||
@@ -114,14 +117,22 @@ export const SecretsManagement = () => {
|
||||
onKeyDown={onSearchInputEscape(searchValue ?? '', setSearchValue)}
|
||||
actions={[
|
||||
searchValue && (
|
||||
<Button
|
||||
key="clear"
|
||||
size="tiny"
|
||||
variant="text"
|
||||
icon={<X />}
|
||||
onClick={() => setSearchValue('')}
|
||||
className="p-0 h-5 w-5"
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
key="clear"
|
||||
size="tiny"
|
||||
variant="text"
|
||||
icon={<X />}
|
||||
onClick={() => setSearchValue('')}
|
||||
className="p-0 h-5 w-5"
|
||||
aria-label="Clear search"
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Clear search</TooltipContent>
|
||||
</Tooltip>
|
||||
),
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -16,6 +16,9 @@ import {
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
WarningIcon,
|
||||
} from 'ui'
|
||||
import { Admonition } from 'ui-patterns/Admonition'
|
||||
@@ -426,20 +429,36 @@ export const CreateWrapperSheet = ({
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Edit />}
|
||||
onClick={() => {
|
||||
setSelectedTableToEdit(table)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Trash />}
|
||||
onClick={() => {
|
||||
removeTable(tableIndex)
|
||||
}}
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Edit />}
|
||||
onClick={() => {
|
||||
setSelectedTableToEdit(table)
|
||||
}}
|
||||
aria-label={`Edit ${table.table_name} foreign table`}
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">{`Edit ${table.table_name} foreign table`}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Trash />}
|
||||
onClick={() => {
|
||||
removeTable(tableIndex)
|
||||
}}
|
||||
aria-label={`Remove ${table.table_name} foreign table`}
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">{`Remove ${table.table_name} foreign table`}</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -15,6 +15,9 @@ import {
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
@@ -280,20 +283,36 @@ export const EditWrapperSheet = ({
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Edit />}
|
||||
onClick={() => {
|
||||
setSelectedTableToEdit(table)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Trash />}
|
||||
onClick={() => {
|
||||
removeTable(tableIndex)
|
||||
}}
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Edit />}
|
||||
onClick={() => {
|
||||
setSelectedTableToEdit(table)
|
||||
}}
|
||||
aria-label={`Edit ${table.table_name} foreign table`}
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">{`Edit ${table.table_name} foreign table`}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
className="px-1"
|
||||
icon={<Trash />}
|
||||
onClick={() => {
|
||||
removeTable(tableIndex)
|
||||
}}
|
||||
aria-label={`Remove ${table.table_name} foreign table`}
|
||||
// Tooltip repeats the label; screen readers would read it twice
|
||||
aria-describedby={undefined}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">{`Remove ${table.table_name} foreign table`}</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -196,7 +196,12 @@ export const LinterDataGrid = ({
|
||||
<LintCategoryBadge category={selectedLint.categories[0]} />
|
||||
</div>
|
||||
<ShortcutTooltip shortcutId={SHORTCUT_IDS.ADVISORS_CLOSE_DETAIL} side="left">
|
||||
<Button variant="text" icon={<X />} onClick={handleSidepanelClose} />
|
||||
<Button
|
||||
variant="text"
|
||||
icon={<X />}
|
||||
onClick={handleSidepanelClose}
|
||||
aria-label="Close lint details panel"
|
||||
/>
|
||||
</ShortcutTooltip>
|
||||
</div>
|
||||
<div className="p-6 flex-grow min-h-0 overflow-y-auto">
|
||||
|
||||
Reference in new issue
Block a user