ui: degrade the working directory picker when file search is off (#26811)
The picker mounts whenever a cwd-aware builtin tool is enabled, so it can open while file_glob_search is not served or was disabled by the user. Every typed query then fired a search that could only fail with a raw error. Gate the debounced search on the tool state, the same way the mention picker does, and show a message in place of the results list that explains why search is unavailable. Manual entry with Enter still commits a directory. The Browse button and the search scope footer are hidden as well: Browse resolves the picked folder name through file_glob_search, and the client-side toggle would not stop that call.
This commit is contained in:
@@ -67,6 +67,20 @@
|
|||||||
const pickerSupported =
|
const pickerSupported =
|
||||||
typeof window !== 'undefined' && typeof window.showDirectoryPicker === 'function';
|
typeof window !== 'undefined' && typeof window.showDirectoryPicker === 'function';
|
||||||
|
|
||||||
|
// When the server does not serve file_glob_search or the user disabled
|
||||||
|
// it, the picker still opens for manual entry but explains why search is
|
||||||
|
// unavailable instead of firing searches that would only fail. Browse is
|
||||||
|
// hidden too: it resolves the picked folder name through the same tool.
|
||||||
|
const fileSearchKey = $derived(toolsStore.getPermissionKey(BuiltInTool.FILE_GLOB_SEARCH));
|
||||||
|
const fileSearchEnabled = $derived(
|
||||||
|
fileSearchKey !== null && toolsStore.isToolEnabled(fileSearchKey)
|
||||||
|
);
|
||||||
|
const searchUnavailableMessage = $derived(
|
||||||
|
fileSearchKey === null
|
||||||
|
? 'File search is unavailable on this server - type a full path and press Enter'
|
||||||
|
: 'File search is disabled - type a full path and press Enter, or enable "Search files" in Settings > Tools'
|
||||||
|
);
|
||||||
|
|
||||||
let searchInputRef: HTMLInputElement | null = $state(null);
|
let searchInputRef: HTMLInputElement | null = $state(null);
|
||||||
|
|
||||||
let queryResults = $state<string[]>([]);
|
let queryResults = $state<string[]>([]);
|
||||||
@@ -98,7 +112,7 @@
|
|||||||
if (!isOpen) return;
|
if (!isOpen) return;
|
||||||
const q = query.trim();
|
const q = query.trim();
|
||||||
nav.reset(-1);
|
nav.reset(-1);
|
||||||
if (q) {
|
if (q && fileSearchEnabled) {
|
||||||
search.run(q);
|
search.run(q);
|
||||||
} else {
|
} else {
|
||||||
search.cancel();
|
search.cancel();
|
||||||
@@ -123,7 +137,7 @@
|
|||||||
// children too, so path navigation does not require a trailing slash.
|
// children too, so path navigation does not require a trailing slash.
|
||||||
const search = useDebouncedSearch({
|
const search = useDebouncedSearch({
|
||||||
debounceMs: SEARCH_DEBOUNCE_MS,
|
debounceMs: SEARCH_DEBOUNCE_MS,
|
||||||
canRun: () => isOpen,
|
canRun: () => isOpen && fileSearchEnabled,
|
||||||
getQuery: () => query.trim(),
|
getQuery: () => query.trim(),
|
||||||
run: async (q, signal, isCurrent) => {
|
run: async (q, signal, isCurrent) => {
|
||||||
const trimmed = q.trim();
|
const trimmed = q.trim();
|
||||||
@@ -340,7 +354,9 @@
|
|||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if query.trim() && (search.isSearching || queryResults.length > 0 || searchError)}
|
{#if !fileSearchEnabled}
|
||||||
|
<div class="px-2 py-1.5 text-sm text-muted-foreground">{searchUnavailableMessage}</div>
|
||||||
|
{:else if query.trim() && (search.isSearching || queryResults.length > 0 || searchError)}
|
||||||
<ChatFormWorkingDirectoryResultsList
|
<ChatFormWorkingDirectoryResultsList
|
||||||
results={queryResults}
|
results={queryResults}
|
||||||
hoveredIndex={nav.hoveredIndex}
|
hoveredIndex={nav.hoveredIndex}
|
||||||
@@ -353,7 +369,7 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if pickerSupported}
|
{#if pickerSupported && fileSearchEnabled}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="-mt-1 flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground"
|
class="-mt-1 flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground"
|
||||||
@@ -364,7 +380,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if homeBase}
|
{#if homeBase && fileSearchEnabled}
|
||||||
<div class="-mx-2 my-2 h-px bg-border/20" aria-hidden="true"></div>
|
<div class="-mx-2 my-2 h-px bg-border/20" aria-hidden="true"></div>
|
||||||
|
|
||||||
<span class="px-2 py-1.5 font-mono text-[10px]">
|
<span class="px-2 py-1.5 font-mono text-[10px]">
|
||||||
|
|||||||
Reference in New Issue
Block a user