feat(frontend): système de plugins — runtime, menus, layouts custom (#43)
Lots F1-F4 : runtime de chargement/registre plugin, extension des menus existants, panneau de gestion des plugins, types de layout custom (sélecteur, fallback, cellule dédiée) branchés sur le port plugin. Suite npm typecheck/test verte (947/947). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@ -91,6 +91,10 @@ function mapNode(node: LayoutNode, f: (n: LayoutNode) => LayoutNode): LayoutNode
|
||||
case "leaf":
|
||||
rebuilt = node;
|
||||
break;
|
||||
case "customPluginLayout":
|
||||
// No children to recurse into — same leaf-like treatment as "leaf".
|
||||
rebuilt = node;
|
||||
break;
|
||||
case "split":
|
||||
rebuilt = {
|
||||
type: "split",
|
||||
@ -319,6 +323,52 @@ export function droppedSessions(
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locally patches a `customPluginLayout` node's opaque `state` (#43, F4).
|
||||
*
|
||||
* Client-side only: the backend has no `LayoutOperation` variant to persist
|
||||
* plugin layout state yet (carnet v2 §3.5 — no backend refonte expected for
|
||||
* F4), so this does NOT call `LayoutGateway.mutateLayout`. It's the same
|
||||
* "real, in-session, not yet cross-restart-persisted" contract every plugin
|
||||
* component's `setState` gets: the tree re-renders with the new state
|
||||
* immediately, but a reload re-fetches the last **persisted** value from the
|
||||
* backend. Returns `tree` unchanged if no such node is found.
|
||||
*/
|
||||
export function setCustomPluginLayoutState(
|
||||
tree: LayoutTree,
|
||||
nodeId: string,
|
||||
state: unknown,
|
||||
): LayoutTree {
|
||||
return {
|
||||
root: mapNode(tree.root, (n) => {
|
||||
if (n.type === "customPluginLayout" && n.node.id === nodeId) {
|
||||
return { type: "customPluginLayout", node: { ...n.node, state } };
|
||||
}
|
||||
return n;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Locally replaces a `customPluginLayout` node with a blank terminal leaf of
|
||||
* the same id (#43, F4 "Choisir un autre layout" fallback action). Same
|
||||
* client-side-only contract as {@link setCustomPluginLayoutState} — no
|
||||
* backend operation exists to persist the node-kind change yet.
|
||||
*/
|
||||
export function replaceCustomPluginLayoutWithTerminal(
|
||||
tree: LayoutTree,
|
||||
nodeId: string,
|
||||
): LayoutTree {
|
||||
return {
|
||||
root: mapNode(tree.root, (n) => {
|
||||
if (n.type === "customPluginLayout" && n.node.id === nodeId) {
|
||||
return { type: "leaf", node: { id: nodeId } };
|
||||
}
|
||||
return n;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
/** Convenience: builds a `split` operation splitting `target` in `direction`. */
|
||||
export function splitOp(target: string, direction: Direction): LayoutOperation {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user