From cb0e2d2536f5c1aabcd29cc384eb507e138fa225 Mon Sep 17 00:00:00 2001 From: le king fu Date: Sun, 18 Oct 2026 19:24:31 -0400 Subject: [PATCH] fix: reload the category tree even when the check after a reattachment fails (#393) The reattachment is committed before the orphan list is checked again: if that check failed, the tree kept showing the categories as they were. The tree now reloads in a finally block, and the failure shows in the window. Resolves #393 Co-Authored-By: Claude Opus 5.5 --- src/hooks/useCategories.test.ts | 17 +++++++++++++++++ src/hooks/useCategories.ts | 12 ++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/hooks/useCategories.test.ts b/src/hooks/useCategories.test.ts index 33668e4..9791cd4 100644 --- a/src/hooks/useCategories.test.ts +++ b/src/hooks/useCategories.test.ts @@ -172,6 +172,23 @@ describe("useCategories — « Vérifier la hiérarchie » (#393)", () => { expect(state.isSaving).toBe(false); }); + it("reloads the tree even when the check after a committed reattachment fails", async () => { + vi.mocked(findOrphanCategories) + .mockResolvedValueOnce([CYCLE]) + .mockRejectedValueOnce(new Error("database is locked")); + vi.mocked(reattachCategory).mockResolvedValue(2); + let api = await mount(); + await api.checkHierarchy(); + api = harness.render(useCategories); + await api.reattachOrphan(CYCLE, null); + expect(reattachCategory).toHaveBeenCalledWith(3, null); + expect(logInfo).toHaveBeenCalledTimes(1); + expect(getAllCategoriesWithCounts).toHaveBeenCalledTimes(2); + const { state } = harness.render(useCategories); + expect(state.hierarchyCheck?.error).toEqual({ message: "database is locked" }); + expect(state.isSaving).toBe(false); + }); + it("shows a refused reattachment in the window by its translated code, with no Journal line", async () => { vi.mocked(findOrphanCategories).mockResolvedValue([CYCLE]); vi.mocked(reattachCategory).mockRejectedValue(new CategoryHierarchyError("parent_has_transactions")); diff --git a/src/hooks/useCategories.ts b/src/hooks/useCategories.ts index f4c8f6c..711269e 100644 --- a/src/hooks/useCategories.ts +++ b/src/hooks/useCategories.ts @@ -417,7 +417,8 @@ export function useCategories() { /** * Reattaches an orphan under `parentId`, or to the root with `null` (#393). * On success: one Journal line (counts, no name), then the orphan list and - * the tree reload. A refusal shows in the window, by its translated code. + * the tree reload; the tree reloads even if the new check fails, since the + * write is committed. A refusal shows in the window, by its translated code. */ const reattachOrphan = useCallback( async (orphan: OrphanCategory, parentId: number | null) => { @@ -425,9 +426,12 @@ export function useCategories() { try { const restored = await reattachCategory(orphan.id, parentId); logInfo(reattachLogLine(orphan.reason, restored)); - const orphans = await findOrphanCategories(); - dispatch({ type: "SET_ORPHANS", payload: orphans }); - await loadCategories(); + try { + const orphans = await findOrphanCategories(); + dispatch({ type: "SET_ORPHANS", payload: orphans }); + } finally { + await loadCategories(); + } dispatch({ type: "SET_SAVING", payload: false }); } catch (e) { dispatch({ type: "SET_HIERARCHY_ERROR", payload: categoriesErrorOf(e) });