fix: improve realtime inspector (#39626)

* Add better error descriptions when the channel fails to join
* If there are no publications, database changes will be disabled and untoggled to prevent errors
This commit is contained in:
Filipe Cabaço authored and GitHub committed 2025-10-21 14:56:49 +01:00
1 parent 5f599a9f4f
commit 541b6fc4f5
3 files changed
+46 -12

No files matched your search

@@ -1,6 +1,6 @@
import { PlusCircle } from 'lucide-react'
import Link from 'next/link'
import { Dispatch, SetStateAction, useState } from 'react'
import { Dispatch, SetStateAction, useState, useEffect } from 'react'
import { useParams } from 'common'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
@@ -38,6 +38,11 @@ export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilter
const { data: org } = useSelectedOrganizationQuery()
const { mutate: sendEvent } = useSendEventMutation()
// Update tempConfig when config changes to ensure consistency
useEffect(() => {
setTempConfig(config)
}, [config])
const onOpen = (v: boolean) => {
// when opening, copy the outside config into the intermediate one
if (v === true) {
@@ -127,9 +132,15 @@ export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilter
<div className="flex gap-2.5 items-center">
<IconDatabaseChanges
size="xlarge"
className="bg-foreground rounded text-background-muted"
className={cn(
'rounded text-background-muted',
config.enableDbChanges ? 'bg-foreground' : 'bg-foreground-lighter'
)}
/>
<label htmlFor="toggle-db-changes" className="text-sm">
<label
htmlFor="toggle-db-changes"
className={cn('text-sm', !config.enableDbChanges && 'text-foreground-lighter')}
>
Database changes
</label>
</div>
@@ -137,17 +148,20 @@ export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilter
id="toggle-db-changes"
size="tiny"
checked={tempConfig.enableDbChanges}
disabled={!config.enableDbChanges}
onChange={() =>
setTempConfig({ ...tempConfig, enableDbChanges: !tempConfig.enableDbChanges })
}
/>
</div>
<p className="text-xs text-foreground-light pt-1">
Listen for Database inserts, updates, deletes and more
{config.enableDbChanges
? 'Listen for Database inserts, updates, deletes and more'
: 'Enable realtime publications to listen for database changes'}
</p>
</div>
{tempConfig.enableDbChanges && (
{tempConfig.enableDbChanges && config.enableDbChanges && (
<>
<div className="border-b border-overlay text-xs px-4 py-3 text-foreground">
Filter messages from database changes
@@ -1,10 +1,10 @@
import { useParams } from 'common'
import { useState, useEffect } from 'react'
import { motion } from 'framer-motion'
import { MousePointer2 } from 'lucide-react'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import { useDatabasePublicationsQuery } from 'data/database-publications/database-publications-query'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { Header } from './Header'
import MessagesTable from './MessagesTable'
import { SendMessageModal } from './SendMessageModal'
@@ -17,6 +17,19 @@ import { EmptyRealtime } from './EmptyRealtime'
export const RealtimeInspector = () => {
const { ref } = useParams()
const { data: org } = useSelectedOrganizationQuery()
const { data: project } = useSelectedProjectQuery()
// Check if realtime publications are available
const { data: publications } = useDatabasePublicationsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const realtimePublication = (publications ?? []).find(
(publication) => publication.name === 'supabase_realtime'
)
const isRealtimeAvailable =
!!realtimePublication &&
((realtimePublication?.tables ?? []).length > 0 || realtimePublication?.tables === null)
const [sendMessageShown, setSendMessageShown] = useState(false)
const [realtimeConfig, setRealtimeConfig] = useState<RealtimeConfig>({
@@ -31,13 +44,18 @@ export const RealtimeInspector = () => {
filter: undefined,
bearer: null,
enablePresence: true,
enableDbChanges: true,
enableDbChanges: isRealtimeAvailable, // Initialize based on publications availability
enableBroadcast: true,
})
const { mutate: sendEvent } = useSendEventMutation()
const { logData, sendMessage } = useRealtimeMessages(realtimeConfig, setRealtimeConfig)
// Update enableDbChanges when publications change
useEffect(() => {
setRealtimeConfig((prev) => ({ ...prev, enableDbChanges: isRealtimeAvailable }))
}, [isRealtimeAvailable])
return (
<div className="flex flex-col grow h-full">
<Header config={realtimeConfig} onChangeConfig={setRealtimeConfig} />
@@ -168,7 +168,7 @@ export const useRealtimeMessages = (
}
// Finally, subscribe to the Channel we just setup
newChannel.subscribe(async (status) => {
newChannel.subscribe(async (status, err) => {
if (status === 'SUBSCRIBED') {
// Let LiveView know we connected so we can update the button text
// pushMessageTo('#conn_info', 'broadcast_subscribed', { host: host })
@@ -192,9 +192,11 @@ export const useRealtimeMessages = (
})
}
} else if (status === 'CHANNEL_ERROR') {
toast.error(
`Failed to connect to the channel ${channelName}: This may be due to restrictive RLS policies. Check your role and try again.`
)
if (err?.message) {
toast.error(`Failed to connect with the following error: ${err.message}`)
} else {
toast.error(`Failed to connect. Please check your RLS policies and try again.`)
}
newChannel.unsubscribe()
setChannel(undefined)