feat(status-ui): improve concurrent session workflows

Add in-place session renewal, searchable model selection, clearer progress feedback, tool-result previews, and per-session presentation state.

Keep commands, errors, loading, and lifecycle indicators attached to their owning runtime so parallel tabs cannot interfere.
This commit is contained in:
2026-08-25 14:56:42 +02:00
parent 9f2c840ae7
commit 166b065ad4
20 changed files with 2211 additions and 430 deletions
+23 -12
View File
@@ -3,9 +3,8 @@ import type { RpcCommand, RpcField } from "../commands/rpc";
const controls = (container: HTMLElement | null) =>
Array.from(
container?.querySelectorAll<HTMLElement>(
"button, input, select, textarea",
) ?? [],
container?.querySelectorAll<HTMLElement>("button, input, select, textarea") ??
[],
).filter((node) => !node.hasAttribute("disabled"));
function valueFor(field: RpcField, value: string | boolean): unknown {
@@ -19,23 +18,25 @@ export function CommandFormDialog({
command,
onSubmit,
onCancel,
pending = false,
commandError,
}: {
command?: RpcCommand;
onSubmit: (input: Record<string, unknown>) => void;
onCancel: () => void;
pending?: boolean;
commandError?: string;
}) {
const ref = useRef<HTMLElement>(null);
const opener = useRef<HTMLElement | null>(null);
const [values, setValues] = useState<Record<string, string | boolean>>({});
const [error, setError] = useState<string>();
const [validationError, setValidationError] = useState<string>();
useEffect(() => {
if (!command) return;
opener.current = document.activeElement as HTMLElement | null;
setValues({});
setError(undefined);
const frame = requestAnimationFrame(() =>
controls(ref.current)[0]?.focus(),
);
setValidationError(undefined);
const frame = requestAnimationFrame(() => controls(ref.current)[0]?.focus());
return () => {
cancelAnimationFrame(frame);
opener.current?.focus();
@@ -44,6 +45,7 @@ export function CommandFormDialog({
if (!command) return null;
const fields = command.input ?? [];
const submit = () => {
if (pending) return;
try {
const input: Record<string, unknown> = {};
for (const field of fields) {
@@ -57,7 +59,7 @@ export function CommandFormDialog({
}
onSubmit(input);
} catch (cause) {
setError(cause instanceof Error ? cause.message : "Invalid input");
setValidationError(cause instanceof Error ? cause.message : "Invalid input");
}
};
return (
@@ -68,6 +70,7 @@ export function CommandFormDialog({
role="dialog"
aria-modal="true"
aria-labelledby="command-form-title"
aria-busy={pending}
onKeyDown={(event) => {
if (event.key === "Escape") {
event.preventDefault();
@@ -99,6 +102,7 @@ export function CommandFormDialog({
aria-label={field.label}
type="checkbox"
checked={values[field.name] === true}
disabled={pending}
onChange={(event) =>
setValues({
...values,
@@ -110,6 +114,7 @@ export function CommandFormDialog({
<select
aria-label={field.label}
value={(values[field.name] as string) ?? ""}
disabled={pending}
onChange={(event) =>
setValues({
...values,
@@ -126,6 +131,7 @@ export function CommandFormDialog({
<textarea
aria-label={field.label}
value={(values[field.name] as string) ?? ""}
disabled={pending}
onChange={(event) =>
setValues({
...values,
@@ -137,6 +143,7 @@ export function CommandFormDialog({
<input
aria-label={field.label}
value={(values[field.name] as string) ?? ""}
disabled={pending}
onChange={(event) =>
setValues({
...values,
@@ -147,10 +154,14 @@ export function CommandFormDialog({
)}
</label>
))}
{error && <p role="alert">{error}</p>}
{(validationError || commandError) && (
<p role="alert">{validationError || commandError}</p>
)}
<div className="extension-options">
<button onClick={submit}>Run command</button>
<button className="quiet" onClick={onCancel}>
<button disabled={pending} onClick={submit}>
{pending ? "Running…" : "Run command"}
</button>
<button className="quiet" disabled={pending} onClick={onCancel}>
Cancel
</button>
</div>