Skip to content

Disable Skip button while a sort is in progress

jedmund requested to merge jedmund/block-skip-on-sort into main

Summary

A user reported data loss after hitting Skip on the random page while a sort was mid-move: the source folder was gone but the destination was incomplete.

The Skip button on src/routes/random/+page.svelte was only disabled while $isLoading (random-album-fetch state) was true — it had no visibility into whether a sort was in flight. SortForm.handleSort()'s isSortLoading was local component state, so when Skip loaded a new album the previous SortForm unmounted and any in-flight sort became invisible to the UI (the server-side executeSort keeps running regardless — Node doesn't abort on client disconnect).

This change lifts sort-in-progress state into a shared Svelte store so the Skip button can gate on it.

Changes

  • src/lib/stores/albums.ts — add isSorting writable store next to isLoading.
  • src/lib/components/SortForm.sveltehandleSort() sets isSorting true on entry and false in finally, around the fetch('/api/preview?action=execute') call that runs executeSort (cp → verify → rm) in sorter.ts.
  • src/routes/random/+page.svelte — Skip button is now disabled={$isLoading || $isSorting} and shows "Sorting..." while a sort is running.

Out of scope (follow-ups)

  • The copy→rm sequence in src/lib/server/services/sorter.ts:214-234 is still non-atomic. The file-count check at 217-230 is the only guard before rm(originalPath) at 234; if cp silently under-copies over NFS and getDirectoryStats doesn't notice, data loss is still possible even without Skip.
  • If a sort fails after the user has already moved to a new album, the error toast is lost with the unmounted SortForm. A global toast or a persistent sort-activity indicator would fix that.

Test plan

  • pnpm run build passes.
  • Open /random, click Sort on a small album → Skip is disabled and reads "Sorting..." for the duration of the request, then re-enables.
  • With an artificially slowed executeSort (temporary await delay(5000) before fs.promises.cp), Skip remains disabled for the full duration.
  • Skip still behaves normally when no sort is active.

Merge request reports

Loading