Header.tsx133 lines · main
1// @ts-nocheck
2import { PermissionAction } from '@supabase/shared-types/out/constants'
3import { IS_PLATFORM, useParams } from 'common'
4import { PlayCircle, StopCircle } from 'lucide-react'
5import { Dispatch, SetStateAction, useCallback } from 'react'
6import { Button } from 'ui'
7
8import { ChooseChannelPopover } from './ChooseChannelPopover'
9import { RealtimeFilterPopover } from './RealtimeFilterPopover'
10import { RealtimeTokensPopover } from './RealtimeTokensPopover'
11import { RealtimeConfig } from './useRealtimeMessages'
12import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
13import { ShortcutTooltip } from '@/components/ui/ShortcutTooltip'
14import { getTemporaryAPIKey } from '@/data/api-keys/temp-api-keys-query'
15import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
16import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
17import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
18import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
19import { useShortcut } from '@/state/shortcuts/useShortcut'
20
21interface HeaderProps {
22 config: RealtimeConfig
23 onChangeConfig: Dispatch<SetStateAction<RealtimeConfig>>
24 channelPopoverOpen: boolean
25 onChannelPopoverChange: (open: boolean) => void
26 filterPopoverOpen: boolean
27 onFilterPopoverChange: (open: boolean) => void
28}
29
30export const Header = ({
31 config,
32 onChangeConfig,
33 channelPopoverOpen,
34 onChannelPopoverChange,
35 filterPopoverOpen,
36 onFilterPopoverChange,
37}: HeaderProps) => {
38 const { mutate: sendEvent } = useSendEventMutation()
39 const { ref } = useParams()
40 const { data: org } = useSelectedOrganizationQuery()
41
42 const { can: canReadAPIKeys } = useAsyncCheckPermissions(
43 PermissionAction.READ,
44 'service_api_keys'
45 )
46
47 const canToggleListening = canReadAPIKeys && config.channelName.length > 0
48
49 const handleToggleListening = useCallback(async () => {
50 const willStartListening = !config.enabled
51 // [Joshen] Refresh if starting to listen + using temp API key, since it has a low refresh rate
52 if (willStartListening && (config.token.startsWith('sb_temp') || !IS_PLATFORM)) {
53 const data = await getTemporaryAPIKey({ projectRef: config.projectRef, expiry: 3600 })
54 const token = data.api_key
55 onChangeConfig({ ...config, token, enabled: !config.enabled })
56 } else {
57 onChangeConfig({ ...config, enabled: !config.enabled })
58 }
59
60 if (willStartListening) {
61 sendEvent({
62 action: 'realtime_inspector_listen_channel_clicked',
63 groups: {
64 project: ref ?? 'Unknown',
65 organization: org?.slug ?? 'Unknown',
66 },
67 })
68 }
69 }, [config, onChangeConfig, sendEvent, ref, org])
70
71 useShortcut(SHORTCUT_IDS.INSPECTOR_TOGGLE_LISTENING, handleToggleListening, {
72 enabled: canToggleListening,
73 })
74
75 const listeningButton = (
76 <Button
77 size="tiny"
78 type={config.enabled ? 'warning' : 'primary'}
79 className="rounded-l-none border-l-0"
80 disabled={!canToggleListening}
81 icon={config.enabled ? <StopCircle size="16" /> : <PlayCircle size="16" />}
82 onClick={handleToggleListening}
83 >
84 {config.enabled ? `Stop listening` : `Start listening`}
85 </Button>
86 )
87
88 return (
89 <div className="flex flex-row min-h-14 md:min-h-(--header-height) gap-2.5 items-center px-4 border-b ">
90 <div className="flex flex-row">
91 <ChooseChannelPopover
92 config={config}
93 onChangeConfig={onChangeConfig}
94 open={channelPopoverOpen}
95 onOpenChange={onChannelPopoverChange}
96 />
97 <RealtimeTokensPopover config={config} onChangeConfig={onChangeConfig} />
98 {canToggleListening ? (
99 <ShortcutTooltip shortcutId={SHORTCUT_IDS.INSPECTOR_TOGGLE_LISTENING} side="bottom">
100 {listeningButton}
101 </ShortcutTooltip>
102 ) : (
103 <ButtonTooltip
104 size="tiny"
105 type={config.enabled ? 'warning' : 'primary'}
106 className="rounded-l-none border-l-0"
107 disabled
108 icon={config.enabled ? <StopCircle size="16" /> : <PlayCircle size="16" />}
109 onClick={handleToggleListening}
110 tooltip={{
111 content: {
112 side: 'bottom',
113 text: !canReadAPIKeys
114 ? 'You need additional permissions to use the realtime inspector'
115 : config.channelName.length === 0
116 ? 'You need to join a channel first'
117 : undefined,
118 },
119 }}
120 >
121 {config.enabled ? `Stop listening` : `Start listening`}
122 </ButtonTooltip>
123 )}
124 </div>
125 <RealtimeFilterPopover
126 config={config}
127 onChangeConfig={onChangeConfig}
128 open={filterPopoverOpen}
129 onOpenChange={onFilterPopoverChange}
130 />
131 </div>
132 )
133}