mirror of
https://github.com/supabase/supabase.git
synced 2026-10-07 18:35:07 +03:00
## Problem The `ui-patterns/CommandMenu` exposes internal components that have the same names as the base shadcn components they wrap. This create confusion about which one to use and forces us to expose the base ones with the `_Shadcn_` suffix. ## Solution Rename those internal components to have `CommandMenu` in their names to make it clearer they are meant to be used with `CommandMenu`. We will then rename the shadcn base ones to remove the suffix. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Refactor * Standardized Command Menu component naming across the design system for improved consistency and clarity. Updated component names: `CommandInput` → `CommandMenuInput`, `CommandList` → `CommandMenuList`, `CommandItem` → `CommandMenuItem`, `CommandEmpty` → `CommandMenuEmpty`, and `CommandGroup` → `CommandMenuGroup`. Updated public API exports, internal subpath references, all examples within the registry, and implementations across documentation, studio, and application interfaces. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45996) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
153 lines
4.4 KiB
TypeScript
153 lines
4.4 KiB
TypeScript
'use client'
|
|
|
|
import { IS_PLATFORM } from 'common'
|
|
import { Auth, EdgeFunctions, Storage } from 'icons'
|
|
import { Database } from 'lucide-react'
|
|
import { useMemo } from 'react'
|
|
import type { ICommand } from 'ui-patterns/CommandMenu'
|
|
import {
|
|
CommandHeader,
|
|
CommandMenuInput,
|
|
CommandWrapper,
|
|
PageType,
|
|
useQuery,
|
|
useRegisterCommands,
|
|
useRegisterPage,
|
|
useSetPage,
|
|
} from 'ui-patterns/CommandMenu'
|
|
|
|
import { COMMAND_MENU_SECTIONS } from './CommandMenu.utils'
|
|
import { ContextSearchResults } from './ContextSearchResults'
|
|
import { orderCommandSectionsByPriority } from './ordering'
|
|
import type { SearchContextValue } from './SearchContext.types'
|
|
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
|
|
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
|
|
|
interface SearchContextOption {
|
|
value: SearchContextValue
|
|
label: string
|
|
pageName: string
|
|
placeholder: string
|
|
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>
|
|
}
|
|
|
|
const SEARCH_CONTEXT_OPTIONS: SearchContextOption[] = [
|
|
{
|
|
value: 'database-tables',
|
|
label: 'Database Tables',
|
|
pageName: 'Search Database Tables',
|
|
placeholder: 'Search database tables...',
|
|
icon: Database,
|
|
},
|
|
{
|
|
value: 'auth-policies',
|
|
label: 'RLS Policies',
|
|
pageName: 'Search RLS Policies',
|
|
placeholder: 'Search rls policies...',
|
|
icon: Auth,
|
|
},
|
|
{
|
|
value: 'edge-functions',
|
|
label: 'Edge Functions',
|
|
pageName: 'Search Edge Functions',
|
|
placeholder: 'Search edge functions...',
|
|
icon: EdgeFunctions,
|
|
},
|
|
{
|
|
value: 'storage',
|
|
label: 'Storage',
|
|
pageName: 'Search Storage',
|
|
placeholder: 'Search buckets...',
|
|
icon: Storage,
|
|
},
|
|
]
|
|
|
|
function ContextSearchPage({
|
|
context,
|
|
placeholder,
|
|
}: {
|
|
context: SearchContextValue
|
|
placeholder: string
|
|
}) {
|
|
const query = useQuery()
|
|
|
|
return (
|
|
<CommandWrapper>
|
|
<CommandHeader>
|
|
<CommandMenuInput placeholder={placeholder} />
|
|
</CommandHeader>
|
|
<ContextSearchResults context={context} query={query} />
|
|
</CommandWrapper>
|
|
)
|
|
}
|
|
|
|
export function useContextSearchCommands() {
|
|
const { data: project } = useSelectedProjectQuery()
|
|
const setPage = useSetPage()
|
|
|
|
const {
|
|
projectAuthAll: authEnabled,
|
|
projectEdgeFunctionAll: edgeFunctionsEnabled,
|
|
projectStorageAll: storageEnabled,
|
|
} = useIsFeatureEnabled(['project_auth:all', 'project_edge_function:all', 'project_storage:all'])
|
|
|
|
const pageDefinitions = [
|
|
{ title: 'Search Database Tables', context: 'database-tables' as const },
|
|
{ title: 'Search RLS Policies', context: 'auth-policies' as const },
|
|
{ title: 'Search Edge Functions', context: 'edge-functions' as const },
|
|
{ title: 'Search Storage', context: 'storage' as const },
|
|
]
|
|
|
|
// Register pages - pageDefinitions is constant, so hooks are called in consistent order
|
|
for (const { title, context } of pageDefinitions) {
|
|
const placeholder =
|
|
SEARCH_CONTEXT_OPTIONS.find((opt) => opt.value === context)?.placeholder ?? ''
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
useRegisterPage(title, {
|
|
type: PageType.Component,
|
|
component: () => <ContextSearchPage context={context} placeholder={placeholder} />,
|
|
})
|
|
}
|
|
|
|
const contextCommands = useMemo(() => {
|
|
return SEARCH_CONTEXT_OPTIONS.filter((option) => {
|
|
let isFeatureEnabled = false
|
|
switch (option.value) {
|
|
case 'database-tables':
|
|
isFeatureEnabled = true
|
|
break
|
|
case 'auth-policies':
|
|
isFeatureEnabled = authEnabled
|
|
break
|
|
case 'edge-functions':
|
|
isFeatureEnabled = edgeFunctionsEnabled
|
|
break
|
|
case 'storage':
|
|
isFeatureEnabled = storageEnabled
|
|
break
|
|
}
|
|
|
|
if (!isFeatureEnabled) return false
|
|
|
|
// If self-hosted, show if feature is enabled
|
|
if (!IS_PLATFORM) {
|
|
return true
|
|
}
|
|
|
|
// only show when inside a project if not self-hosted
|
|
return !!project
|
|
}).map((option) => ({
|
|
id: `search-${option.value}`,
|
|
name: `Search ${option.label}...`,
|
|
action: () => setPage(option.pageName),
|
|
icon: () => <option.icon className="h-4 w-4" strokeWidth={1.5} />,
|
|
})) as ICommand[]
|
|
}, [setPage, authEnabled, edgeFunctionsEnabled, storageEnabled, project])
|
|
|
|
useRegisterCommands(COMMAND_MENU_SECTIONS.QUERY, contextCommands, {
|
|
orderSection: orderCommandSectionsByPriority,
|
|
sectionMeta: { priority: 3 },
|
|
enabled: !IS_PLATFORM || !!project,
|
|
})
|
|
}
|