mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-02 22:01:05 +02:00
refactor: enhance DocumentsFilters and FolderTreeView components for improved filter handling and search functionality
This commit is contained in:
parent
3251f0e98d
commit
be7e73e615
5 changed files with 20 additions and 28 deletions
|
|
@ -65,7 +65,7 @@ export function DocumentsFilters({
|
||||||
<div className="flex select-none">
|
<div className="flex select-none">
|
||||||
<div className="flex items-center gap-2 w-full">
|
<div className="flex items-center gap-2 w-full">
|
||||||
{/* Filter + New Folder Toggle Group */}
|
{/* Filter + New Folder Toggle Group */}
|
||||||
<ToggleGroup type="multiple" variant="outline" value={[]}>
|
<ToggleGroup type="multiple" variant="outline" value={[]} className="overflow-visible">
|
||||||
{onCreateFolder && (
|
{onCreateFolder && (
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
|
|
@ -90,11 +90,11 @@ export function DocumentsFilters({
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<ToggleGroupItem
|
<ToggleGroupItem
|
||||||
value="filter"
|
value="filter"
|
||||||
className="relative h-9 w-9 shrink-0 border-sidebar-border text-sidebar-foreground/60 hover:text-sidebar-foreground hover:border-sidebar-border bg-sidebar"
|
className="relative h-9 w-9 shrink-0 border-sidebar-border text-sidebar-foreground/60 hover:text-sidebar-foreground hover:border-sidebar-border bg-sidebar overflow-visible"
|
||||||
>
|
>
|
||||||
<ListFilter size={14} />
|
<ListFilter size={14} />
|
||||||
{activeTypes.length > 0 && (
|
{activeTypes.length > 0 && (
|
||||||
<span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[9px] font-medium text-primary-foreground">
|
<span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-sidebar-border text-[9px] font-medium text-sidebar-foreground">
|
||||||
{activeTypes.length}
|
{activeTypes.length}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
@ -167,22 +167,6 @@ export function DocumentsFilters({
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{activeTypes.length > 0 && (
|
|
||||||
<div className="px-3 pt-1.5 pb-1.5 border-t border-border dark:border-neutral-700">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
className="w-full h-7 text-[11px] text-muted-foreground hover:text-foreground hover:bg-neutral-200 dark:hover:bg-neutral-700"
|
|
||||||
onClick={() => {
|
|
||||||
activeTypes.forEach((t) => {
|
|
||||||
onToggleType(t, false);
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Clear filters
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
|
||||||
|
|
@ -96,14 +96,21 @@ export function FolderTreeView({
|
||||||
);
|
);
|
||||||
const handleCancelRename = useCallback(() => setRenamingFolderId(null), [setRenamingFolderId]);
|
const handleCancelRename = useCallback(() => setRenamingFolderId(null), [setRenamingFolderId]);
|
||||||
|
|
||||||
|
const effectiveActiveTypes = useMemo(() => {
|
||||||
|
if (activeTypes.includes("FILE" as DocumentTypeEnum) && !activeTypes.includes("LOCAL_FOLDER_FILE" as DocumentTypeEnum)) {
|
||||||
|
return [...activeTypes, "LOCAL_FOLDER_FILE" as DocumentTypeEnum];
|
||||||
|
}
|
||||||
|
return activeTypes;
|
||||||
|
}, [activeTypes]);
|
||||||
|
|
||||||
const hasDescendantMatch = useMemo(() => {
|
const hasDescendantMatch = useMemo(() => {
|
||||||
if (activeTypes.length === 0 && !searchQuery) return null;
|
if (effectiveActiveTypes.length === 0 && !searchQuery) return null;
|
||||||
const match: Record<number, boolean> = {};
|
const match: Record<number, boolean> = {};
|
||||||
|
|
||||||
function check(folderId: number): boolean {
|
function check(folderId: number): boolean {
|
||||||
if (match[folderId] !== undefined) return match[folderId];
|
if (match[folderId] !== undefined) return match[folderId];
|
||||||
const childDocs = (docsByFolder[folderId] ?? []).some(
|
const childDocs = (docsByFolder[folderId] ?? []).some(
|
||||||
(d) => activeTypes.length === 0 || activeTypes.includes(d.document_type as DocumentTypeEnum)
|
(d) => effectiveActiveTypes.length === 0 || effectiveActiveTypes.includes(d.document_type as DocumentTypeEnum)
|
||||||
);
|
);
|
||||||
if (childDocs) {
|
if (childDocs) {
|
||||||
match[folderId] = true;
|
match[folderId] = true;
|
||||||
|
|
@ -124,7 +131,7 @@ export function FolderTreeView({
|
||||||
check(f.id);
|
check(f.id);
|
||||||
}
|
}
|
||||||
return match;
|
return match;
|
||||||
}, [folders, docsByFolder, foldersByParent, activeTypes, searchQuery]);
|
}, [folders, docsByFolder, foldersByParent, effectiveActiveTypes, searchQuery]);
|
||||||
|
|
||||||
const folderSelectionStates = useMemo(() => {
|
const folderSelectionStates = useMemo(() => {
|
||||||
const states: Record<number, FolderSelectionState> = {};
|
const states: Record<number, FolderSelectionState> = {};
|
||||||
|
|
@ -194,7 +201,7 @@ export function FolderTreeView({
|
||||||
? childFolders.filter((f) => hasDescendantMatch[f.id])
|
? childFolders.filter((f) => hasDescendantMatch[f.id])
|
||||||
: childFolders;
|
: childFolders;
|
||||||
const childDocs = (docsByFolder[key] ?? []).filter(
|
const childDocs = (docsByFolder[key] ?? []).filter(
|
||||||
(d) => activeTypes.length === 0 || activeTypes.includes(d.document_type as DocumentTypeEnum)
|
(d) => effectiveActiveTypes.length === 0 || effectiveActiveTypes.includes(d.document_type as DocumentTypeEnum)
|
||||||
);
|
);
|
||||||
|
|
||||||
const nodes: React.ReactNode[] = [];
|
const nodes: React.ReactNode[] = [];
|
||||||
|
|
@ -278,7 +285,7 @@ export function FolderTreeView({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (treeNodes.length === 0 && (activeTypes.length > 0 || searchQuery)) {
|
if (treeNodes.length === 0 && (effectiveActiveTypes.length > 0 || searchQuery)) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-1 flex-col items-center justify-center gap-3 px-4 py-12 text-muted-foreground">
|
<div className="flex flex-1 flex-col items-center justify-center gap-3 px-4 py-12 text-muted-foreground">
|
||||||
<Search className="h-10 w-10" />
|
<Search className="h-10 w-10" />
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ export function RightPanelExpandButton() {
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={() => startTransition(() => setCollapsed(false))}
|
onClick={() => startTransition(() => setCollapsed(false))}
|
||||||
className="h-7 w-7 shrink-0"
|
className="h-8 w-8 shrink-0 -m-0.5"
|
||||||
>
|
>
|
||||||
<PanelRight className="h-4 w-4" />
|
<PanelRight className="h-4 w-4" />
|
||||||
<span className="sr-only">Expand panel</span>
|
<span className="sr-only">Expand panel</span>
|
||||||
|
|
|
||||||
|
|
@ -531,7 +531,8 @@ export function DocumentsSidebar({
|
||||||
const typeCounts = useMemo(() => {
|
const typeCounts = useMemo(() => {
|
||||||
const counts: Partial<Record<string, number>> = {};
|
const counts: Partial<Record<string, number>> = {};
|
||||||
for (const d of treeDocuments) {
|
for (const d of treeDocuments) {
|
||||||
counts[d.document_type] = (counts[d.document_type] || 0) + 1;
|
const displayType = d.document_type === "LOCAL_FOLDER_FILE" ? "FILE" : d.document_type;
|
||||||
|
counts[displayType] = (counts[displayType] || 0) + 1;
|
||||||
}
|
}
|
||||||
return counts;
|
return counts;
|
||||||
}, [treeDocuments]);
|
}, [treeDocuments]);
|
||||||
|
|
@ -746,7 +747,7 @@ export function DocumentsSidebar({
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 min-h-0 overflow-x-hidden pt-0 flex flex-col">
|
<div className="flex-1 min-h-0 pt-0 flex flex-col">
|
||||||
<div className="px-4 pb-2">
|
<div className="px-4 pb-2">
|
||||||
<DocumentsFilters
|
<DocumentsFilters
|
||||||
typeCounts={typeCounts}
|
typeCounts={typeCounts}
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ export const getConnectorIcon = (connectorType: EnumConnectorName | string, clas
|
||||||
case "DEEPEST":
|
case "DEEPEST":
|
||||||
return <Telescope {...iconProps} />;
|
return <Telescope {...iconProps} />;
|
||||||
case "LOCAL_FOLDER_FILE":
|
case "LOCAL_FOLDER_FILE":
|
||||||
return null;
|
return <File {...iconProps} />;
|
||||||
default:
|
default:
|
||||||
return <Search {...iconProps} />;
|
return <Search {...iconProps} />;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue