mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
p2 rewritten by the Chord v2 authoring rules (decision "App authoring rules confirmed by the p2 audit"), in four parts merged together: - core: session lifecycle (relocate, clone, fork, archive) and search rebuild are persisted jobs on a new server store; Sessions v6 with client-chosen ids and visible operations; Retry answers with the worker's real outcome; workers push branch, subagent and status state to the server; roots take the method's ctx. - services: models, envs, ports, login, mcp, logs, sharing and voice follow external state (self.follow, followNative) instead of copy loops; methods answer after their state commits; presence from host.references. - chat: chat mode, artifacts and prompt resources follow Durable and native state; shell commands are Chord jobs (shellId is the requestId); status pushed before send and stop answer; race-free draft claim. - ui: optimistic updates on web (useOptimistic) and terminal (TuiScope.optimistic, extended in Chord with a reducer and a pending flag), pending states for long work, visible rollback, load waterfalls removed; merged with the one composer and immediate first send (ccff9876e) and the folder + button (5a31a6d5f). docs/optimistic-ui.md describes the pattern.
79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
import { ChevronIcon, locationLabel, Sheet } from "@p2/app/v1/web";
|
|
import { useState } from "react";
|
|
import type { Session } from "./contract.ts";
|
|
|
|
/** The session's search index rebuild (`Search.rebuilds`): running, failed with why, or none. */
|
|
export type Reindex = { readonly phase: "running" } | { readonly phase: "failed"; readonly error: string } | undefined;
|
|
|
|
export function SessionSheet({
|
|
session,
|
|
onClose,
|
|
onRename,
|
|
onPin,
|
|
onArchive,
|
|
onShare,
|
|
onCwd,
|
|
reindex,
|
|
onReindex,
|
|
}: {
|
|
session: Session;
|
|
onClose: () => void;
|
|
onRename: (title: string) => void;
|
|
onPin: () => void;
|
|
onArchive: () => void;
|
|
onShare: () => void;
|
|
onCwd: () => void;
|
|
reindex: Reindex;
|
|
/** Re-indexes the session's history for search (long work: the row shows it running); absent without search. */
|
|
onReindex: (() => void) | undefined;
|
|
}) {
|
|
const [title, setTitle] = useState(session.title);
|
|
const changed = title.trim() !== "" && title.trim() !== session.title;
|
|
return (
|
|
<Sheet title="Session" onClose={onClose}>
|
|
<form
|
|
className="inline-form"
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
if (changed) onRename(title.trim());
|
|
onClose();
|
|
}}
|
|
>
|
|
<input
|
|
className="input"
|
|
aria-label="Title"
|
|
value={title}
|
|
onChange={(event) => setTitle(event.target.value)}
|
|
/>
|
|
{changed && (
|
|
<button type="submit" className="text-action">
|
|
Save
|
|
</button>
|
|
)}
|
|
</form>
|
|
<div className="list">
|
|
<button type="button" className="row-button" onClick={onShare}>
|
|
<span>Share</span>
|
|
<ChevronIcon />
|
|
</button>
|
|
<button type="button" className="row-button" onClick={onCwd}>
|
|
<span>Working directory</span>
|
|
<small className="row-value mono">{locationLabel(session.env, session.cwd)}</small>
|
|
<ChevronIcon />
|
|
</button>
|
|
<button type="button" className="row-button" onClick={onPin}>
|
|
<span>{session.pinned ? "Unpin" : "Pin to top"}</span>
|
|
</button>
|
|
{onReindex && (
|
|
<button type="button" className="row-button" disabled={reindex?.phase === "running"} onClick={onReindex}>
|
|
<span>{reindex?.phase === "running" ? "Rebuilding search index…" : "Rebuild search index"}</span>
|
|
{reindex?.phase === "failed" && <small className="row-value error">{reindex.error}</small>}
|
|
</button>
|
|
)}
|
|
<button type="button" className="row-button danger" onClick={onArchive}>
|
|
<span>Archive</span>
|
|
</button>
|
|
</div>
|
|
</Sheet>
|
|
);
|
|
}
|