diff --git a/admin/src/components/command-palette/CommandPalette.tsx b/admin/src/components/command-palette/CommandPalette.tsx index 144ba62..0a73892 100644 --- a/admin/src/components/command-palette/CommandPalette.tsx +++ b/admin/src/components/command-palette/CommandPalette.tsx @@ -194,7 +194,7 @@ export default function CommandPalette() { }, [query, recentItems, allItems, favoriteCommandItems]); // Flatten all results into a single list for keyboard navigation. - // Order: Favorites → Recent → Pages → Actions → Entities → Settings + // Order: Favorites → Recent → Pages → Entities → Actions → Settings const flatList = useMemo((): FlatItem[] => { const items: FlatItem[] = []; if (!query) { @@ -207,14 +207,15 @@ export default function CommandPalette() { } else if (parsed.showScopeList) { // No items when showing scope selector } else { - // Pages (navigation) first, then actions const pages = commandResults.filter((i) => i.category === 'navigation'); const actions = commandResults.filter((i) => i.category === 'action'); const settings = commandResults.filter((i) => i.category === 'settings'); + // Pages first (exact name matches ranked highest by MiniSearch) for (const item of pages) items.push({ type: 'command', item }); - for (const item of actions) items.push({ type: 'command', item }); - // Entities in the middle + // Entities next (database records like doc files, campaigns, users) for (const item of entityResults) items.push({ type: 'entity', item }); + // Actions after entities + for (const item of actions) items.push({ type: 'command', item }); // Settings last for (const item of settings) items.push({ type: 'command', item }); } @@ -268,6 +269,7 @@ export default function CommandPalette() { // Group commands by category for display, in priority order: // Pages (navigation) → Actions → Settings (least frequent) + // Entities are interleaved between pages and actions in the render phase. // NOTE: These hooks must stay above the early return to satisfy Rules of Hooks const CATEGORY_ORDER: (CommandCategory | 'favorites' | 'recent')[] = [ 'favorites', 'recent', 'navigation', 'action', 'settings', @@ -451,15 +453,15 @@ export default function CommandPalette() { )} - {/* Render in priority order: Pages → Actions → Entities → Settings + {/* Render in priority order: Pages → Entities → Actions → Settings For no-query mode: Favorites → Recent (no entities) */} {(() => { const sections: React.ReactNode[] = []; const commandEntries = Array.from(groupedCommands.entries()); - // Render command groups that come before entities (everything except settings) + // Pages (navigation) first — skip actions and settings for now for (const [groupKey, items] of commandEntries) { - if (groupKey === 'settings') continue; // settings rendered after entities + if (groupKey === 'settings' || groupKey === 'action') continue; sections.push( , + ); + flatIndex += actionItems.length; + } + // Settings last const settingsItems = groupedCommands.get('settings'); if (settingsItems) { diff --git a/admin/src/components/command-palette/useCommandIndex.ts b/admin/src/components/command-palette/useCommandIndex.ts index dba0d28..4f3aaf1 100644 --- a/admin/src/components/command-palette/useCommandIndex.ts +++ b/admin/src/components/command-palette/useCommandIndex.ts @@ -87,7 +87,9 @@ export function useCommandIndex() { searchOptions: { boost: { title: 10, keywordsJoined: 3, group: 1 }, prefix: true, - fuzzy: 0.2, + // Only allow fuzzy matching for terms 5+ chars to prevent + // false positives like "test" → "text" + fuzzy: (term) => (term.length >= 5 ? 0.2 : false), }, });