mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-09 05:39:12 +00:00
Allow file filter dropdown to pop up automatically when typing "file:"
This commit is contained in:
@@ -149,7 +149,7 @@ function FileCard({
|
|||||||
{file.file_name.split("/").pop()}
|
{file.file_name.split("/").pop()}
|
||||||
</div>
|
</div>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent>
|
<DialogContent className="max-w-fit">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -166,8 +166,8 @@ function FileCard({
|
|||||||
</div>
|
</div>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<ScrollArea className="h-[50vh]">
|
<ScrollArea className="h-[50vh] w-[80vw]">
|
||||||
<p className="whitespace-pre-wrap break-words text-sm font-normal">
|
<p className="whitespace-pre-wrap break-words text-sm font-normal word-wrap">
|
||||||
{!selectedFileFullText && (
|
{!selectedFileFullText && (
|
||||||
<InlineLoading
|
<InlineLoading
|
||||||
className="mt-4"
|
className="mt-4"
|
||||||
@@ -462,21 +462,53 @@ interface FileFilterComboBoxProps {
|
|||||||
allFiles: string[];
|
allFiles: string[];
|
||||||
onChooseFile: (file: string) => void;
|
onChooseFile: (file: string) => void;
|
||||||
isMobileWidth: boolean;
|
isMobileWidth: boolean;
|
||||||
explicitFile?: string;
|
inputText?: string;
|
||||||
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function FileFilterComboBox(props: FileFilterComboBoxProps) {
|
function FileFilterComboBox(props: FileFilterComboBoxProps) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [value, setValue] = useState(props.explicitFile || "");
|
const [value, setValue] = useState(props.inputText || "");
|
||||||
|
const [noMatchingFiles, setNoMatchingFiles] = useState(false);
|
||||||
|
const [inputText, setInputText] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.explicitFile) {
|
if (props.inputText) {
|
||||||
setValue(props.explicitFile);
|
if (props.inputText === "INITIALIZE") {
|
||||||
|
setOpen(true);
|
||||||
|
setInputText("");
|
||||||
|
} else {
|
||||||
|
setInputText(props.inputText);
|
||||||
|
if (props.allFiles.includes(props.inputText)) {
|
||||||
|
setValue(props.inputText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setInputText("");
|
||||||
}
|
}
|
||||||
}, [props.explicitFile]);
|
}, [props.inputText]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputText && !props.allFiles.includes(inputText)) {
|
||||||
|
setNoMatchingFiles(true);
|
||||||
|
setValue("");
|
||||||
|
} else if (!inputText) {
|
||||||
|
setNoMatchingFiles(false);
|
||||||
|
setValue("");
|
||||||
|
} else {
|
||||||
|
setNoMatchingFiles(false);
|
||||||
|
setValue(inputText);
|
||||||
|
}
|
||||||
|
}, [inputText, props.allFiles]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) {
|
||||||
|
props.onClose();
|
||||||
|
}
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover open={open} onOpenChange={setOpen}>
|
<Popover open={open || (noMatchingFiles && (!!inputText))} onOpenChange={setOpen}>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -489,14 +521,14 @@ function FileFilterComboBox(props: FileFilterComboBoxProps) {
|
|||||||
? "✔️"
|
? "✔️"
|
||||||
: "Selected"
|
: "Selected"
|
||||||
: props.isMobileWidth
|
: props.isMobileWidth
|
||||||
? " "
|
? " "
|
||||||
: "Select file"}
|
: "Select file"}
|
||||||
<Funnel className="opacity-50" />
|
<Funnel className="opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="w-[200px] p-0">
|
<PopoverContent className="w-[200px] p-0">
|
||||||
<Command>
|
<Command>
|
||||||
<CommandInput placeholder="Search files..." />
|
<CommandInput placeholder="Search files..." value={inputText} onInput={(e) => setInputText(e.currentTarget.value)} />
|
||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandEmpty>No files found.</CommandEmpty>
|
<CommandEmpty>No files found.</CommandEmpty>
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
@@ -578,8 +610,11 @@ export default function Search() {
|
|||||||
|
|
||||||
if (extractedFileFilterValue) {
|
if (extractedFileFilterValue) {
|
||||||
setSelectedFileFilter(extractedFileFilterValue);
|
setSelectedFileFilter(extractedFileFilterValue);
|
||||||
|
} else {
|
||||||
|
setSelectedFileFilter("INITIALIZE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [searchQuery]);
|
}, [searchQuery]);
|
||||||
|
|
||||||
function handleSearchInputChange(value: string) {
|
function handleSearchInputChange(value: string) {
|
||||||
@@ -604,8 +639,12 @@ export default function Search() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applySuggestion(suggestion: string) {
|
function applySuggestion(suggestion: string) {
|
||||||
// Append the file: filter with the selected suggestion
|
// Scrub any existing `file:` filter
|
||||||
const newQuery = `file:"${suggestion}" ${searchQuery}`;
|
const fileFilterRegex = /file:([^"\s]*|"[^"]*")?/i;
|
||||||
|
const searchQueryWithoutFileFilter = searchQuery.replace(fileFilterRegex, "").trim();
|
||||||
|
|
||||||
|
// Prepend the file: filter with the selected suggestion
|
||||||
|
const newQuery = `file:"${suggestion}" ${searchQueryWithoutFileFilter}`;
|
||||||
setSearchQuery(newQuery);
|
setSearchQuery(newQuery);
|
||||||
searchInputRef.current?.focus();
|
searchInputRef.current?.focus();
|
||||||
search();
|
search();
|
||||||
@@ -771,7 +810,8 @@ export default function Search() {
|
|||||||
allFiles={allFiles}
|
allFiles={allFiles}
|
||||||
onChooseFile={(file) => applySuggestion(file)}
|
onChooseFile={(file) => applySuggestion(file)}
|
||||||
isMobileWidth={isMobileWidth}
|
isMobileWidth={isMobileWidth}
|
||||||
explicitFile={selectedFileFilter}
|
inputText={selectedFileFilter}
|
||||||
|
onClose={() => searchInputRef.current?.focus()}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className="px-2 gap-2 inline-flex rounded-none items-center border-l border-gray-300 hover:text-gray-500"
|
className="px-2 gap-2 inline-flex rounded-none items-center border-l border-gray-300 hover:text-gray-500"
|
||||||
|
|||||||
Reference in New Issue
Block a user