browse the directories of the server the pane is on
Reported from the iPad: MacBook selected, and the directory picker still listed alpha folders. Three layers all defaulted to this origin — useFilesAPI, DirPickerModal and PwdSelector — so the pane pointed one way and the pickers another. Same defect as browseDirectories in the mobile app, found this morning: a path only means something on the machine it came from, and offering another machine folders is worse than offering none, because picking one silently runs the agent somewhere that does not exist. The dir-picker cache is keyed by server too. Without it one machine tree is served from cache under the other name, which looks like the fix not working. Other useFilesAPI callers pass no server and are unchanged — the code editor and the message bubble still read this origin exactly as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,12 +8,14 @@ type DirPickerModalProps = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onSelect: (absPath: string) => void;
|
||||
/** Whose filesystem to browse. Absent = this origin. */
|
||||
serverId?: string | null;
|
||||
};
|
||||
|
||||
// A simplified file-browser modal for picking a working directory (returns an absolute path).
|
||||
// Navigates within the home root; dirs elsewhere are reachable via the selector's free-text field.
|
||||
export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) => {
|
||||
const api = useFilesAPI('home');
|
||||
export const DirPickerModal = ({ open, onClose, onSelect, serverId }: DirPickerModalProps) => {
|
||||
const api = useFilesAPI('home', serverId);
|
||||
const [path, setPath] = useState('/'); // root-relative, always starts with '/'
|
||||
const [creating, setCreating] = useState(false);
|
||||
const [newName, setNewName] = useState('');
|
||||
@@ -23,7 +25,9 @@ export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps)
|
||||
const [showHidden, setShowHidden] = useState(false);
|
||||
|
||||
const { data, isLoading, refetch } = useQuery({
|
||||
queryKey: ['dir-picker', path],
|
||||
// Server in the key: two machines have different trees, and without it one machine's folders
|
||||
// are served from cache under the other's name.
|
||||
queryKey: ['dir-picker', path, serverId ?? null],
|
||||
queryFn: () => api.listDir(path),
|
||||
enabled: open,
|
||||
});
|
||||
|
||||
@@ -6,14 +6,16 @@ import { DirPickerModal } from './DirPickerModal';
|
||||
type PwdSelectorProps = {
|
||||
value: string | null; // null = the default general_chat_sessions dir
|
||||
onChange: (cwd: string | null) => void;
|
||||
/** Which Officer's directories to offer. Absent = this origin. */
|
||||
serverId?: string | null;
|
||||
};
|
||||
|
||||
// A shorter, friendlier label for a working directory.
|
||||
const shorten = (cwd: string) => cwd.replace(/^\/home\/[^/]+/, '~');
|
||||
const basename = (cwd: string) => cwd.split('/').filter(Boolean).pop() ?? cwd;
|
||||
|
||||
export const PwdSelector = ({ value, onChange }: PwdSelectorProps) => {
|
||||
const { pwds, defaultCwd } = useChatPwds();
|
||||
export const PwdSelector = ({ value, onChange, serverId }: PwdSelectorProps) => {
|
||||
const { pwds, defaultCwd } = useChatPwds(serverId);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [browse, setBrowse] = useState(false);
|
||||
const [custom, setCustom] = useState('');
|
||||
@@ -96,7 +98,7 @@ export const PwdSelector = ({ value, onChange }: PwdSelectorProps) => {
|
||||
</>
|
||||
)}
|
||||
|
||||
<DirPickerModal open={browse} onClose={() => setBrowse(false)} onSelect={(p) => pick(p)} />
|
||||
<DirPickerModal open={browse} onClose={() => setBrowse(false)} onSelect={(p) => pick(p)} serverId={serverId} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -95,6 +95,7 @@ export const SessionList = () => {
|
||||
}}
|
||||
/>
|
||||
<PwdSelector
|
||||
serverId={serverId}
|
||||
value={activeCwd}
|
||||
onChange={(cwd) => {
|
||||
setSelected(null); // sessions belong to a cwd — clear the open one when switching
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { useClient, getHeaders } from 'hooks/useClient';
|
||||
import { useServerClient } from 'hooks/useServerClient';
|
||||
|
||||
const API_URL = '/api';
|
||||
|
||||
export const useFilesAPI = (root: string = 'home') => {
|
||||
const client = useClient();
|
||||
/**
|
||||
* `serverId` names another Officer; absent is this origin, which is every existing caller.
|
||||
*
|
||||
* Load-bearing for the chat directory pickers: a path only means something on the machine it came from,
|
||||
* so browsing without it showed THIS server's folders while the pane was pointed at another — the exact
|
||||
* bug the mobile app has with `browseDirectories`.
|
||||
*/
|
||||
export const useFilesAPI = (root: string = 'home', serverId?: string | null) => {
|
||||
const client = useServerClient(serverId);
|
||||
const rootParam = root !== 'home' ? `root=${encodeURIComponent(root)}` : '';
|
||||
const withRoot = (url: string) =>
|
||||
rootParam ? (url.includes('?') ? `${url}&${rootParam}` : `${url}?${rootParam}`) : url;
|
||||
|
||||
Reference in New Issue
Block a user