Persist capture data per session (field values, schema, links)

Capture mode state lived only in React memory and was lost when
reopening a session or remounting EngineProvider.

- Add per-session localStorage capture snapshot (schema, values, links)
- Restore on session mount; persist on field/schema/link changes
- Seed binder links from storage without spurious bus events
- Clean up capture key when session is deleted
- Integration test for reload persistence
This commit is contained in:
2026-06-08 01:23:48 +02:00
parent ba34ba868f
commit b28feaad42
8 changed files with 437 additions and 9 deletions

View File

@@ -20,6 +20,8 @@ import {
type ReactNode,
} from "react";
import type { EvidenceLink } from "@shared/evidence-link";
import type { EventBus } from "@engine/events";
import {
@@ -68,9 +70,20 @@ export interface BinderProviderProps {
* because its observers attach to the current `window`.
*/
readonly services?: Omit<BinderServices, "rect">;
/**
* Restored evidence links for this session. Seeded directly into the
* repo (no bus events) so reload does not spuriously re-emit
* `EvidenceLinkCreated`.
*/
readonly initialLinks?: readonly EvidenceLink[];
}
export function BinderProvider({ children, bus, services }: BinderProviderProps) {
export function BinderProvider({
children,
bus,
services,
initialLinks,
}: BinderProviderProps) {
const built = useMemo<BinderServices>(() => {
const links = services?.links ?? createInMemoryLinkRepo();
const bindings = services?.bindings ?? createBindingService(links, bus);
@@ -78,6 +91,15 @@ export function BinderProvider({ children, bus, services }: BinderProviderProps)
return { links, bindings, rect };
}, [bus, services]);
useEffect(() => {
if (!initialLinks?.length || services?.links) return;
for (const link of initialLinks) {
if (!built.links.get(link.id)) {
built.links.create(link);
}
}
}, [built.links, initialLinks, services?.links]);
// Disconnect rect observers + listeners on unmount.
useEffect(() => {
return () => {