lvwerra's picture
lvwerra HF Staff
Polish sidebar creation and terminal headers
cae0460
Raw
History Blame Contribute Delete
3 kB
import { useState } from 'react';
import type { Cli, Session } from '../types';
import Logo from './Logo';
import FolderPicker from './FolderPicker';
const slug = (s: string) => s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
// Next free "<label-slug>-<n>" for this CLI — mirrors the server's nextName so
// the prepopulated value matches what the server would pick anyway.
function defaultName(c: Cli, sessions: Session[]) {
const base = slug(c.label) || c.id;
const re = new RegExp(`^${base}-(\\d+)$`);
let max = 0;
for (const s of sessions) {
const m = s.name.match(re);
if (m) max = Math.max(max, parseInt(m[1], 10));
}
return `${base}-${max + 1}`;
}
// Creation widget for AI agents. Shell and Files are created via the quick-add
// buttons at the bottom of the sidebar instead (rename after creation).
export default function NewSession({
clis, sessions, defaultPath = '.', onCreate, onCancel,
}: {
clis: Cli[];
sessions: Session[];
defaultPath?: string;
onCreate: (name: string, cli: string, path: string) => void;
onCancel?: () => void;
}) {
const agents = clis.filter((c) => c.available && c.id !== 'shell' && c.id !== 'files');
const [cli, setCli] = useState(agents[0]?.id || '');
const [name, setName] = useState(() => (agents[0] ? defaultName(agents[0], sessions) : ''));
// Prepopulated values follow the selected agent until the user types.
const [nameDirty, setNameDirty] = useState(false);
const [loc, setLoc] = useState(defaultPath || '.');
const sel = agents.find((c) => c.id === cli) || agents[0];
const pick = (c: Cli) => {
setCli(c.id);
if (!nameDirty) setName(defaultName(c, sessions));
};
const submit = () => { if (sel) onCreate(name.trim() || sel.label, sel.id, loc || '.'); };
return (
<div className="widget">
<div className="w-field">
<span className="w-label">Agent</span>
<div className="agent-picks">
{agents.map((c) => (
<button
key={c.id}
className={`agent-pick${cli === c.id ? ' on' : ''}`}
onClick={() => pick(c)}
>
<Logo cli={c.id} size={13} />
<span>{c.label}</span>
</button>
))}
</div>
</div>
<div className="w-field">
<span className="w-label">Name</span>
<input
autoFocus
placeholder="Agent name"
value={name}
onChange={(e) => { setName(e.target.value); setNameDirty(e.target.value.trim() !== ''); }}
onKeyDown={(e) => { if (e.key === 'Enter') submit(); if (e.key === 'Escape') onCancel?.(); }}
/>
</div>
<div className="w-field">
<span className="w-label">Folder</span>
<FolderPicker value={loc} onChange={setLoc} />
</div>
<div className="widget-actions">
<button className="btn-primary" onClick={submit} disabled={!sel}>Create</button>
</div>
</div>
);
}