fix(frontend): la conversation survit au redemarrage agent et a l'aller-retour projet — #291 (ProjectsView/WebWorkspace conservent le pointeur viewerConversation mais ne rendent le viewer que si sa conversation appartient au projet actif: le projet intermediaire affiche sa propre surface sans fuite, le retour au projet source remonte la vue avec la meme cle project/conversation et relit le transcript persiste; useConversationThread ne vide plus le buffer au changement de conversation cible, un contenu deja visible reste affiche pendant relecture ou echec; l'erreur de lecture devient "Impossible de recharger la conversation." avec bouton Reessayer branchant refreshTail sans retirer les tours visibles; QA verte reconfirmee par Git: ProjectsView.ls7 scenario "rehydrates the same conversation" (restart agent, switch alpha->beta->alpha, deux readPage identiques sur {projectId, conversationId}), ConversationViewer + useConversationThread 19/19, npm run build, git diff --check; reserves hors perimetre preexistantes: 3 echecs historiques ProjectsView.ls7 (helper panneau Work/open conversation) + 1 echec WebDesktopWorkspace (libelle anglais Project context); validation runtime AppImage/live restante; aucun push)
This commit is contained in:
@ -4,7 +4,7 @@
|
||||
* states, scroll-up "load older" trigger, and the back button (`onClose`).
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { render, screen, fireEvent, within } from "@testing-library/react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { DIProvider } from "@/app/di";
|
||||
@ -256,7 +256,12 @@ describe("ConversationViewer", () => {
|
||||
};
|
||||
renderViewer({ conversation: failing });
|
||||
const alert = await screen.findByRole("alert");
|
||||
expect(alert.textContent).toContain("lecture impossible");
|
||||
expect(alert.textContent).toContain(
|
||||
"Impossible de recharger la conversation.",
|
||||
);
|
||||
expect(
|
||||
within(alert).getByRole("button", { name: "Réessayer" }),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it("offers a 'load older' control when more turns exist and triggers loadOlder", async () => {
|
||||
|
||||
@ -288,12 +288,20 @@ export function ConversationViewer({
|
||||
|
||||
{/* ── Error ── */}
|
||||
{vm.error && (
|
||||
<p
|
||||
<div
|
||||
role="alert"
|
||||
className="mx-4 mt-2 shrink-0 rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-sm text-danger"
|
||||
className="mx-4 mt-2 flex shrink-0 items-center justify-between gap-3 rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-sm text-danger"
|
||||
>
|
||||
{vm.error}
|
||||
</p>
|
||||
<span>Impossible de recharger la conversation.</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => void vm.refreshTail()}
|
||||
loading={vm.busy}
|
||||
>
|
||||
Réessayer
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Thread ── */}
|
||||
|
||||
@ -151,10 +151,9 @@ export function useConversationThread(
|
||||
|
||||
// (Re)open whenever the target conversation changes.
|
||||
useEffect(() => {
|
||||
setBuffer([]);
|
||||
setHasMore(false);
|
||||
void open();
|
||||
}, [open, setBuffer]);
|
||||
}, [open]);
|
||||
|
||||
return { turns, busy, error, hasMore, loadOlder, refreshTail };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user