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:
ChloeGarciaMillerandandGildas Garcia authored and GitHub committed 2026-09-22 11:31:30 +02:00
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>
),
]}
/>
@@ -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">