Home / Function/ RealtimeFilterPopover() — supabase Function Reference

RealtimeFilterPopover() — supabase Function Reference

Architecture documentation for the RealtimeFilterPopover() function in index.tsx from the supabase codebase.

Entity Profile

Relationship Graph

Source Code

apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx lines 35–259

export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilterPopoverProps) => {
  const [open, setOpen] = useState(false)
  const [applyConfigOpen, setApplyConfigOpen] = useState(false)
  const [tempConfig, setTempConfig] = useState(config)

  const { ref } = useParams()
  const { data: project } = useSelectedProjectQuery()
  const { data: org } = useSelectedOrganizationQuery()
  const { mutate: sendEvent } = useSendEventMutation()

  const { data: publications } = useDatabasePublicationsQuery({
    projectRef: project?.ref,
    connectionString: project?.connectionString,
  })
  const realtimePublication = (publications ?? []).find(
    (publication) => publication.name === 'supabase_realtime'
  )

  // 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) {
      setTempConfig(config)
    }
    setOpen(v)
  }

  // [Joshen] Restricting the schemas to only public as any other schema won’t work out of the box due to missing permissions
  // Consequently, SchemaSelector here will also be disabled
  const isFiltered = config.table !== '*'

  return (
    <>
      <Popover_Shadcn_ open={open} onOpenChange={onOpen}>
        <PopoverTrigger_Shadcn_ asChild>
          <Button
            icon={<PlusCircle size="16" />}
            type={isFiltered ? 'primary' : 'dashed'}
            className={cn('rounded-full px-1 text-xs h-[26px]')}
            size="small"
          >
            {isFiltered ? (
              <>
                <span className="mr-1">Filtered by </span>
                <Badge variant="success">table: {config.table}</Badge>
              </>
            ) : (
              <span className="mr-1">Filter messages</span>
            )}
          </Button>
        </PopoverTrigger_Shadcn_>
        <PopoverContent_Shadcn_ className="p-0 w-[365px]" align="start">
          <div className="border-b border-overlay text-xs px-4 py-3 text-foreground">
            Listen to event types
          </div>
          <div className="py-3 px-4 border-b border-overlay">
            <div className="flex items-center justify-between gap-2">
              <div className="flex gap-2.5 items-center">
                <IconPresence
                  size="xlarge"
                  className="bg-foreground rounded text-background-muted"
                />
                <label htmlFor="toggle-presence" className="text-sm">
                  Presence
                </label>
              </div>
              <Toggle
                id="toggle-presence"
                size="tiny"
                checked={tempConfig.enablePresence}
                onChange={() =>
                  setTempConfig({ ...tempConfig, enablePresence: !tempConfig.enablePresence })
                }
              />
            </div>
            <p className="text-xs text-foreground-light pt-1">
              Store and synchronize user state consistently across clients
            </p>
          </div>
          <div className="py-3 px-4 border-b border-overlay">
            <div className="flex items-center justify-between">
              <div className="flex gap-2.5 items-center">
                <IconBroadcast
                  size="xlarge"
                  className="bg-foreground rounded text-background-muted"
                />
                <label htmlFor="toggle-broadcast" className="text-sm">
                  Broadcast
                </label>
              </div>
              <Toggle
                id="toggle-broadcast"
                size="tiny"
                checked={tempConfig.enableBroadcast}
                onChange={() =>
                  setTempConfig({ ...tempConfig, enableBroadcast: !tempConfig.enableBroadcast })
                }
              />
            </div>
            <p className="text-xs  text-foreground-light pt-1">
              Send any data to any client subscribed to the same channel
            </p>
          </div>
          <div className="py-3 px-4 border-b border-overlay">
            <div className="flex items-center justify-between">
              <div className="flex gap-2.5 items-center">
                <IconDatabaseChanges
                  size="xlarge"
                  className={cn(
                    'rounded text-background-muted',
                    config.enableDbChanges ? 'bg-foreground' : 'bg-foreground-lighter'
                  )}
                />
                <label
                  htmlFor="toggle-db-changes"
                  className={cn('text-sm', !config.enableDbChanges && 'text-foreground-lighter')}
                >
                  Database changes
                </label>
              </div>
              <Toggle
                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
            </p>
            {!config.enableDbChanges && (
              <p className="text-xs text-foreground-light mt-2">
                Enable{' '}
                <InlineLink
                  href={`/project/${ref}/database/publications${!!realtimePublication ? `/${realtimePublication.id}` : ''}`}
                >
                  realtime publications
                </InlineLink>{' '}
                for your tables to listen for database changes
              </p>
            )}
          </div>

          {tempConfig.enableDbChanges && config.enableDbChanges && (
            <>
              <div className="border-b border-overlay text-xs px-4 py-3 text-foreground">
                Filter messages from database changes
              </div>
              <div className="flex border-b border-overlay p-4 gap-y-2 flex-col">
                <FilterSchema
                  value={tempConfig.schema}
                  onChange={(v) => setTempConfig({ ...tempConfig, schema: v, table: '*' })}
                />

                <FilterTable
                  value={tempConfig.table}
                  schema={tempConfig.schema}
                  onChange={(table) => setTempConfig({ ...tempConfig, table })}
                />
              </div>
              <div className="border-b border-overlay p-4 flex flex-col gap-2">
                <div className="flex flex-row gap-4 items-center">
                  <p className="w-[60px] flex justify-end text-sm">AND</p>
                  <Input
                    size="tiny"
                    className="flex-grow"
                    placeholder="body=eq.hey"
                    value={tempConfig.filter}
                    onChange={(v) => setTempConfig({ ...tempConfig, filter: v.target.value })}
                  />
                </div>
                <p className="text-xs text-foreground-light pl-[80px]">
                  Learn more about realtime filtering in{' '}
                  <Link
                    className="underline"
                    target="_blank"
                    rel="noreferrer"
                    href={`${DOCS_URL}/guides/realtime/postgres-changes#available-filters`}
                  >
                    our docs
                  </Link>
                </p>
              </div>
            </>
          )}
          <div className="px-4 py-2 gap-2 flex justify-end">
            <Button type="default" onClick={() => setOpen(false)}>
              Cancel
            </Button>
            <Button onClick={() => setApplyConfigOpen(true)}>Apply</Button>
          </div>
        </PopoverContent_Shadcn_>
      </Popover_Shadcn_>
      <ConfirmationModal
        title="Previously found messages will be lost"
        variant="destructive"
        confirmLabel="Confirm"
        size="small"
        visible={applyConfigOpen}
        onCancel={() => setApplyConfigOpen(false)}
        onConfirm={() => {
          sendEvent({
            action: 'realtime_inspector_filters_applied',
            groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
          })
          onChangeConfig(tempConfig)
          setApplyConfigOpen(false)
          setOpen(false)
        }}
      >
        <p className="text-sm text-foreground-light">
          The realtime inspector will clear currently collected messages and start listening for new
          messages matching the updated filters.
        </p>
      </ConfirmationModal>
    </>
  )
}

Subdomains

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free