Serialize toolbox writes and preserve concurrent edits
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s
This commit is contained in:
parent
7521d50626
commit
a4cf633ab4
12 changed files with 381 additions and 320 deletions
|
|
@ -46,41 +46,53 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
|
|||
]
|
||||
};
|
||||
if (options.tutorial === true) toolbox.tutorial = true;
|
||||
if (!store.setToolboxes([toolbox, ...store.toolboxes])) return null;
|
||||
store.updateModuleData(toolbox.id, memosModuleId, { items: [{ id: uid("memo"), text: welcomeText, color: "#f6c453", updatedAt: now }] }, "memos");
|
||||
store.updateModuleData(toolbox.id, linksModuleId, { links: [libraryLink] }, "links");
|
||||
if (gameId) store.setLinks({ ...store.links, [gameId]: toolbox.id });
|
||||
const memos = compactModuleDataForStorage("memos", { items: [{ id: uid("memo"), text: welcomeText, color: "#f6c453", updatedAt: now }] });
|
||||
const links = compactModuleDataForStorage("links", { links: [libraryLink] });
|
||||
void store.persistToolboxSnapshot((current) => ({
|
||||
toolboxes: [toolbox, ...current.toolboxes],
|
||||
links: gameId ? { ...current.links, [gameId]: toolbox.id } : current.links,
|
||||
moduleData: {
|
||||
...current.moduleData,
|
||||
[globalModuleKey(toolbox.id, memosModuleId)]: memos,
|
||||
[globalModuleKey(toolbox.id, linksModuleId)]: links
|
||||
}
|
||||
}));
|
||||
return toolbox;
|
||||
}
|
||||
|
||||
function updateToolbox(nextToolbox) {
|
||||
store.setToolboxes(store.toolboxes.map((toolbox) => toolbox.id === nextToolbox.id
|
||||
? { ...nextToolbox, updatedAt: new Date().toISOString() }
|
||||
const updatedAt = new Date().toISOString();
|
||||
store.setToolboxes((toolboxes) => toolboxes.map((toolbox) => toolbox.id === nextToolbox.id
|
||||
? { ...nextToolbox, updatedAt }
|
||||
: toolbox));
|
||||
}
|
||||
|
||||
function deleteToolbox(id) {
|
||||
const toolbox = store.toolboxes.find((item) => item.id === id);
|
||||
const nextToolboxes = store.toolboxes.filter((item) => item.id !== id);
|
||||
const nextModuleData = { ...store.moduleData };
|
||||
(toolbox?.modules || []).forEach((module) => delete nextModuleData[`${id}:${module.id}`]);
|
||||
const nextLinks = { ...store.links };
|
||||
Object.entries(nextLinks).forEach(([gameId, toolboxId]) => {
|
||||
if (toolboxId === id) delete nextLinks[gameId];
|
||||
return store.persistToolboxSnapshot((current) => {
|
||||
const toolbox = current.toolboxes.find((item) => item.id === id);
|
||||
const moduleData = { ...current.moduleData };
|
||||
(toolbox?.modules || []).forEach((module) => delete moduleData[`${id}:${module.id}`]);
|
||||
return {
|
||||
toolboxes: current.toolboxes.filter((item) => item.id !== id),
|
||||
moduleData,
|
||||
links: Object.fromEntries(Object.entries(current.links).filter(([, toolboxId]) => toolboxId !== id))
|
||||
};
|
||||
});
|
||||
return store.persistToolboxSnapshot(nextToolboxes, nextLinks, nextModuleData);
|
||||
}
|
||||
|
||||
function linkToolboxToGame(gameId, toolboxId) {
|
||||
const previousToolboxId = store.links[gameId] || "";
|
||||
const nextLinks = { ...store.links };
|
||||
if (toolboxId) nextLinks[gameId] = toolboxId;
|
||||
else delete nextLinks[gameId];
|
||||
store.setLinks(nextLinks);
|
||||
const touched = new Set([previousToolboxId, toolboxId].filter(Boolean));
|
||||
store.setToolboxes(store.toolboxes.map((toolbox) => touched.has(toolbox.id)
|
||||
? { ...toolbox, updatedAt: new Date().toISOString() }
|
||||
: toolbox));
|
||||
const updatedAt = new Date().toISOString();
|
||||
return store.persistToolboxSnapshot((current) => {
|
||||
const links = { ...current.links };
|
||||
const touched = new Set([links[gameId], toolboxId].filter(Boolean));
|
||||
if (toolboxId) links[gameId] = toolboxId;
|
||||
else delete links[gameId];
|
||||
return {
|
||||
...current,
|
||||
links,
|
||||
toolboxes: current.toolboxes.map((toolbox) => touched.has(toolbox.id) ? { ...toolbox, updatedAt } : toolbox)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function addImageFiles(toolboxId, moduleId, files) {
|
||||
|
|
@ -125,8 +137,9 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
|
|||
confirmLabel: "Créer",
|
||||
onResolve: (confirmed) => {
|
||||
if (!confirmed) return;
|
||||
store.setToolboxes(store.toolboxes.map((item) => item.id === toolboxId
|
||||
? { ...item, modules: [...item.modules, { id: moduleId, type: "checklist", title: list.title || "Checklist" }], updatedAt: new Date().toISOString() }
|
||||
const updatedAt = new Date().toISOString();
|
||||
store.setToolboxes((toolboxes) => toolboxes.map((item) => item.id === toolboxId
|
||||
? { ...item, modules: [...item.modules, { id: moduleId, type: "checklist", title: list.title || "Checklist" }], updatedAt }
|
||||
: item));
|
||||
store.updateModuleData(toolboxId, moduleId, { sections }, "checklist");
|
||||
notify("Checklist créée dans la toolbox associée.");
|
||||
|
|
@ -147,7 +160,7 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
|
|||
});
|
||||
imported.moduleOrder = remapModuleOrderIds(imported.moduleOrder, moduleIdMap);
|
||||
const normalizedImport = normalizeToolbox(imported);
|
||||
const nextModuleData = { ...store.moduleData };
|
||||
const nextModuleData = {};
|
||||
Object.entries(payload.modules || {}).forEach(([oldId, data]) => {
|
||||
const nextId = moduleIdMap.get(oldId);
|
||||
const module = normalizedImport.modules.find((item) => item.id === nextId);
|
||||
|
|
@ -156,9 +169,11 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
|
|||
if (compact) nextModuleData[`${normalizedImport.id}:${nextId}`] = compact;
|
||||
}
|
||||
});
|
||||
const nextLinks = { ...store.links };
|
||||
if (gameId) nextLinks[gameId] = normalizedImport.id;
|
||||
const saved = await store.persistToolboxSnapshot([normalizedImport, ...store.toolboxes], nextLinks, nextModuleData);
|
||||
const saved = await store.persistToolboxSnapshot((current) => ({
|
||||
toolboxes: [normalizedImport, ...current.toolboxes],
|
||||
links: gameId ? { ...current.links, [gameId]: normalizedImport.id } : current.links,
|
||||
moduleData: { ...current.moduleData, ...nextModuleData }
|
||||
}));
|
||||
if (!saved) return null;
|
||||
return normalizedImport;
|
||||
}
|
||||
|
|
@ -183,12 +198,12 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
|
|||
const moduleOrder = remapModuleOrderIds(toolbox.moduleOrder, localModuleIdMap);
|
||||
return normalizeToolbox({ ...toolbox, id: nextToolboxId, name: `${toolbox.name || "Toolbox"} (import)`, modules, moduleOrder, updatedAt: new Date().toISOString() });
|
||||
});
|
||||
const nextLinks = { ...store.links };
|
||||
const nextLinks = {};
|
||||
Object.entries(payload.links || {}).forEach(([gameId, oldToolboxId]) => {
|
||||
const nextToolboxId = toolboxIdMap.get(oldToolboxId);
|
||||
if (nextToolboxId) nextLinks[gameId] = nextToolboxId;
|
||||
});
|
||||
const nextModuleData = { ...store.moduleData };
|
||||
const nextModuleData = {};
|
||||
Object.entries(payload.modules).forEach(([key, data]) => {
|
||||
const [oldToolboxId] = key.split(":");
|
||||
const nextToolboxId = toolboxIdMap.get(oldToolboxId);
|
||||
|
|
@ -198,7 +213,11 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
|
|||
const compact = compactModuleDataForStorage(module?.type, data);
|
||||
if (nextToolboxId && nextModuleId && compact) nextModuleData[`${nextToolboxId}:${nextModuleId}`] = compact;
|
||||
});
|
||||
const saved = await store.persistToolboxSnapshot([...importedToolboxes, ...store.toolboxes], nextLinks, nextModuleData);
|
||||
const saved = await store.persistToolboxSnapshot((current) => ({
|
||||
toolboxes: [...importedToolboxes, ...current.toolboxes],
|
||||
links: { ...current.links, ...nextLinks },
|
||||
moduleData: { ...current.moduleData, ...nextModuleData }
|
||||
}));
|
||||
if (!saved) throw new Error("Impossible d'enregistrer l'import global.");
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +238,7 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
|
|||
updateModuleData: store.updateModuleData,
|
||||
updateToolboxOrder: (orderedIds) => {
|
||||
const order = new Map(orderedIds.map((id, index) => [id, index]));
|
||||
store.setToolboxes([...store.toolboxes].sort((a, b) => (order.get(a.id) ?? 9999) - (order.get(b.id) ?? 9999)));
|
||||
store.setToolboxes((toolboxes) => [...toolboxes].sort((a, b) => (order.get(a.id) ?? 9999) - (order.get(b.id) ?? 9999)));
|
||||
},
|
||||
importToolbox: async (file, gameId = "") => {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue