Show full paths in command palette switcher

https://feedback.yaak.app/p/command-palette-search-should-include-parent-folder-names
This commit is contained in:
Gregory Schier
2025-11-03 05:54:29 -08:00
parent c8d5e7c97b
commit f3e44c53d7
4 changed files with 36 additions and 15 deletions

View File

@@ -30,7 +30,10 @@ import { deleteModelWithConfirm } from '../lib/deleteModelWithConfirm';
import { showDialog } from '../lib/dialog';
import { editEnvironment } from '../lib/editEnvironment';
import { renameModelWithPrompt } from '../lib/renameModelWithPrompt';
import { resolvedModelNameWithFolders } from '../lib/resolvedModelName';
import {
resolvedModelNameWithFolders,
resolvedModelNameWithFoldersArray,
} from '../lib/resolvedModelName';
import { router } from '../lib/router';
import { setWorkspaceSearchParams } from '../lib/setWorkspaceSearchParams';
import { CookieDialog } from './CookieDialog';
@@ -40,7 +43,6 @@ import { HotKey } from './core/HotKey';
import { HttpMethodTag } from './core/HttpMethodTag';
import { Icon } from './core/Icon';
import { PlainInput } from './core/PlainInput';
import { HStack } from './core/Stacks';
interface CommandPaletteGroup {
key: string;
@@ -275,10 +277,17 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
key: `switch-request-${r.id}`,
searchText: resolvedModelNameWithFolders(r),
label: (
<HStack space={2}>
<HttpMethodTag short className="text-xs" request={r} />
<div className="truncate">{resolvedModelNameWithFolders(r)}</div>
</HStack>
<div className="flex items-center gap-x-0.5">
<HttpMethodTag short className="text-xs mr-2" request={r} />
{resolvedModelNameWithFoldersArray(r).map((name, i, all) => (
<>
{i !== 0 && (
<Icon icon="chevron_right" className="opacity-80"/>
)}
<div className={classNames(i < all.length - 1 && 'truncate')}>{name}</div>
</>
))}
</div>
),
onSelect: async () => {
await router.navigate({
@@ -400,7 +409,7 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
);
return (
<div className="h-full w-[400px] grid grid-rows-[auto_minmax(0,1fr)] overflow-hidden py-2">
<div className="h-full w-[min(700px,80vw)] grid grid-rows-[auto_minmax(0,1fr)] overflow-hidden py-2">
<div className="px-2 w-full">
<PlainInput
autoFocus

View File

@@ -52,7 +52,13 @@ export function Overlay({
{open && (
<FocusTrap
focusTrapOptions={{
allowOutsideClick: true, // So we can still click toasts and things
// Allow outside click so we can click things like toasts
allowOutsideClick: true,
delayInitialFocus: true,
checkCanFocusTrap: async () => {
// Not sure why delayInitialFocus: true doesn't help, but having this no-op promise
// seems to be required to make things work.
},
}}
>
<m.div

View File

@@ -10,6 +10,7 @@ import {
} from 'react';
import { useRandomKey } from '../../hooks/useRandomKey';
import { useStateWithDeps } from '../../hooks/useStateWithDeps';
import { generateId } from '../../lib/generateId';
import { IconButton } from './IconButton';
import type { InputProps } from './Input';
import { Label } from './Label';
@@ -99,7 +100,7 @@ export const PlainInput = forwardRef<{ focus: () => void }, PlainInputProps>(fun
}
}, [regenerateFocusedUpdateKey, defaultValue]);
const id = `input-${name}`;
const id = useRef(`input-${generateId()}`);
const commonClassName = classNames(
className,
'!bg-transparent min-w-0 w-full focus:outline-none placeholder:text-placeholder',
@@ -134,7 +135,7 @@ export const PlainInput = forwardRef<{ focus: () => void }, PlainInputProps>(fun
)}
>
<Label
htmlFor={id}
htmlFor={id.current}
className={labelClassName}
visuallyHidden={hideLabel}
required={required}
@@ -177,10 +178,11 @@ export const PlainInput = forwardRef<{ focus: () => void }, PlainInputProps>(fun
)}
>
<input
id={id}
id={id.current}
ref={inputRef}
key={forceUpdateKey}
type={type === 'password' && !obscured ? 'text' : type}
name={name}
defaultValue={defaultValue ?? undefined}
autoComplete="off"
autoCapitalize="off"

View File

@@ -1,4 +1,4 @@
import type { AnyModel} from '@yaakapp-internal/models';
import type { AnyModel } from '@yaakapp-internal/models';
import { foldersAtom } from '@yaakapp-internal/models';
import { jotaiStore } from './jotai';
@@ -39,7 +39,11 @@ export function resolvedModelName(r: AnyModel | null): string {
}
export function resolvedModelNameWithFolders(model: AnyModel | null): string {
if (model == null) return '';
return resolvedModelNameWithFoldersArray(model).join(' / ');
}
export function resolvedModelNameWithFoldersArray(model: AnyModel | null): string[] {
if (model == null) return [];
const folders = jotaiStore.get(foldersAtom) ?? [];
const getParents = (m: AnyModel, names: string[]) => {
@@ -47,11 +51,11 @@ export function resolvedModelNameWithFolders(model: AnyModel | null): string {
if ('folderId' in m) {
const parent = folders.find((f) => f.id === m.folderId);
if (parent) {
names = [resolvedModelName(parent), ...names];
names = [...resolvedModelNameWithFoldersArray(parent), ...names];
}
}
return names;
};
return getParents(model, []).join(' / ');
return getParents(model, []);
}