EdgeFunctionSearchResults.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. 'use client'
  2. import { useParams } from 'common'
  3. import { EdgeFunctions } from 'icons'
  4. import { Loader2 } from 'lucide-react'
  5. import { useMemo } from 'react'
  6. import {
  7. EmptyState,
  8. ResultsList,
  9. SkeletonResults,
  10. type SearchResult,
  11. } from './ContextSearchResults.shared'
  12. import { useEdgeFunctionsQuery } from '@/data/edge-functions/edge-functions-query'
  13. interface EdgeFunctionSearchResultsProps {
  14. query: string
  15. }
  16. export function EdgeFunctionSearchResults({ query }: EdgeFunctionSearchResultsProps) {
  17. const { ref: projectRef } = useParams()
  18. const trimmedQuery = query.trim()
  19. const {
  20. data: functions,
  21. isLoading: isLoadingFunctions,
  22. isError: isErrorFunctions,
  23. } = useEdgeFunctionsQuery(
  24. {
  25. projectRef,
  26. },
  27. {
  28. enabled: !!projectRef,
  29. }
  30. )
  31. const functionResults: SearchResult[] = useMemo(() => {
  32. if (!functions) return []
  33. const filtered = trimmedQuery
  34. ? functions.filter((func) => {
  35. const searchLower = trimmedQuery.toLowerCase()
  36. const functionName = func.name?.toLowerCase() || ''
  37. const functionSlug = func.slug?.toLowerCase() || ''
  38. return functionName.includes(searchLower) || functionSlug.includes(searchLower)
  39. })
  40. : functions
  41. // Limit results for performance
  42. return filtered.slice(0, 20).map((func) => {
  43. const displayName = func.name || func.slug || 'Untitled Function'
  44. const description = func.version ? `Version ${func.version}` : undefined
  45. return {
  46. id: String(func.id),
  47. name: displayName,
  48. description,
  49. }
  50. })
  51. }, [functions, trimmedQuery])
  52. const totalFunctions = functions?.length ?? 0
  53. const renderFooter = () => (
  54. <div className="absolute bottom-0 left-0 right-0 flex items-center justify-between min-h-9 h-9 px-4 border-t bg-surface-200 text-xs text-foreground-light z-10">
  55. <div className="flex items-center gap-x-2">
  56. {isLoadingFunctions ? (
  57. <span className="flex items-center gap-2">
  58. <Loader2 size={14} className="animate-spin" /> Loading...
  59. </span>
  60. ) : (
  61. <span>
  62. Total: {totalFunctions.toLocaleString()} function{totalFunctions !== 1 ? 's' : ''}
  63. </span>
  64. )}
  65. </div>
  66. </div>
  67. )
  68. if (isLoadingFunctions) {
  69. return (
  70. <div className="relative h-full flex flex-col">
  71. <div className="flex-1 min-h-0 overflow-hidden">
  72. <SkeletonResults />
  73. </div>
  74. {renderFooter()}
  75. </div>
  76. )
  77. }
  78. if (isErrorFunctions) {
  79. return (
  80. <div className="relative h-full flex flex-col">
  81. <div className="flex-1 min-h-0 overflow-hidden">
  82. <div className="h-full flex flex-col items-center justify-center py-12 px-4 gap-4 text-center text-foreground-lighter">
  83. <EdgeFunctions className="h-6 w-6" strokeWidth={1.5} />
  84. <p className="text-sm">Failed to load edge functions</p>
  85. </div>
  86. </div>
  87. {renderFooter()}
  88. </div>
  89. )
  90. }
  91. if (functionResults.length === 0) {
  92. return (
  93. <div className="relative h-full flex flex-col">
  94. <div className="flex-1 min-h-0 overflow-hidden">
  95. <EmptyState icon={EdgeFunctions} label="Edge Functions" query={query} />
  96. </div>
  97. {renderFooter()}
  98. </div>
  99. )
  100. }
  101. return (
  102. <div className="relative h-full flex flex-col">
  103. <div className="flex-1 min-h-0 overflow-hidden">
  104. <ResultsList
  105. results={functionResults}
  106. icon={EdgeFunctions}
  107. getRoute={(result) => {
  108. const func = functions?.find((f) => String(f.id) === result.id)
  109. if (!func || !projectRef) return `/project/${projectRef}/functions` as `/${string}`
  110. return `/project/${projectRef}/functions/${func.slug}` as `/${string}`
  111. }}
  112. className="pb-9"
  113. />
  114. </div>
  115. {renderFooter()}
  116. </div>
  117. )
  118. }