feat(frontend): persist + restore project library manifest (P2.4 projects)

Saved projects now round-trip their declared library manifest (compile scope):
buildSavePayload includes libraries_json from useLibraryManifestStore; loading a
project restores it (and clears any stale example manifest). Existing projects
load with an empty manifest -> legacy scan-all (unchanged); new saves capture
whatever manifest is active. Pairs with the backend libraries_json column.
This commit is contained in:
David Montero 2026-06-07 00:47:39 +02:00
parent e947f1e600
commit 288ab46521
3 changed files with 15 additions and 0 deletions

View File

@ -3,6 +3,7 @@ import { useParams, useNavigate } from 'react-router-dom';
import { getProjectById } from '../services/projectService'; import { getProjectById } from '../services/projectService';
import { useSimulatorStore } from '../store/useSimulatorStore'; import { useSimulatorStore } from '../store/useSimulatorStore';
import { useProjectStore } from '../store/useProjectStore'; import { useProjectStore } from '../store/useProjectStore';
import { useLibraryManifestStore } from '../store/useLibraryManifestStore';
import { useSEO } from '../utils/useSEO'; import { useSEO } from '../utils/useSEO';
import { EditorPage } from './EditorPage'; import { EditorPage } from './EditorPage';
import type { BoardInstance, BoardKind } from '../types/board'; import type { BoardInstance, BoardKind } from '../types/board';
@ -56,6 +57,14 @@ export const ProjectByIdPage: React.FC = () => {
.then((project) => { .then((project) => {
const payload = buildLoadPayload(project); const payload = buildLoadPayload(project);
loadProjectState(payload); loadProjectState(payload);
// P2.4 — restore the declared library manifest (compile scope), also
// clearing any stale example manifest from before this load.
try {
const libs = JSON.parse(project.libraries_json || '[]');
useLibraryManifestStore.getState().setLibraries(Array.isArray(libs) ? libs : null);
} catch {
useLibraryManifestStore.getState().setLibraries(null);
}
setCurrentProject({ setCurrentProject({
id: project.id, id: project.id,
slug: project.slug, slug: project.slug,

View File

@ -42,6 +42,7 @@ export interface ProjectResponse {
components_json: string; components_json: string;
wires_json: string; wires_json: string;
boards_json: string; // serialized BoardInstance[] boards_json: string; // serialized BoardInstance[]
libraries_json?: string; // P2.4 — declared library manifest (compile scope)
owner_username: string; owner_username: string;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
@ -62,6 +63,7 @@ export interface ProjectSaveData {
components_json: string; components_json: string;
wires_json: string; wires_json: string;
boards_json?: string; // serialized BoardInstance[] boards_json?: string; // serialized BoardInstance[]
libraries_json?: string; // P2.4 — declared library manifest (compile scope)
} }
export async function getMyProjects(): Promise<ProjectResponse[]> { export async function getMyProjects(): Promise<ProjectResponse[]> {

View File

@ -11,6 +11,7 @@ import type { BoardInstance } from '../types/board';
import type { Wire } from '../types/wire'; import type { Wire } from '../types/wire';
import { useEditorStore, chipFileGroupId } from '../store/useEditorStore'; import { useEditorStore, chipFileGroupId } from '../store/useEditorStore';
import { useSimulatorStore } from '../store/useSimulatorStore'; import { useSimulatorStore } from '../store/useSimulatorStore';
import { useLibraryManifestStore } from '../store/useLibraryManifestStore';
/** /**
* Editor groups owned by programmable custom-chips on the canvas (those whose * Editor groups owned by programmable custom-chips on the canvas (those whose
@ -107,6 +108,9 @@ export function buildSavePayload(meta: SnapshotInputs = {}): ProjectSaveData {
components_json: JSON.stringify(sim.components), components_json: JSON.stringify(sim.components),
wires_json: JSON.stringify(sim.wires), wires_json: JSON.stringify(sim.wires),
boards_json: JSON.stringify(sim.boards.map(serialisableBoard)), boards_json: JSON.stringify(sim.boards.map(serialisableBoard)),
// P2.4 — persist the declared library manifest (compile scope) so reloading
// the project re-sends it. Empty when the project declares no libraries.
libraries_json: JSON.stringify(useLibraryManifestStore.getState().libraries ?? []),
}; };
} }