Files
supabase/apps/studio/components/interfaces/TableGridEditor/RealtimeToggleDialog.tsx
Joshen Lim f7ea722b35 Consolidate grid header actions in table editor into a single row (#45504)
## Consolidate Table Editor grid header actions into a single row


https://github.com/user-attachments/assets/1020c385-8fa9-4ef1-b5e7-03983111508b

## Changes involved
- Index advisor, Realtime, and API docs are now behind a dropdown menu
button (Treated as secondary actions)
- Grid header actions shifted into the same row as filter bar (more
space for data grid)
- Header actions will hide while filter bar is in focus (remove
distractions, more space for filter bar)

## Changes to filter bar
- Filter bar will refocus when deleting a filter
- Clicking on the search icon will focus on the free form input of the
filter bar

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

* **New Features**
* Added a “More” dropdown in grid actions to access Realtime, API docs,
and Index Advisor.
* New dialogs for enabling Index Advisor and toggling Realtime are now
consistently managed.

* **Improvements**
* Improved filter focus handling with auto-refocus when conditions
change and responsive header behavior.
* Adjusted popover alignment, separator visuals,
header/footer/pagination layout and sizing.
* Filter bar now supports programmatic focus; Connect button supports
icon-only mode.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
2026-05-06 10:53:49 +08:00

122 lines
4.0 KiB
TypeScript

import { useParams } from 'common'
import { toast } from 'sonner'
import {
Button,
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
} from 'ui'
import { InlineLink } from '@/components/ui/InlineLink'
import { useDatabasePublicationsQuery } from '@/data/database-publications/database-publications-query'
import { useDatabasePublicationUpdateMutation } from '@/data/database-publications/database-publications-update-mutation'
import { Entity } from '@/data/table-editor/table-editor-types'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { useTrack } from '@/lib/telemetry/track'
export const RealtimeToggleDialog = ({
table,
open,
setOpen,
}: {
table: Entity
open: boolean
setOpen: (value: boolean) => void
}) => {
const track = useTrack()
const { ref } = useParams()
const { data: project } = useSelectedProjectQuery()
const { data: publications } = useDatabasePublicationsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const realtimePublication = (publications ?? []).find(
(publication) => publication.name === 'supabase_realtime'
)
const realtimeEnabledTables = realtimePublication?.tables ?? []
const isRealtimeEnabled = realtimeEnabledTables.some((t) => t.id === table?.id)
const { mutate: updatePublications, isPending: isTogglingRealtime } =
useDatabasePublicationUpdateMutation({
onSuccess: () => {
setOpen(false)
track(isRealtimeEnabled ? 'table_realtime_disabled' : 'table_realtime_enabled', {
method: 'ui',
schema_name: table.schema,
table_name: table.name,
})
},
onError: (error) => {
toast.error(`Failed to toggle realtime for ${table.name}: ${error.message}`)
},
})
const toggleRealtime = async () => {
if (!project || !realtimePublication) return
const exists = realtimeEnabledTables.some((x) => x.id === table.id)
const tables = !exists
? [`${table.schema}.${table.name}`].concat(
realtimeEnabledTables.map((t) => `${t.schema}.${t.name}`)
)
: realtimeEnabledTables.filter((x) => x.id !== table.id).map((x) => `${x.schema}.${x.name}`)
track('realtime_toggle_table_clicked', {
newState: exists ? 'disabled' : 'enabled',
origin: 'tableGridHeader',
})
updatePublications({
projectRef: project?.ref,
connectionString: project?.connectionString,
id: realtimePublication.id,
tables,
})
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent size="small" aria-describedby={undefined}>
<DialogHeader>
<DialogTitle>
{isRealtimeEnabled ? 'Disable' : 'Enable'} realtime for {table.name}
</DialogTitle>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection>
<div className="space-y-2">
<p className="text-sm">
Once realtime has been {isRealtimeEnabled ? 'disabled' : 'enabled'}, the table will{' '}
{isRealtimeEnabled ? 'no longer ' : ''}broadcast any changes to authorized
subscribers.
</p>
{!isRealtimeEnabled && (
<p className="text-sm">
You may also select which events to broadcast to subscribers on the{' '}
<InlineLink href={`/project/${ref}/database/publications`}>
database publications
</InlineLink>{' '}
settings.
</p>
)}
</div>
</DialogSection>
<DialogFooter>
<Button type="default" disabled={isTogglingRealtime} onClick={() => setOpen(false)}>
Cancel
</Button>
<Button type="primary" loading={isTogglingRealtime} onClick={toggleRealtime}>
{isRealtimeEnabled ? 'Disable' : 'Enable'} realtime
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}