From 76551d898b6c85121e00f10e32c68d505b2b5c7a Mon Sep 17 00:00:00 2001 From: Claudio Date: Sun, 10 May 2026 22:37:12 +0200 Subject: [PATCH] fix(nextcloud): NULL parent_id on cross-source-root child folders + spinner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix NULLed parent_id only for folders within the SourceRoot being deleted, but folder rows under a *different* SourceRoot whose path nests inside this one (e.g. 'Leóns 1st Year' at .../Taco and Muli - 2024 onward/Leóns 1st Year) still pointed into our delete set. folders_parent_id_fkey kept tripping. Widen the UPDATE to NULL parent_id for any folder whose parent_id is in folder_ids, regardless of source_root_id. UI: trash button on a Nextcloud library now swaps to a spinning Loader2 while the delete is in flight (only the row being deleted — others stay as trash icons but disabled). Title updates to flag that a cascade through every photo + folder can take a few seconds. Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/app/routers/nextcloud.py | 16 ++++++++++------ .../src/components/dialogs/SettingsDialog.tsx | 12 ++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/backend/app/routers/nextcloud.py b/backend/app/routers/nextcloud.py index 1461088..bd53543 100644 --- a/backend/app/routers/nextcloud.py +++ b/backend/app/routers/nextcloud.py @@ -333,14 +333,18 @@ async def delete_nextcloud_source_root( ) ) # Folders have a self-referential parent_id FK with no - # ON DELETE rule. A flat DELETE of the whole subtree trips - # `folders_parent_id_fkey` because postgres checks the - # constraint per row, regardless of insertion / list order. - # NULL the parent_id on every folder we're about to delete - # first so the chain breaks cleanly. + # ON DELETE rule. NULL parent_id on every folder that points + # *into* our delete set — that includes children within this + # source root AND any folder under a different SourceRoot whose + # path happens to nest inside this one (e.g. a 'Leóns 1st Year' + # SourceRoot at `.../Taco and Muli - 2024 onward/Leóns 1st Year` + # has folder rows whose parent_id points at folder rows under + # 'Taco and Muli - 2024 onward'). Without this, deleting the + # outer SourceRoot trips folders_parent_id_fkey from the inner + # SourceRoot's still-live rows. await db.execute( update(Folder) - .where(Folder.id.in_(folder_ids)) + .where(Folder.parent_id.in_(folder_ids)) .values(parent_id=None) ) await db.execute(delete(Folder).where(Folder.id.in_(folder_ids))) diff --git a/frontend/src/components/dialogs/SettingsDialog.tsx b/frontend/src/components/dialogs/SettingsDialog.tsx index 1c7c40e..0ff1c8e 100644 --- a/frontend/src/components/dialogs/SettingsDialog.tsx +++ b/frontend/src/components/dialogs/SettingsDialog.tsx @@ -1594,9 +1594,17 @@ function NextcloudIntegrationCard() { variant="ghost" disabled={removeRoot.isPending} onClick={() => removeRoot.mutate(r.id)} - title="Remove this library" + title={ + removeRoot.isPending && removeRoot.variables === r.id + ? 'Removing — cascades through every photo + folder, may take a few seconds' + : 'Remove this library' + } > - + {removeRoot.isPending && removeRoot.variables === r.id ? ( + + ) : ( + + )} ))}