refactor(ui): supprime le popup de reprise par cellule (#177)
Retire la surface utilisateur de reprise par cellule : - supprime ResumeConversationPopup et son test (resumeConversationPopup.test.tsx) - débranche l'appel dans LayoutGrid et retire l'export terminals/index - ajuste les tests dépendants (libellé « Terminé » dans LayoutGrid.chat.test, refitEpoch) - commentaire affiné dans ResumeProjectPanel La reprise implicite éventuelle sera rediscutée ultérieurement (objectif immédiat : retirer la surface). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -22,16 +22,11 @@ import type { Agent, AgentProfile } from "@/domain";
|
||||
import type { LayoutNode } from "@/domain";
|
||||
import type { ProjectWorkState } from "@/domain";
|
||||
import type {
|
||||
ConversationDetails,
|
||||
LiveAgent,
|
||||
OpenTerminalOptions,
|
||||
TerminalHandle,
|
||||
} from "@/ports";
|
||||
import {
|
||||
ResumeConversationPopup,
|
||||
TerminalView,
|
||||
useWritePortal,
|
||||
} from "@/features/terminals";
|
||||
import { TerminalView, useWritePortal } from "@/features/terminals";
|
||||
import { useGateways } from "@/app/di";
|
||||
import { useProjectWorkState } from "@/features/workstate/useProjectWorkState";
|
||||
import {
|
||||
@ -192,7 +187,6 @@ function NodeView({
|
||||
session={node.node.session ?? null}
|
||||
agent={node.node.agent ?? null}
|
||||
conversationId={node.node.conversationId ?? null}
|
||||
agentWasRunning={node.node.agentWasRunning ?? false}
|
||||
cwd={cwd}
|
||||
vm={vm}
|
||||
parentSplit={parentSplit}
|
||||
@ -238,7 +232,6 @@ interface LeafViewProps {
|
||||
session: string | null;
|
||||
agent: string | null;
|
||||
conversationId: string | null;
|
||||
agentWasRunning: boolean;
|
||||
cwd: string;
|
||||
vm: LayoutViewModel;
|
||||
parentSplit: { container: string; index: number; siblings: number } | null;
|
||||
@ -248,19 +241,6 @@ interface LeafViewProps {
|
||||
refitSignal: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A launch deferred by the resume popup (T7): TerminalView asked the opener to
|
||||
* launch (fresh open or reattach-failed fallback) for a cell that carries a
|
||||
* `conversationId`. We hold the open request here until the user picks
|
||||
* Reprendre / Nouvelle conversation, then resolve the promise with the handle.
|
||||
*/
|
||||
interface PendingResume {
|
||||
opts: OpenTerminalOptions;
|
||||
onData: (bytes: Uint8Array) => void;
|
||||
resolve: (handle: TerminalHandle) => void;
|
||||
reject: (e: unknown) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A transient in-cell notice. `goToNodeId`, when present, identifies the layout
|
||||
* leaf that already hosts the conflicting live agent; the notice then renders an
|
||||
@ -355,7 +335,6 @@ function LeafView({
|
||||
session,
|
||||
agent,
|
||||
conversationId,
|
||||
agentWasRunning,
|
||||
cwd,
|
||||
vm,
|
||||
parentSplit,
|
||||
@ -812,15 +791,6 @@ function LeafView({
|
||||
// we never silently relaunch a clone (product rule "1 agent = 1 employé").
|
||||
const [busyNotice, setBusyNotice] = useState<CellNotice | null>(null);
|
||||
|
||||
// ── Resume popup state (T7) ───────────────────────────────────────────────
|
||||
// When an agent cell carries a persisted conversation id and its PTY session
|
||||
// is dead, the opener is about to relaunch in Resume mode. We intercept that
|
||||
// launch with a popup so the user can choose Resume vs a fresh conversation.
|
||||
// The reattach path (live PTY) never goes through this opener, so the popup is
|
||||
// naturally skipped there.
|
||||
const [pendingResume, setPendingResume] = useState<PendingResume | null>(null);
|
||||
const [resumeDetails, setResumeDetails] = useState<ConversationDetails | null>(null);
|
||||
|
||||
// ── Live re-attach on background wake (inter-agent delegation) ─────────────
|
||||
// Bumped to re-key the TerminalView and force a re-attach to the cell's
|
||||
// pinned agent when that agent becomes live in the *background* AFTER this
|
||||
@ -836,8 +806,6 @@ function LeafView({
|
||||
const [attachGen, setAttachGen] = useState(0);
|
||||
useEffect(() => {
|
||||
if (!agentId || !agentGateway?.attachLiveAgent) return;
|
||||
// Mid resume decision: let the popup own the (re)launch — don't race it.
|
||||
if (pendingResume) return;
|
||||
// Only act when the pinned agent is live in ANOTHER (non-visible) cell and
|
||||
// this cell is not already bound to that session. `backgroundLive` is the
|
||||
// same guard `doLaunch` and the dropdown use; crucially it ignores a session
|
||||
@ -913,52 +881,9 @@ function LeafView({
|
||||
|
||||
const terminalOpener = agentGateway && agentId
|
||||
? (opts: OpenTerminalOptions, onData: (bytes: Uint8Array) => void): Promise<TerminalHandle> => {
|
||||
// No persisted conversation ⇒ fresh cell: open straight away (the launch
|
||||
// may assign a new id). No popup on this path.
|
||||
if (!conversationId) {
|
||||
return doLaunch(opts, onData, undefined);
|
||||
}
|
||||
// If the cell was closed/remounted while the agent was running, resume
|
||||
// silently. Layout/project changes must not interrupt an ongoing turn
|
||||
// with a modal choice; the persisted conversation id is the continuity
|
||||
// signal and `agentWasRunning` tells us this was not an intentional stop.
|
||||
if (agentWasRunning) {
|
||||
return doLaunch(opts, onData, conversationId);
|
||||
}
|
||||
// Resume case: defer the launch behind the popup. Fetch the best-effort
|
||||
// enriched details (last topic + tokens) to enrich it; failure or empty
|
||||
// ⇒ degraded mode (status only). Inspection never blocks the resume.
|
||||
Promise.resolve(
|
||||
agentGateway.inspectConversation?.(projectId, agentId, conversationId),
|
||||
)
|
||||
.then((details) => setResumeDetails(details ?? {}))
|
||||
.catch(() => setResumeDetails({}));
|
||||
return new Promise<TerminalHandle>((resolve, reject) => {
|
||||
setPendingResume({ opts, onData, resolve, reject });
|
||||
});
|
||||
return doLaunch(opts, onData, conversationId ?? undefined);
|
||||
}
|
||||
: undefined;
|
||||
|
||||
/** "Reprendre" → launch resuming the existing conversation id. */
|
||||
const onResume = () => {
|
||||
const p = pendingResume;
|
||||
if (!p) return;
|
||||
setPendingResume(null);
|
||||
setResumeDetails(null);
|
||||
doLaunch(p.opts, p.onData, conversationId ?? undefined).then(p.resolve, p.reject);
|
||||
};
|
||||
|
||||
/** "Nouvelle conversation" → clear the id first (Assign), then launch fresh. */
|
||||
const onNewConversation = () => {
|
||||
const p = pendingResume;
|
||||
if (!p) return;
|
||||
setPendingResume(null);
|
||||
setResumeDetails(null);
|
||||
// Clear the persisted conversation id BEFORE launching so the backend treats
|
||||
// it as a fresh cell and assigns a new conversation.
|
||||
void vm.setCellConversation(id, null);
|
||||
doLaunch(p.opts, p.onData, undefined).then(p.resolve, p.reject);
|
||||
};
|
||||
// Agent cells re-attach through the agent gateway; plain cells fall back to
|
||||
// the terminal gateway's reattach (handled by TerminalView's default).
|
||||
const reattachOpener = agentGateway && agentId
|
||||
@ -1639,14 +1564,6 @@ function LeafView({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{pendingResume && (
|
||||
<ResumeConversationPopup
|
||||
agentWasRunning={agentWasRunning}
|
||||
details={resumeDetails}
|
||||
onResume={onResume}
|
||||
onNewConversation={onNewConversation}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user