Fix text quoting and format web app search page with prettier

This commit is contained in:
Debanjum
2025-01-21 18:18:44 +07:00
parent 8022f040d2
commit 7fad1f43f6

View File

@@ -73,12 +73,8 @@ import {
CommandInput, CommandInput,
CommandItem, CommandItem,
CommandList, CommandList,
} from "@/components/ui/command" } from "@/components/ui/command";
import { import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import { uploadDataForIndexing } from "../common/chatFunctions"; import { uploadDataForIndexing } from "../common/chatFunctions";
import { Progress } from "@/components/ui/progress"; import { Progress } from "@/components/ui/progress";
@@ -125,11 +121,17 @@ interface FileCardProps {
selectedFileFullText: string | null; selectedFileFullText: string | null;
} }
function FileCard({ file, setSelectedFile, setSelectedFileFullText, handleDownload, handleDelete, isDeleting, selectedFileFullText }: FileCardProps) { function FileCard({
file,
setSelectedFile,
setSelectedFileFullText,
handleDownload,
handleDelete,
isDeleting,
selectedFileFullText,
}: FileCardProps) {
return ( return (
<Card <Card className="animate-fade-in-up bg-secondary h-52">
className="animate-fade-in-up bg-secondary h-52"
>
<CardHeader className="p-2"> <CardHeader className="p-2">
<CardTitle <CardTitle
className="flex items-center gap-2 justify-between" className="flex items-center gap-2 justify-between"
@@ -140,36 +142,23 @@ function FileCard({ file, setSelectedFile, setSelectedFileFullText, handleDownlo
<div <div
className="text-sm font-medium truncate hover:text-clip hover:whitespace-normal cursor-pointer" className="text-sm font-medium truncate hover:text-clip hover:whitespace-normal cursor-pointer"
onClick={() => { onClick={() => {
setSelectedFileFullText( setSelectedFileFullText("");
'', setSelectedFile(file.file_name);
);
setSelectedFile(
file.file_name,
);
}} }}
> >
{file.file_name {file.file_name.split("/").pop()}
.split("/")
.pop()}
</div> </div>
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle> <DialogTitle>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{file.file_name {file.file_name.split("/").pop()}
.split("/")
.pop()}
<Button <Button
variant={ variant={"ghost"}
"ghost"
}
title="Download as plaintext" title="Download as plaintext"
onClick={() => onClick={() =>
handleDownload( handleDownload(file.file_name, file.raw_text)
file.file_name,
file.raw_text,
)
} }
> >
<Download className="h-4 w-4" /> <Download className="h-4 w-4" />
@@ -182,15 +171,11 @@ function FileCard({ file, setSelectedFile, setSelectedFileFullText, handleDownlo
{!selectedFileFullText && ( {!selectedFileFullText && (
<InlineLoading <InlineLoading
className="mt-4" className="mt-4"
message={ message={"Loading"}
"Loading"
}
iconClassName="h-5 w-5" iconClassName="h-5 w-5"
/> />
)} )}
{ {selectedFileFullText}
selectedFileFullText
}
</p> </p>
</ScrollArea> </ScrollArea>
</DialogContent> </DialogContent>
@@ -207,16 +192,12 @@ function FileCard({ file, setSelectedFile, setSelectedFileFullText, handleDownlo
variant={"ghost"} variant={"ghost"}
className="flex items-center gap-2 p-1 text-sm" className="flex items-center gap-2 p-1 text-sm"
onClick={() => { onClick={() => {
handleDelete( handleDelete(file.file_name);
file.file_name,
);
}} }}
> >
<Trash className="h-4 w-4" /> <Trash className="h-4 w-4" />
<span className="text-xs"> <span className="text-xs">
{isDeleting {isDeleting ? "Deleting..." : "Delete"}
? "Deleting..."
: "Delete"}
</span> </span>
</Button> </Button>
</DropdownMenuItem> </DropdownMenuItem>
@@ -237,7 +218,7 @@ function FileCard({ file, setSelectedFile, setSelectedFileFullText, handleDownlo
</div> </div>
</CardFooter> </CardFooter>
</Card> </Card>
) );
} }
interface NoteResultProps { interface NoteResultProps {
@@ -397,8 +378,8 @@ const UploadFiles: React.FC<{
<DialogHeader> <DialogHeader>
<DialogTitle>Build Your Knowledge Base</DialogTitle> <DialogTitle>Build Your Knowledge Base</DialogTitle>
<DialogDescription> <DialogDescription>
Add context for your Khoj knowledge base. Add context for your Khoj knowledge base. Quickly search and get
Quickly search and get personalized answers from your documents. personalized answers from your documents.
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
<div <div
@@ -485,8 +466,8 @@ interface FileFilterComboBoxProps {
} }
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.explicitFile || "");
useEffect(() => { useEffect(() => {
if (props.explicitFile) { if (props.explicitFile) {
@@ -504,17 +485,12 @@ function FileFilterComboBox(props: FileFilterComboBoxProps) {
className={`justify-between" ${props.isMobileWidth ? "w-full" : "w-[200px]"}`} className={`justify-between" ${props.isMobileWidth ? "w-full" : "w-[200px]"}`}
> >
{value {value
? ( ? props.isMobileWidth
props.isMobileWidth ? ? "✔️"
"✔️" : "Selected"
: "Selected" : props.isMobileWidth
) ? " "
: ( : "Select file"}
props.isMobileWidth ?
" "
: "Select file"
)
}
<Funnel className="opacity-50" /> <Funnel className="opacity-50" />
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
@@ -529,16 +505,16 @@ function FileFilterComboBox(props: FileFilterComboBoxProps) {
key={file} key={file}
value={file} value={file}
onSelect={(currentValue) => { onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue) setValue(currentValue === value ? "" : currentValue);
setOpen(false) setOpen(false);
props.onChooseFile(currentValue) props.onChooseFile(currentValue);
}} }}
> >
{file} {file}
<Check <Check
className={cn( className={cn(
"ml-auto", "ml-auto",
value === file ? "opacity-100" : "opacity-0" value === file ? "opacity-100" : "opacity-0",
)} )}
/> />
</CommandItem> </CommandItem>
@@ -548,7 +524,7 @@ function FileFilterComboBox(props: FileFilterComboBoxProps) {
</Command> </Command>
</PopoverContent> </PopoverContent>
</Popover> </Popover>
) );
} }
export default function Search() { export default function Search() {
@@ -576,18 +552,18 @@ export default function Search() {
useEffect(() => { useEffect(() => {
// Load all files once on page load // Load all files once on page load
fetch('/api/content/computer', { fetch("/api/content/computer", {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
}, },
}) })
.then(response => response.json()) .then((response) => response.json())
.then(data => { .then((data) => {
setAllFiles(data); setAllFiles(data);
}) })
.catch(error => { .catch((error) => {
console.error('Error loading files:', error); console.error("Error loading files:", error);
}); });
}, []); }, []);
@@ -606,7 +582,6 @@ export default function Search() {
} }
}, [searchQuery]); }, [searchQuery]);
function handleSearchInputChange(value: string) { function handleSearchInputChange(value: string) {
setSearchQuery(value); setSearchQuery(value);
@@ -673,7 +648,6 @@ export default function Search() {
if (Array.isArray(filesList)) { if (Array.isArray(filesList)) {
setFiles(filesList.toSorted()); setFiles(filesList.toSorted());
} }
} catch (error) { } catch (error) {
setError("Failed to load files"); setError("Failed to load files");
console.error("Error fetching files:", error); console.error("Error fetching files:", error);
@@ -778,7 +752,9 @@ export default function Search() {
<Input <Input
autoFocus={true} autoFocus={true}
className="border-none pl-4 focus-visible:ring-transparent focus-visible:ring-offset-transparent" className="border-none pl-4 focus-visible:ring-transparent focus-visible:ring-offset-transparent"
onChange={(e) => handleSearchInputChange(e.currentTarget.value)} onChange={(e) =>
handleSearchInputChange(e.currentTarget.value)
}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === "Enter") { if (e.key === "Enter") {
search(); search();
@@ -791,7 +767,12 @@ export default function Search() {
/> />
</div> </div>
<div id="actions" className="flex gap-2"> <div id="actions" className="flex gap-2">
<FileFilterComboBox allFiles={allFiles} onChooseFile={(file) => applySuggestion(file)} isMobileWidth={isMobileWidth} explicitFile={selectedFileFilter} /> <FileFilterComboBox
allFiles={allFiles}
onChooseFile={(file) => applySuggestion(file)}
isMobileWidth={isMobileWidth}
explicitFile={selectedFileFilter}
/>
<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"
variant={"ghost"} variant={"ghost"}
@@ -870,34 +851,37 @@ export default function Search() {
)} )}
{error && <div className="text-red-500">{error}</div>} {error && <div className="text-red-500">{error}</div>}
{!searchResults && !fileObjectsLoading && files.length === 0 && ( {!searchResults &&
<Card className="flex flex-col items-center justify-center border-none shadow-none"> !fileObjectsLoading &&
<CardHeader className="flex flex-col items-center justify-center"> files.length === 0 && (
<CardDescription className="border-muted-foreground border w-fit rounded-lg mb-2 text-center text-lg p-4"> <Card className="flex flex-col items-center justify-center border-none shadow-none">
<FileDashed <CardHeader className="flex flex-col items-center justify-center">
weight="fill" <CardDescription className="border-muted-foreground border w-fit rounded-lg mb-2 text-center text-lg p-4">
className="text-muted-foreground h-10 w-10" <FileDashed
/> weight="fill"
</CardDescription> className="text-muted-foreground h-10 w-10"
<CardTitle className="text-center"> />
Let's get started! </CardDescription>
</CardTitle> <CardTitle className="text-center">
</CardHeader> Let&apos;s get started!
<CardContent> </CardTitle>
<div className="text-muted-foreground items-center justify-center text-center flex"> </CardHeader>
To use search, upload docs via the "Add Documents" button. <CardContent>
</div> <div className="text-muted-foreground items-center justify-center text-center flex">
<Link To use search, upload docs via the
href="https://docs.khoj.dev/data-sources/share_your_data" &quot;Add Documents&quot; button.
className="no-underline"
>
<div className="mt-4 text-center text-secondary-foreground bg-secondary w-fit m-auto p-2 rounded-lg">
Learn More
</div> </div>
</Link> <Link
</CardContent> href="https://docs.khoj.dev/data-sources/share_your_data"
</Card> className="no-underline"
)} >
<div className="mt-4 text-center text-secondary-foreground bg-secondary w-fit m-auto p-2 rounded-lg">
Learn More
</div>
</Link>
</CardContent>
</Card>
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{files.map((file, index) => ( {files.map((file, index) => (
@@ -906,7 +890,9 @@ export default function Search() {
file={file} file={file}
index={index} index={index}
setSelectedFile={setSelectedFile} setSelectedFile={setSelectedFile}
setSelectedFileFullText={setSelectedFileFullText} setSelectedFileFullText={
setSelectedFileFullText
}
handleDownload={handleDownload} handleDownload={handleDownload}
handleDelete={handleDelete} handleDelete={handleDelete}
isDeleting={isDeleting} isDeleting={isDeleting}
@@ -920,14 +906,22 @@ export default function Search() {
{/* Show prev button if not on first page */} {/* Show prev button if not on first page */}
{pageNumber > 0 && ( {pageNumber > 0 && (
<PaginationItem className="list-none"> <PaginationItem className="list-none">
<PaginationPrevious onClick={() => setPageNumber(pageNumber - 1)} /> <PaginationPrevious
onClick={() =>
setPageNumber(pageNumber - 1)
}
/>
</PaginationItem> </PaginationItem>
)} )}
{/* Show first page if not on first two pages */} {/* Show first page if not on first two pages */}
{pageNumber > 1 && ( {pageNumber > 1 && (
<PaginationItem className="list-none"> <PaginationItem className="list-none">
<PaginationLink onClick={() => setPageNumber(0)}>1</PaginationLink> <PaginationLink
onClick={() => setPageNumber(0)}
>
1
</PaginationLink>
</PaginationItem> </PaginationItem>
)} )}
@@ -941,19 +935,33 @@ export default function Search() {
{/* Show previous page if not on first page */} {/* Show previous page if not on first page */}
{pageNumber > 0 && ( {pageNumber > 0 && (
<PaginationItem className="list-none"> <PaginationItem className="list-none">
<PaginationLink onClick={() => setPageNumber(pageNumber - 1)}>{pageNumber}</PaginationLink> <PaginationLink
onClick={() =>
setPageNumber(pageNumber - 1)
}
>
{pageNumber}
</PaginationLink>
</PaginationItem> </PaginationItem>
)} )}
{/* Current page */} {/* Current page */}
<PaginationItem className="list-none"> <PaginationItem className="list-none">
<PaginationLink isActive>{pageNumber + 1}</PaginationLink> <PaginationLink isActive>
{pageNumber + 1}
</PaginationLink>
</PaginationItem> </PaginationItem>
{/* Show next page if not on last page */} {/* Show next page if not on last page */}
{pageNumber < numPages - 1 && ( {pageNumber < numPages - 1 && (
<PaginationItem className="list-none"> <PaginationItem className="list-none">
<PaginationLink onClick={() => setPageNumber(pageNumber + 1)}>{pageNumber + 2}</PaginationLink> <PaginationLink
onClick={() =>
setPageNumber(pageNumber + 1)
}
>
{pageNumber + 2}
</PaginationLink>
</PaginationItem> </PaginationItem>
)} )}
@@ -967,22 +975,30 @@ export default function Search() {
{/* Show last page if not on last two pages */} {/* Show last page if not on last two pages */}
{pageNumber < numPages - 2 && ( {pageNumber < numPages - 2 && (
<PaginationItem className="list-none"> <PaginationItem className="list-none">
<PaginationLink onClick={() => setPageNumber(numPages - 1)}>{numPages}</PaginationLink> <PaginationLink
onClick={() =>
setPageNumber(numPages - 1)
}
>
{numPages}
</PaginationLink>
</PaginationItem> </PaginationItem>
)} )}
{/* Show next button if not on last page */} {/* Show next button if not on last page */}
{pageNumber < numPages - 1 && ( {pageNumber < numPages - 1 && (
<PaginationItem className="list-none"> <PaginationItem className="list-none">
<PaginationNext onClick={() => setPageNumber(pageNumber + 1)} /> <PaginationNext
onClick={() =>
setPageNumber(pageNumber + 1)
}
/>
</PaginationItem> </PaginationItem>
)} )}
</PaginationContent> </PaginationContent>
</Pagination> </Pagination>
</div> </div>
)} )}
</div> </div>
</div> </div>
</div> </div>