Files
supabase/apps/docs/components/RealtimeLimitsEstimator/RealtimeLimitsEstimator.tsx
Filipe Cabaçoandgithub-actions[bot] 0a9a0eec92 chore: update pg changes documentation (#47593)
## 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?

update pg changes documentation

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Updated the Realtime Postgres Changes guide with a new, generalized
“Listening to specific events” section (including INSERT/UPDATE/DELETE/*
examples) and standardized `event` usage.
* Refreshed “Available filters” with a unified filter builder approach,
expanded operator reference, consistent Filter-string/tab patterns,
`not.` and `AND` guidance, and clearer limitations (including
delete-event filtering).
* Updated “Selecting specific columns” examples to match the latest
payload/subscription guidance.
* **Refactor**
* Simplified the Realtime limits estimator by removing filter-based
throughput inputs and related UI/table columns; throughput is now based
on compute add-on, RLS, and concurrency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-06 10:34:28 +01:00

199 lines
6.8 KiB
TypeScript

import throughputTable from '~/data/realtime/throughput.json'
import { ChevronDown } from 'lucide-react'
import { useState } from 'react'
import {
Button,
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>
<h4>Set your expected parameters</h4>
<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">
<h4>Current maximum possible throughput</h4>
<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 asChild>
<div className="py-1 flex items-center">
<p className="text-sm">View raw throughput table</p>
<Button
variant="text"
icon={
<ChevronDown
size={18}
strokeWidth={2}
className={expandPreview ? 'rotate-180' : undefined}
/>
}
className="px-1"
onClick={() => setExpandPreview(!expandPreview)}
/>
</div>
</CollapsibleTrigger>
<CollapsibleContent>
<div>
{throughputTable
.map((l) => l.computeAddOn)
.filter((v, i, a) => a.indexOf(v) === i)
.map((computeAddOn) => (
<div>
<h4>{COMPUTE_LABELS[computeAddOn]}</h4>
<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>
)
}