Files
supabase/apps/studio/components/interfaces/App/CommandMenu/ContextSearchCommands.tsx
T
Gildas Garcia 224dbb09bb chore: rename CommandMenu internal components to avoid conflicts with base shadcn ones (#45996)
## 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 -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45996)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-20 14:05:59 +02:00

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,
})
}