From 928eaebe2cb800469a052862b86aa8866b24de68 Mon Sep 17 00:00:00 2001 From: Andre Padez Date: Mon, 10 Aug 2026 01:38:08 +0100 Subject: [PATCH] hide dot-directories in the folder picker, with a toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file-browser API does not filter them — readdir returns everything — so browsing for a working directory opened onto .cache, .local, .npm and thirty more before anything worth picking. Hidden by default, one toggle in the footer to reveal, and shown dimmed when revealed so they read as a different class of thing. The count sits on the toggle and the empty state names it too: a folder holding only dot-directories used to say 'No subfolders here', which is a lie with no way to notice it. Co-Authored-By: Claude Opus 5 --- .../src/apps/ChatHistory/DirPickerModal.tsx | 48 ++++++++++++++----- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx b/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx index bf60bd70..01b92e60 100644 --- a/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx +++ b/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; -import { Folder, ChevronRight, Loader2, FolderPlus, Check } from 'lucide-react'; +import { Folder, ChevronRight, Loader2, FolderPlus, Check, Eye, EyeOff } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { useFilesAPI, type DirEntry } from '../../hooks/useFilesAPI'; @@ -17,6 +17,10 @@ export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) const [path, setPath] = useState('/'); // root-relative, always starts with '/' const [creating, setCreating] = useState(false); const [newName, setNewName] = useState(''); + // Off by default. The server does not filter these — `readdir` returns everything — so a home + // directory opened straight onto `.cache`, `.local`, `.npm` and thirty more before anything you + // recognise. They are still reachable, just not in the way by default. + const [showHidden, setShowHidden] = useState(false); const { data, isLoading, refetch } = useQuery({ queryKey: ['dir-picker', path], @@ -25,9 +29,11 @@ export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) }); const rootDir = data?.rootDir ?? ''; - const dirs = ((data?.entries ?? []) as DirEntry[]) + const allDirs = ((data?.entries ?? []) as DirEntry[]) .filter((e) => e.type === 'directory') .sort((a, b) => a.name.localeCompare(b.name)); + const hiddenCount = allDirs.filter((d) => d.name.startsWith('.')).length; + const dirs = showHidden ? allDirs : allDirs.filter((d) => !d.name.startsWith('.')); const absCurrent = path === '/' ? rootDir : `${rootDir}${path}`; const segments = path.split('/').filter(Boolean); @@ -72,7 +78,13 @@ export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) ) : dirs.length === 0 ? ( -
No subfolders here
+ // Say when the folder isn't actually empty, just filtered — "No subfolders here" over a + // directory holding thirty dot-folders is a lie the toggle below can't help you spot. +
+ {hiddenCount > 0 + ? `No visible subfolders — ${hiddenCount} hidden ${hiddenCount === 1 ? 'one is' : 'ones are'} filtered out` + : 'No subfolders here'} +
) : ( dirs.map((d) => ( )) )} @@ -110,12 +124,24 @@ export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) ) : ( - +
+ + {/* Shown even at zero, so the control's state is always legible: a folder with nothing + hidden and one with everything hidden must not look identical. */} + +
)}