import { useEffect, useState } from 'react';
import * as api from '../api';
import { FolderGlyph } from './icons';
const join = (a: string, b: string) => (a ? `${a}/${b}` : b);
const ROOT = '.';
const isRoot = (p: string) => p === '' || p === ROOT;
// Folder names are typed freely; just strip separators and traversal.
const cleanName = (s: string) => s.replace(/[/\\]/g, '').replace(/\.\./g, '').trim();
// Inline "+ new folder" row shown at the end of every level, so a fresh
// subfolder anywhere in the tree is one click + type away.
function NewFolderRow({ base, depth, onPick }: {
base: string; depth: number; onPick: (p: string) => void;
}) {
const [adding, setAdding] = useState(false);
const [name, setName] = useState('');
const commit = () => {
const n = cleanName(name);
if (n) onPick(join(base, n));
setAdding(false); setName('');
};
if (!adding) {
return (
);
}
return (
setName(e.target.value)}
onBlur={commit}
onKeyDown={(e) => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') { setAdding(false); setName(''); } }}
/>
);
}
// One level of the workspace folder tree: click a name to pick it as the
// location, click the caret to expand its subfolders.
function Level({ path, depth, value, onPick }: {
path: string; depth: number; value: string; onPick: (p: string) => void;
}) {
const [folders, setFolders] = useState(null);
const [open, setOpen] = useState>(new Set());
useEffect(() => {
let alive = true;
api.listFolders(path).then((r) => { if (alive) setFolders(r.folders); }).catch(() => { if (alive) setFolders([]); });
return () => { alive = false; };
}, [path]);
if (!folders) return …
;
return (
<>
{folders.map((f) => {
const p = join(path, f);
const expanded = open.has(f);
return (
{expanded &&
}
);
})}
>
);
}
/**
* Workspace location picker. `value` is a workspace-relative path; '.' is the
* workspace root. Picking a not-yet-existing folder is fine: the server
* creates it when the agent is created.
*/
export default function FolderPicker({ value, onChange }: {
value: string;
onChange: (p: string) => void;
}) {
const [open, setOpen] = useState(false);
const root = isRoot(value);
return (
{open && (
{ onChange(p); }} />
)}
);
}