| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- // @ts-nocheck
- import { zodResolver } from '@hookform/resolvers/zod'
- import { IS_PLATFORM, useParams } from 'common'
- import { ChevronDown } from 'lucide-react'
- import { Dispatch, SetStateAction, useState } from 'react'
- import { useForm } from 'react-hook-form'
- import {
- Button,
- Form,
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- Input,
- Popover,
- PopoverContent,
- PopoverTrigger,
- Switch,
- } from 'ui'
- import * as z from 'zod'
- import { RealtimeConfig } from './useRealtimeMessages'
- import { DocsButton } from '@/components/ui/DocsButton'
- import { ShortcutTooltip } from '@/components/ui/ShortcutTooltip'
- import { getTemporaryAPIKey } from '@/data/api-keys/temp-api-keys-query'
- import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
- import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
- import { DOCS_URL } from '@/lib/constants'
- import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
- type ControlledOpenProps =
- | { open: boolean; onOpenChange: (open: boolean) => void }
- | { open?: undefined; onOpenChange?: undefined }
- type ChooseChannelPopoverProps = {
- config: RealtimeConfig
- onChangeConfig: Dispatch<SetStateAction<RealtimeConfig>>
- } & ControlledOpenProps
- const FormSchema = z.object({ channel: z.string(), isPrivate: z.boolean() })
- export const ChooseChannelPopover = ({
- config,
- onChangeConfig,
- open: controlledOpen,
- onOpenChange,
- }: ChooseChannelPopoverProps) => {
- const [internalOpen, setInternalOpen] = useState(false)
- const isControlled = controlledOpen !== undefined
- const open = isControlled ? controlledOpen : internalOpen
- const setOpen = (v: boolean) => {
- if (isControlled) {
- onOpenChange?.(v)
- } else {
- setInternalOpen(v)
- }
- }
- const { ref } = useParams()
- const { data: org } = useSelectedOrganizationQuery()
- const { mutate: sendEvent } = useSendEventMutation()
- const form = useForm<z.infer<typeof FormSchema>>({
- mode: 'onBlur',
- reValidateMode: 'onBlur',
- resolver: zodResolver(FormSchema as any),
- defaultValues: { channel: '', isPrivate: false },
- })
- const onOpen = (v: boolean) => {
- // when opening, copy the outside config into the intermediate one
- if (v === true) {
- form.setValue('channel', config.channelName)
- }
- setOpen(v)
- }
- const onSubmit = async () => {
- setOpen(false)
- sendEvent({
- action: 'realtime_inspector_listen_channel_clicked',
- groups: {
- project: ref ?? 'Unknown',
- organization: org?.slug ?? 'Unknown',
- },
- })
- let token = config.token
- // [Joshen] Refresh if starting to listen + using temp API key, since it has a low refresh rate
- if (token.startsWith('sb_temp') || !IS_PLATFORM) {
- const data = await getTemporaryAPIKey({ projectRef: config.projectRef, expiry: 3600 })
- token = data.api_key
- }
- onChangeConfig({
- ...config,
- token,
- channelName: form.getValues('channel'),
- isChannelPrivate: form.getValues('isPrivate'),
- enabled: true,
- })
- }
- const channelPopoverTrigger = (
- <PopoverTrigger asChild>
- <Button className="rounded-r-none" type="default" size="tiny" iconRight={<ChevronDown />}>
- <p
- className="max-w-[120px] truncate"
- title={config.channelName.length > 0 ? config.channelName : ''}
- >
- {config.channelName.length > 0 ? `Channel: ${config.channelName}` : 'Join a channel'}
- </p>
- </Button>
- </PopoverTrigger>
- )
- return (
- <Popover open={open} onOpenChange={onOpen}>
- {!open && config.channelName.length === 0 ? (
- <ShortcutTooltip shortcutId={SHORTCUT_IDS.INSPECTOR_JOIN_CHANNEL} side="bottom">
- {channelPopoverTrigger}
- </ShortcutTooltip>
- ) : (
- channelPopoverTrigger
- )}
- <PopoverContent className="p-0 w-[320px]" align="start">
- <div className="p-4 flex flex-col text-sm">
- {config.channelName.length === 0 ? (
- <>
- <Form {...form}>
- <form
- id="realtime-channel"
- onSubmit={form.handleSubmit(() => onSubmit())}
- className="flex flex-col gap-y-4"
- >
- <FormField
- name="channel"
- control={form.control}
- render={({ field }) => (
- <FormItem className="flex flex-col gap-y-2">
- <div className="flex flex-col gap-y-1">
- <label className="text-foreground text-xs">Name of channel</label>
- <div className="flex flex-row">
- <FormControl>
- <Input
- {...field}
- autoComplete="off"
- className="rounded-r-none text-xs px-2.5 py-1 h-auto"
- placeholder="Enter a channel name"
- />
- </FormControl>
- <Button
- type="primary"
- className="rounded-l-none"
- disabled={form.getValues().channel.length === 0}
- onClick={() => onSubmit()}
- >
- Listen to channel
- </Button>
- </div>
- </div>
- <FormDescription className="text-xs text-foreground-lighter">
- The channel you initialize with the Briven Realtime client. Learn more
- in{' '}
- <a
- target="_blank"
- rel="noreferrer"
- className="underline hover:text-foreground transition"
- href={`${DOCS_URL}/guides/realtime/concepts#channels`}
- >
- our docs
- </a>
- </FormDescription>
- </FormItem>
- )}
- />
- <FormField
- key="isPrivate"
- control={form.control}
- name="isPrivate"
- render={({ field }) => (
- <FormItem className="">
- <div className="flex flex-row items-center gap-x-2">
- <FormControl>
- <Switch
- checked={field.value}
- onCheckedChange={field.onChange}
- disabled={field.disabled}
- />
- </FormControl>
- <FormLabel className="text-xs">Is channel private?</FormLabel>
- </div>
- <FormDescription className="text-xs text-foreground-lighter mt-2">
- If the channel is marked as private, it will use RLS policies to filter
- messages.
- </FormDescription>
- </FormItem>
- )}
- />
- <DocsButton
- abbrev={false}
- className="w-min"
- href={`${DOCS_URL}/guides/realtime/authorization`}
- />
- </form>
- </Form>
- </>
- ) : (
- <div className="space-y-2">
- <div className="flex items-center gap-x-2">
- <p className="text-foreground text-xs">
- Currently joined{' '}
- <span className={config.isChannelPrivate ? 'text-brand' : 'text-warning'}>
- {config.isChannelPrivate ? 'private' : 'public'}
- </span>{' '}
- channel:
- </p>
- <p className="text-xs border border-scale-600 py-0.5 px-1 rounded-md bg-surface-200">
- {config.channelName}
- </p>
- </div>
- <p className="text-xs text-foreground-lighter mt-2">
- If you leave this channel, all of the messages populated on this page will disappear
- </p>
- <Button
- type="default"
- onClick={() => onChangeConfig({ ...config, channelName: '', enabled: false })}
- >
- Leave channel
- </Button>
- </div>
- )}
- </div>
- </PopoverContent>
- </Popover>
- )
- }
|