MetricOptions.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // @ts-nocheck
  2. import { useDebounce } from '@uidotdev/usehooks'
  3. import { useParams } from 'common'
  4. import { Home, Plus } from 'lucide-react'
  5. import { useState } from 'react'
  6. import {
  7. Command,
  8. CommandGroup,
  9. CommandInput,
  10. CommandItem,
  11. CommandList,
  12. DropdownMenuCheckboxItem,
  13. DropdownMenuPortal,
  14. DropdownMenuSub,
  15. DropdownMenuSubContent,
  16. DropdownMenuSubTrigger,
  17. SQL_ICON,
  18. } from 'ui'
  19. import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
  20. import { DEPRECATED_REPORTS } from './Reports.constants'
  21. import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
  22. import { useContentQuery } from '@/data/content/content-query'
  23. import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
  24. import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
  25. import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
  26. import { Metric, METRIC_CATEGORIES, METRICS } from '@/lib/constants/metrics'
  27. import { editorPanelState } from '@/state/editor-panel-state'
  28. import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
  29. import type { Dashboards } from '@/types'
  30. interface MetricOptionsProps {
  31. config?: Dashboards.Content
  32. handleChartSelection: ({
  33. metric,
  34. isAddingChart,
  35. }: {
  36. metric: Metric
  37. isAddingChart: boolean
  38. }) => void
  39. }
  40. export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsProps) => {
  41. const { ref: projectRef } = useParams()
  42. const { data: selectedOrganization } = useSelectedOrganizationQuery()
  43. const { openSidebar } = useSidebarManagerSnapshot()
  44. const [search, setSearch] = useState('')
  45. const { projectAuthAll: authEnabled, projectStorageAll: storageEnabled } = useIsFeatureEnabled([
  46. 'project_auth:all',
  47. 'project_storage:all',
  48. ])
  49. const metricCategories = Object.values(METRIC_CATEGORIES).filter(({ key }) => {
  50. if (key === 'api_auth') return authEnabled
  51. if (key === 'api_storage') return storageEnabled
  52. return true
  53. })
  54. const { mutate: sendEvent } = useSendEventMutation()
  55. const debouncedSearch = useDebounce(search, 300)
  56. const {
  57. data,
  58. isPending: isLoading,
  59. refetch,
  60. } = useContentQuery({
  61. projectRef,
  62. type: 'sql',
  63. name: debouncedSearch.length === 0 ? undefined : debouncedSearch,
  64. })
  65. const snippets = data?.content
  66. return (
  67. <>
  68. {metricCategories.map((cat) => {
  69. return (
  70. <DropdownMenuSub key={cat.key}>
  71. <DropdownMenuSubTrigger className="space-x-2">
  72. {cat.icon ? cat.icon() : <Home size={14} />}
  73. <p>{cat.label}</p>
  74. </DropdownMenuSubTrigger>
  75. <DropdownMenuPortal>
  76. <DropdownMenuSubContent>
  77. {METRICS.filter(
  78. (metric) =>
  79. !DEPRECATED_REPORTS.includes(metric.key) && metric?.category?.key === cat.key
  80. ).map((metric) => {
  81. return (
  82. <DropdownMenuCheckboxItem
  83. key={metric.key}
  84. className="cursor-pointer"
  85. checked={config?.layout?.some((x: any) => x.attribute === metric.key)}
  86. onCheckedChange={(e) => handleChartSelection({ metric, isAddingChart: e })}
  87. >
  88. <div className="flex flex-col space-y-0">
  89. <span>{metric.label}</span>
  90. </div>
  91. </DropdownMenuCheckboxItem>
  92. )
  93. })}
  94. </DropdownMenuSubContent>
  95. </DropdownMenuPortal>
  96. </DropdownMenuSub>
  97. )
  98. })}
  99. <DropdownMenuSub
  100. onOpenChange={(open) => {
  101. if (open) refetch()
  102. }}
  103. >
  104. <DropdownMenuSubTrigger className="space-x-2">
  105. <SQL_ICON
  106. size={14}
  107. strokeWidth={1.5}
  108. className="fill-foreground-light w-5 h-4 shrink-0 grow-0 -ml-0.5"
  109. />
  110. <p>SQL Snippets</p>
  111. </DropdownMenuSubTrigger>
  112. <DropdownMenuPortal>
  113. <DropdownMenuSubContent className="p-0">
  114. <Command shouldFilter={false}>
  115. <CommandInput
  116. autoFocus
  117. placeholder="Search snippets..."
  118. value={search}
  119. onValueChange={setSearch}
  120. />
  121. <CommandList>
  122. {isLoading ? (
  123. <div className="flex flex-col p-1 gap-y-1">
  124. <ShimmeringLoader />
  125. <ShimmeringLoader className="w-3/4" />
  126. </div>
  127. ) : !snippets?.length ? (
  128. <p className="text-xs text-center text-foreground-lighter py-3">
  129. No snippets found
  130. </p>
  131. ) : null}
  132. <CommandGroup>
  133. {snippets?.map((snippet) => (
  134. <CommandItem
  135. key={snippet.id}
  136. value={snippet.id}
  137. className="cursor-pointer"
  138. onSelect={() => {
  139. if (!config?.layout.find((x) => x.id === snippet.id)) {
  140. handleChartSelection({
  141. metric: {
  142. id: snippet.id,
  143. key: `snippet_${snippet.id}`,
  144. label: snippet.name,
  145. },
  146. isAddingChart: true,
  147. })
  148. sendEvent({
  149. action: 'custom_report_add_sql_block_clicked',
  150. groups: {
  151. project: projectRef ?? 'Unknown',
  152. organization: selectedOrganization?.slug ?? 'Unknown',
  153. },
  154. })
  155. }
  156. }}
  157. >
  158. {snippet.name}
  159. </CommandItem>
  160. ))}
  161. </CommandGroup>
  162. </CommandList>
  163. <div className="h-px bg-border-overlay -mx-1" />
  164. <CommandGroup>
  165. <CommandItem
  166. className="cursor-pointer w-full"
  167. onSelect={() => {
  168. editorPanelState.openAsNew()
  169. openSidebar(SIDEBAR_KEYS.EDITOR_PANEL)
  170. }}
  171. >
  172. <div className="w-full flex items-center gap-2">
  173. <Plus size={14} strokeWidth={1.5} />
  174. <p>Create snippet</p>
  175. </div>
  176. </CommandItem>
  177. </CommandGroup>
  178. </Command>
  179. </DropdownMenuSubContent>
  180. </DropdownMenuPortal>
  181. </DropdownMenuSub>
  182. </>
  183. )
  184. }