Move entity results above actions in command palette and tighten fuzzy matching
- Reorder result hierarchy: Pages → Entities → Actions → Settings (doc files and database records now appear right after page matches) - Disable fuzzy matching for terms under 5 characters to prevent false positives like "test" matching "text" (all SMS pages) - Prefix matching still works for short terms (e.g. "mail" → MailHog) Bunker Admin
This commit is contained in:
parent
46fc92fab8
commit
41d86782b4
@ -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() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 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(
|
||||
<CommandGroupSection
|
||||
key={groupKey}
|
||||
@ -476,7 +478,7 @@ export default function CommandPalette() {
|
||||
flatIndex += items.length;
|
||||
}
|
||||
|
||||
// Entity groups (only when searching)
|
||||
// Entities right after pages (doc files, campaigns, users, etc.)
|
||||
if (query && !parsed.showScopeList) {
|
||||
for (const [entityType, items] of groupedEntities.entries()) {
|
||||
sections.push(
|
||||
@ -495,6 +497,25 @@ export default function CommandPalette() {
|
||||
}
|
||||
}
|
||||
|
||||
// Actions after entities
|
||||
const actionItems = groupedCommands.get('action');
|
||||
if (actionItems) {
|
||||
sections.push(
|
||||
<CommandGroupSection
|
||||
key="action"
|
||||
groupKey="action"
|
||||
items={actionItems}
|
||||
flatIndexRef={{ current: flatIndex }}
|
||||
selectedIndex={selectedIndex}
|
||||
favoritePaths={favoritePaths}
|
||||
token={token}
|
||||
onSelect={handleSelect}
|
||||
onHover={setSelectedIndex}
|
||||
/>,
|
||||
);
|
||||
flatIndex += actionItems.length;
|
||||
}
|
||||
|
||||
// Settings last
|
||||
const settingsItems = groupedCommands.get('settings');
|
||||
if (settingsItems) {
|
||||
|
||||
@ -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),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user