From 272356a3bf407295110a933f318a561d4060d132 Mon Sep 17 00:00:00 2001 From: Chris0Jeky Date: Sun, 29 Mar 2026 22:43:02 +0100 Subject: [PATCH 1/4] Fix archive board freeze by navigating before clearing state Navigate to /boards before calling boardStore.deleteBoard so the BoardView is unmounted and its reactive subscriptions (sortedColumns, cardsByColumn, filter computeds) are torn down before the sequential state mutations fire. This eliminates the ~30-second browser freeze caused by cascading re-renders while the view was still mounted. Add loading state to the lifecycle action button to provide immediate feedback and prevent double-clicks. Fixes #519 --- .../components/board/BoardSettingsModal.vue | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/frontend/taskdeck-web/src/components/board/BoardSettingsModal.vue b/frontend/taskdeck-web/src/components/board/BoardSettingsModal.vue index 519641f7e..813e7ff3b 100644 --- a/frontend/taskdeck-web/src/components/board/BoardSettingsModal.vue +++ b/frontend/taskdeck-web/src/components/board/BoardSettingsModal.vue @@ -21,6 +21,7 @@ const router = useRouter() // Form state const name = ref('') const description = ref('') +const lifecycleActionInProgress = ref(false) // Watch for board changes watch(() => props.board, (newBoard) => { @@ -30,9 +31,12 @@ watch(() => props.board, (newBoard) => { } }, { immediate: true }) -const lifecycleActionLabel = computed(() => ( - props.board.isArchived ? 'Restore Board' : 'Move to Archive' -)) +const lifecycleActionLabel = computed(() => { + if (lifecycleActionInProgress.value) { + return props.board.isArchived ? 'Restoring...' : 'Archiving...' + } + return props.board.isArchived ? 'Restore Board' : 'Move to Archive' +}) const lifecycleActionButtonClass = computed(() => ( props.board.isArchived @@ -80,21 +84,31 @@ async function handleLifecycleTransition() { return } + lifecycleActionInProgress.value = true + try { if (shouldArchive) { + // Navigate away BEFORE clearing board state to prevent the mounted + // BoardView from re-rendering every computed (columns, cards, filters) + // as each piece of state is set to null/empty. This was the root cause + // of the ~30-second freeze reported in #519 — sequential reactive + // mutations cascaded through dozens of watchers while the view was + // still mounted. + emit('updated') + emit('close') + await router.push('/boards') + + // Run the store mutation after navigation so the old BoardView is + // already unmounted and its reactive subscriptions are torn down. await boardStore.deleteBoard(props.board.id) } else { await boardStore.updateBoard(props.board.id, { isArchived: false }) - } - - emit('updated') - emit('close') - - if (shouldArchive) { - router.push('/boards') + emit('updated') + emit('close') } } catch (error) { console.error('Failed to update board lifecycle state:', error) + lifecycleActionInProgress.value = false } } @@ -188,6 +202,7 @@ useEscapeToClose(() => props.isOpen, handleClose)