better cache usage, make filters blue

This commit is contained in:
Cole Goldsmith 2025-09-23 11:04:27 -05:00
parent 744a799c11
commit 0b39baa5ec
6 changed files with 43 additions and 23 deletions

View file

@ -12,6 +12,7 @@ import { Button } from "./ui/button";
import { DeleteConfirmationDialog } from "./confirmation-dialog"; import { DeleteConfirmationDialog } from "./confirmation-dialog";
import { useDeleteDocument } from "@/app/api/mutations/useDeleteDocument"; import { useDeleteDocument } from "@/app/api/mutations/useDeleteDocument";
import { toast } from "sonner"; import { toast } from "sonner";
import { useRouter } from "next/navigation";
interface KnowledgeActionsDropdownProps { interface KnowledgeActionsDropdownProps {
filename: string; filename: string;
@ -22,6 +23,7 @@ export const KnowledgeActionsDropdown = ({
}: KnowledgeActionsDropdownProps) => { }: KnowledgeActionsDropdownProps) => {
const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const deleteDocumentMutation = useDeleteDocument(); const deleteDocumentMutation = useDeleteDocument();
const router = useRouter();
const handleDelete = async () => { const handleDelete = async () => {
try { try {
@ -43,7 +45,17 @@ export const KnowledgeActionsDropdown = ({
<EllipsisVertical className="h-4 w-4" /> <EllipsisVertical className="h-4 w-4" />
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent side="right" sideOffset={-10}> <DropdownMenuContent side="right" align="start" sideOffset={-10}>
<DropdownMenuItem
className="text-primary focus:text-primary"
onClick={() => {
router.push(
`/knowledge/chunks?filename=${encodeURIComponent(filename)}`
);
}}
>
View chunks
</DropdownMenuItem>
{/* //TODO: Implement rename and sync */} {/* //TODO: Implement rename and sync */}
{/* <DropdownMenuItem {/* <DropdownMenuItem
className="text-primary focus:text-primary" className="text-primary focus:text-primary"

View file

@ -6,7 +6,7 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { Filter, Loader2, Plus, Save } from "lucide-react"; import { Filter, Loader2, Plus, Save, X } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { import {
useGetFiltersSearchQuery, useGetFiltersSearchQuery,
@ -123,7 +123,7 @@ export function KnowledgeFilterList({
size="sm" size="sm"
onClick={handleCreateNew} onClick={handleCreateNew}
title="Create New Filter" title="Create New Filter"
className="h-8 px-3" className="h-8 px-3 text-muted-foreground"
> >
<Plus className="h-3 w-3" /> <Plus className="h-3 w-3" />
</Button> </Button>
@ -152,7 +152,9 @@ export function KnowledgeFilterList({
> >
<div className="flex flex-col gap-1 flex-1 min-w-0"> <div className="flex flex-col gap-1 flex-1 min-w-0">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Filter className="h-4 w-4" /> <div className="flex items-center justify-center bg-blue-500/20 w-5 h-5 rounded">
<Filter className="h-3 w-3 text-blue-400" />
</div>
<div className="text-sm font-medium truncate group-hover:text-accent-foreground"> <div className="text-sm font-medium truncate group-hover:text-accent-foreground">
{filter.name} {filter.name}
</div> </div>
@ -172,8 +174,8 @@ export function KnowledgeFilterList({
</div> </div>
<span className="text-xs bg-muted text-muted-foreground px-1 py-0.5 rounded-sm"> <span className="text-xs bg-muted text-muted-foreground px-1 py-0.5 rounded-sm">
{(() => { {(() => {
const dataSources = const dataSources = parseQueryData(filter.query_data)
parseQueryData(filter.query_data).filters.data_sources; .filters.data_sources;
if (dataSources[0] === "*") return "All sources"; if (dataSources[0] === "*") return "All sources";
const count = dataSources.length; const count = dataSources.length;
return `${count} ${count === 1 ? "source" : "sources"}`; return `${count} ${count === 1 ? "source" : "sources"}`;
@ -181,6 +183,19 @@ export function KnowledgeFilterList({
</span> </span>
</div> </div>
</div> </div>
{selectedFilter?.id === filter.id && (
<Button
variant="ghost"
size="sm"
className="px-0"
onClick={(e) => {
e.stopPropagation();
onFilterSelect(null);
}}
>
<X className="h-4 w-4 flex-shrink-0 opacity-0 group-hover:opacity-100 text-muted-foreground" />
</Button>
)}
</div> </div>
)) ))
)} )}
@ -189,7 +204,7 @@ export function KnowledgeFilterList({
<Dialog open={showCreateModal} onOpenChange={setShowCreateModal}> <Dialog open={showCreateModal} onOpenChange={setShowCreateModal}>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>Create New Knowledge Filter</DialogTitle> <DialogTitle>Create a new knowledge filter</DialogTitle>
<DialogDescription> <DialogDescription>
Save a reusable filter to quickly scope searches across your Save a reusable filter to quickly scope searches across your
knowledge base. knowledge base.

View file

@ -44,7 +44,7 @@ export const useCreateFilter = () => {
return useMutation({ return useMutation({
mutationFn: createFilter, mutationFn: createFilter,
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["knowledge-filters"], exact: false }); queryClient.invalidateQueries({ queryKey: ["knowledge-filters"]});
}, },
}); });
}; };

View file

@ -33,7 +33,7 @@ export const useDeleteFilter = () => {
mutationFn: deleteFilter, mutationFn: deleteFilter,
onSuccess: () => { onSuccess: () => {
// Invalidate filters queries so UI refreshes automatically // Invalidate filters queries so UI refreshes automatically
queryClient.invalidateQueries({ queryKey: ["knowledge-filters"], exact: false }); queryClient.invalidateQueries({ queryKey: ["knowledge-filters"] });
}, },
}); });
}; };

View file

@ -46,7 +46,7 @@ export const useUpdateFilter = () => {
mutationFn: updateFilter, mutationFn: updateFilter,
onSuccess: () => { onSuccess: () => {
// Refresh any knowledge filter lists/searches // Refresh any knowledge filter lists/searches
queryClient.invalidateQueries({ queryKey: ["knowledge-filters"], exact: false }); queryClient.invalidateQueries({ queryKey: ["knowledge-filters"] });
}, },
}); });
}; };

View file

@ -3,14 +3,13 @@
import { import {
Building2, Building2,
Cloud, Cloud,
Filter,
HardDrive, HardDrive,
Search, Search,
Trash2, Trash2,
X, X,
} from "lucide-react"; } from "lucide-react";
import { AgGridReact, CustomCellRendererProps } from "ag-grid-react"; import { AgGridReact, CustomCellRendererProps } from "ag-grid-react";
import { useCallback, useEffect, useState, useRef, ChangeEvent } from "react"; import { useCallback, useState, useRef, ChangeEvent } from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { SiGoogledrive } from "react-icons/si"; import { SiGoogledrive } from "react-icons/si";
import { TbBrandOnedrive } from "react-icons/tb"; import { TbBrandOnedrive } from "react-icons/tb";
@ -60,11 +59,10 @@ function SearchPage() {
const deleteDocumentMutation = useDeleteDocument(); const deleteDocumentMutation = useDeleteDocument();
const { const { data = [], isFetching } = useGetSearchQuery(
data = [], parsedFilterData?.query || "*",
isFetching, parsedFilterData
refetch: refetchSearch, );
} = useGetSearchQuery(parsedFilterData?.query || "", parsedFilterData);
const handleTableSearch = (e: ChangeEvent<HTMLInputElement>) => { const handleTableSearch = (e: ChangeEvent<HTMLInputElement>) => {
gridRef.current?.api.setGridOption("quickFilterText", e.target.value); gridRef.current?.api.setGridOption("quickFilterText", e.target.value);
@ -200,10 +198,6 @@ function SearchPage() {
} }
}; };
useEffect(() => {
refetchSearch();
}, [selectedFilter, refetchSearch]);
return ( return (
<div <div
className={`fixed inset-0 md:left-72 top-[53px] flex flex-col transition-all duration-300 ${ className={`fixed inset-0 md:left-72 top-[53px] flex flex-col transition-all duration-300 ${
@ -230,8 +224,7 @@ function SearchPage() {
<form className="flex gap-3"> <form className="flex gap-3">
<div className="primary-input min-h-10 !flex items-center flex-nowrap gap-2 focus-within:border-foreground transition-colors !py-0"> <div className="primary-input min-h-10 !flex items-center flex-nowrap gap-2 focus-within:border-foreground transition-colors !py-0">
{selectedFilter?.name && ( {selectedFilter?.name && (
<div className="flex items-center gap-2 bg-accent text-accent-foreground px-1 py-0.5 rounded max-w-[300px]"> <div className="flex items-center gap-1 bg-blue-500/20 text-blue-400 px-1.5 py-0.5 rounded max-w-[300px]">
<Filter className="h-3 w-3 flex-shrink-0 ml-1" />
<span className="truncate">{selectedFilter?.name}</span> <span className="truncate">{selectedFilter?.name}</span>
<X <X
aria-label="Remove filter" aria-label="Remove filter"