mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 03:15:06 +03:00
## What kind of change does this PR introduce? bug fix for accessibility, fixes [docs-1265](https://linear.app/supabase/issue/DOCS-1365/add-aria-label-to-icon-only-buttons-button-name) ## What is the current behavior? some controles in the docs app have no accessible name, so screen readers announce them as an unlabelled "button" ## What is the new behavior? - adds each control a name the way its neighbours already do - adds menu toggle a state-dependent `aria-label` and `aria-expanded` - adds `button-name` to `enforced_rules` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Accessibility** - Added descriptive labels to configuration selectors and mobile menu controls. - Mobile menu controls now announce whether the menu is open or closed. - Expanded accessibility validation to check button names across documentation pages. - **UI Improvements** - Updated the raw throughput table control with a clearer button appearance and expandable chevron indicator. - Replaced a schema-migration tooltip with a direct in-page link. - **Documentation** - Removed the Info Tooltip component guidance from the contributing documentation. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
200 lines
7.1 KiB
TypeScript
200 lines
7.1 KiB
TypeScript
import throughputTable from '~/data/realtime/throughput.json'
|
|
import { ChevronDown } from 'lucide-react'
|
|
import { useState } from 'react'
|
|
import {
|
|
cn,
|
|
Collapsible,
|
|
CollapsibleContent,
|
|
CollapsibleTrigger,
|
|
Label,
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from 'ui'
|
|
|
|
import {
|
|
COMPUTE_LABELS,
|
|
COMPUTE_OPTIONS,
|
|
THROUGHPUT_METRIC_HEADINGS,
|
|
THROUGHPUT_TABLE_HEADINGS,
|
|
} from './RealtimeLimitsEstimator.constants'
|
|
|
|
export default function RealtimeLimitsEstimater({}) {
|
|
const findTableValue = ({ computeAddOn, rls, concurrency }) => {
|
|
return throughputTable.find(
|
|
(l) => l.computeAddOn === computeAddOn && l.rls === rls && l.concurrency === concurrency
|
|
)
|
|
}
|
|
|
|
const [computeAddOn, setComputeAddOn] = useState('micro')
|
|
const [rls, setRLS] = useState(false)
|
|
const [concurrency, setConcurrency] = useState(500)
|
|
|
|
const [limits, setLimits] = useState(findTableValue({ computeAddOn, rls, concurrency }))
|
|
|
|
const [expandPreview, setExpandPreview] = useState(false)
|
|
|
|
const handleComputeAddOnSelection = (val) => {
|
|
setComputeAddOn(val)
|
|
setConcurrency(500)
|
|
setLimits(findTableValue({ computeAddOn: val, rls, concurrency: 500 }))
|
|
}
|
|
|
|
const handleRLSSelection = (value) => {
|
|
const val = value.toLowerCase() === 'true'
|
|
setRLS(val)
|
|
setConcurrency(500)
|
|
setLimits(findTableValue({ computeAddOn, rls: val, concurrency: 500 }))
|
|
}
|
|
|
|
const handleConcurrencySelection = (value) => {
|
|
const val = parseInt(value)
|
|
setConcurrency(val)
|
|
setLimits(findTableValue({ computeAddOn, rls, concurrency: val }))
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<span className="block font-heading font-semibold text-lg mt-9 mb-[18px] text-foreground">
|
|
Set your expected parameters
|
|
</span>
|
|
<div className="grid mb-8 gap-y-8 gap-x-8 grid-cols-2 xl:grid-cols-4">
|
|
<div>
|
|
<Label htmlFor="computeAddOn">Compute:</Label>
|
|
<Select onValueChange={handleComputeAddOnSelection} value={computeAddOn}>
|
|
<SelectTrigger id="computeAddOn">
|
|
<SelectValue className="font-mono" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{COMPUTE_OPTIONS.map((option) => (
|
|
<SelectItem key={option.value} value={option.value}>
|
|
{option.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="rls">RLS:</Label>
|
|
<Select onValueChange={handleRLSSelection} value={rls.toString()}>
|
|
<SelectTrigger id="rls">
|
|
<SelectValue className="font-mono" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="false">No</SelectItem>
|
|
<SelectItem value="true">Yes</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div>
|
|
<Label htmlFor="concurrency">Connected clients:</Label>
|
|
<Select onValueChange={handleConcurrencySelection} value={concurrency.toString()}>
|
|
<SelectTrigger id="concurrency">
|
|
<SelectValue className="font-mono" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{throughputTable
|
|
.filter((l) => l.computeAddOn === computeAddOn && l.rls === rls)
|
|
.map((l) => (
|
|
<SelectItem key={l.concurrency} value={l.concurrency.toString()}>
|
|
{Intl.NumberFormat().format(l.concurrency)}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
|
|
{limits && (
|
|
<div className="mt-8">
|
|
<span className="block font-heading font-semibold text-lg mt-9 mb-[18px] text-foreground">
|
|
Current maximum possible throughput
|
|
</span>
|
|
|
|
<table className="table-auto">
|
|
<thead>
|
|
<tr>
|
|
{THROUGHPUT_METRIC_HEADINGS.map((heading) => (
|
|
<th key={heading} className="px-4 py-2">
|
|
{heading}
|
|
</th>
|
|
))}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td className="border px-4 py-2">{limits.maxDBChanges}</td>
|
|
<td className="border px-4 py-2">{limits.maxMessagesPerClient}</td>
|
|
<td className="border px-4 py-2">
|
|
{Intl.NumberFormat().format(limits.totalMessagesPerSecond)}
|
|
</td>
|
|
<td className="border px-4 py-2">{limits.p95Latency}ms</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
|
|
<Collapsible open={expandPreview} onOpenChange={setExpandPreview}>
|
|
<CollapsibleTrigger className="group text-base py-1 flex items-center gap-1 cursor-pointer select-none mb-10 text-foreground-light hover:text-foreground transition-colors">
|
|
View raw throughput table
|
|
<ChevronDown
|
|
size={14}
|
|
strokeWidth={2}
|
|
aria-hidden
|
|
className={cn(
|
|
'text-foreground-lighter group-hover:text-foreground transition-colors',
|
|
expandPreview && 'rotate-180'
|
|
)}
|
|
/>
|
|
</CollapsibleTrigger>
|
|
<CollapsibleContent>
|
|
<div>
|
|
{throughputTable
|
|
.map((l) => l.computeAddOn)
|
|
.filter((v, i, a) => a.indexOf(v) === i)
|
|
.map((computeAddOn) => (
|
|
<div>
|
|
<span className="block font-heading font-semibold text-lg mt-9 mb-[18px] text-foreground">
|
|
{COMPUTE_LABELS[computeAddOn]}
|
|
</span>
|
|
<table className="table-auto">
|
|
<thead>
|
|
<tr>
|
|
{THROUGHPUT_TABLE_HEADINGS.map((heading) => (
|
|
<th key={heading} className="px-4 py-2">
|
|
{heading}
|
|
</th>
|
|
))}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{throughputTable
|
|
.filter((l) => l.computeAddOn === computeAddOn)
|
|
.map((l) => (
|
|
<tr>
|
|
<td className="border px-4 py-2">{l.rls ? '✅' : '🚫'}</td>
|
|
<td className="border px-4 py-2">
|
|
{Intl.NumberFormat().format(l.concurrency)}
|
|
</td>
|
|
<td className="border px-4 py-2">{l.maxDBChanges}</td>
|
|
<td className="border px-4 py-2">{l.maxMessagesPerClient}</td>
|
|
<td className="border px-4 py-2">
|
|
{Intl.NumberFormat().format(l.totalMessagesPerSecond)}
|
|
</td>
|
|
<td className="border px-4 py-2">{l.p95Latency}ms</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CollapsibleContent>
|
|
</Collapsible>
|
|
</div>
|
|
)
|
|
}
|