Header.tsx 4.8 KB

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