Standardized status messages, foreground progress dialogs, and N+1 fixes (0.9.0) #180

Merged
ValleyGeek merged 16 commits from 0.8.0/dupe-compare-progress into main 2026-08-26 05:24:55 +00:00
Member

Summary

  • Added core/status_message.py: a single standard for every long-running action's status text — {action} [Stage n/total name]: {count}/{total} (rate unit/s; M:SS remain) {item_name}, with a 10-second rolling-average rate. Dialogs render it as up to three lines (action/stage, count/rate/ETA, item name); the status bar keeps the single-line form.
  • Applied the standard to the perceptual duplicate scan (added progress reporting to the previously-silent hash-comparison stage), the directory-open scan (relabeled into three stages: Scanning Directory, Updating Database, Generating Thumbnails), subdirectory tag creation, and Sort into Folders.
  • Converted four previously-silent or background-only operations into modal dialogs shown before their work starts, each with a progress bar and (except the closing-side share sync) a Cancel button:
    • NetworkHydrateDialog — cache pull on directory open.
    • NetworkSyncDialog — cache push on close/switch/exit (no cancel — interrupting a share write mid-copy could corrupt it).
    • SubdirTagBuildDialog — "Create Tags from Sub-directories," now shown before planning starts instead of after.
    • SortIntoFoldersDialog — rebuilt around a loading/content stack so the preview-building step shows progress in the same dialog that then displays the result; toggling multi-tag directories re-triggers the loading step.
  • Fixed a full-repo audit's worth of N+1 query loops causing silent multi-second-to-minutes hangs on large workspaces: subdirectory tag planning/apply, the post-hydrate grid preload, Sort into Folders' eligible-image lookup, duplicate-group bulk actions, and network share metadata import.
  • Fixed two Qt UI bugs found via real-world testing: switching directly between two network shares now shows both the closing-share sync dialog and the new share's loading dialog (previously the second could silently fail to appear); closing/switching a directory now visibly clears the old grid and title before any sync dialog appears, instead of leaving stale content on screen throughout the sync.
  • PR-prep: bumped VERSION to 0.9.0 (compiled inputs changed), added the CHANGELOG.md section, recorded docs/DECISIONS.md DR-044, and updated resources/help/USER_GUIDE.md for all the above.

Follow-up work filed (not fixed in this PR)

  • #176 — a separate, unreported hang between the hydrate dialog closing and the grid populating (redundant full-table reads + an unchunked thumbnail-BLOB load).
  • #178 — background scan writes can contend with main-thread tag/delete writes for SQLite's single writer lock, which can freeze the UI; needs a connection-management change (shared writer connection per WorkingDB) rather than a status-reporting fix, so it's tracked separately.

Test plan

  • ruff check . / ruff format --check . — clean
  • Full pytest -q — 775 passed, 1 skipped
  • ./scripts/check-version-bump.sh — confirms VERSION bumped (0.8.00.9.0)

https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ

## Summary - Added `core/status_message.py`: a single standard for every long-running action's status text — `{action} [Stage n/total name]: {count}/{total} (rate unit/s; M:SS remain) {item_name}`, with a 10-second rolling-average rate. Dialogs render it as up to three lines (action/stage, count/rate/ETA, item name); the status bar keeps the single-line form. - Applied the standard to the perceptual duplicate scan (added progress reporting to the previously-silent hash-comparison stage), the directory-open scan (relabeled into three stages: **Scanning Directory**, **Updating Database**, **Generating Thumbnails**), subdirectory tag creation, and Sort into Folders. - Converted four previously-silent or background-only operations into modal dialogs shown *before* their work starts, each with a progress bar and (except the closing-side share sync) a **Cancel** button: - `NetworkHydrateDialog` — cache pull on directory open. - `NetworkSyncDialog` — cache push on close/switch/exit (no cancel — interrupting a share write mid-copy could corrupt it). - `SubdirTagBuildDialog` — "Create Tags from Sub-directories," now shown before planning starts instead of after. - `SortIntoFoldersDialog` — rebuilt around a loading/content stack so the preview-building step shows progress in the same dialog that then displays the result; toggling multi-tag directories re-triggers the loading step. - Fixed a full-repo audit's worth of N+1 query loops causing silent multi-second-to-minutes hangs on large workspaces: subdirectory tag planning/apply, the post-hydrate grid preload, Sort into Folders' eligible-image lookup, duplicate-group bulk actions, and network share metadata import. - Fixed two Qt UI bugs found via real-world testing: switching directly between two network shares now shows both the closing-share sync dialog and the new share's loading dialog (previously the second could silently fail to appear); closing/switching a directory now visibly clears the old grid and title before any sync dialog appears, instead of leaving stale content on screen throughout the sync. - PR-prep: bumped `VERSION` to `0.9.0` (compiled inputs changed), added the `CHANGELOG.md` section, recorded `docs/DECISIONS.md` DR-044, and updated `resources/help/USER_GUIDE.md` for all the above. ## Follow-up work filed (not fixed in this PR) - #176 — a separate, unreported hang between the hydrate dialog closing and the grid populating (redundant full-table reads + an unchunked thumbnail-BLOB load). - #178 — background scan writes can contend with main-thread tag/delete writes for SQLite's single writer lock, which can freeze the UI; needs a connection-management change (shared writer connection per `WorkingDB`) rather than a status-reporting fix, so it's tracked separately. ## Test plan - [x] `ruff check .` / `ruff format --check .` — clean - [x] Full `pytest -q` — 775 passed, 1 skipped - [x] `./scripts/check-version-bump.sh` — confirms `VERSION` bumped (`0.8.0` → `0.9.0`) https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(dupe): report progress during the perceptual-hash comparison stage
All checks were successful
CI / lint (push) Successful in 16s
CI / test (push) Successful in 3m2s
CI / appimage (push) Successful in 17m7s
CI / build-appimage (push) Successful in 0s
CI / windows-exe (push) Successful in 21m30s
CI / build-windows-exe (push) Successful in 0s
4dd4b5dac2
The visual-dupe scan's pairwise Hamming-distance comparison (O(n^2)) ran
with no progress feedback after hashing finished, leaving the UI looking
frozen on large libraries. Thread an optional on_progress callback through
group_visual_duplicates/_union_find_groups, throttled per outer iteration,
and relay it via DupeWorker's existing progress signal. Status messages now
read "Stage 1/2: Scanning ..." during hashing and "Stage 2: Comparing X/Y"
during comparison.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(dupe): add counts and a 5s rolling rate to dupe scan status text
All checks were successful
CI / lint (push) Successful in 19s
CI / test (push) Successful in 5m5s
CI / windows-exe (push) Successful in 16m1s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 18m48s
CI / build-appimage (push) Successful in 0s
1dccf4b538
Stage 1 now reads "Stage 1 of 2: Scanning {count} of {total} ({rate}
img/s) {name}", tracking image throughput over a rolling 5-second window
rather than a since-start average so the rate reacts to recent speed.
Stage 2 mirrors this with "{done} of {total_pairs} ({rate} pairs/s)"
for visual scans, omitting whichever fields aren't available yet (exact
scans have no pairwise sub-progress, so stage 2 there stays a bare label).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(dupe): add a time-remaining estimate to dupe scan status text
All checks were successful
CI / lint (push) Successful in 16s
CI / test (push) Successful in 3m27s
CI / windows-exe (push) Successful in 16m34s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 18m4s
CI / build-appimage (push) Successful in 0s
f74942bcd7
Derive an M:SS ETA from the same rolling-5s rate already shown, using
(remaining_count / rate), and append it next to the rate in both stages:
"Stage 1 of 2: Scanning {n} of {total} ({rate} img/s; {mm:ss} remain) {name}"
and, when a rate is known, "Stage 2 of 2: Comparing {n} of {total} ({rate}
pairs/s; {mm:ss} remain)" for visual scans. The ETA (like the rate) is
simply omitted from the message when not yet computable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(status): standardize progress/status messages across every worker and dialog
All checks were successful
CI / lint (push) Successful in 20s
CI / test (push) Successful in 4m7s
CI / windows-exe (push) Successful in 17m20s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 17m48s
CI / build-appimage (push) Successful in 0s
ff3a099ae6
Introduce core/status_message.py (RateTracker with a rolling 10s window,
Stage, build_status_message) as a single formatter for the app's "{action}
[Stage n/total name]: count/total (rate unit/s; M:SS remain) item_name"
status-text shape, with each piece included only when calculable.

Migrate every background operation onto it: DupeWorker (gains real ACTION
text: "Scan Duplicate Files" / "Scan Visual Duplicates"), the directory-scan
pipeline (discover/enrich phases, replacing the old since-start-average
ui/scan_progress.py, now deleted), thumbnail generation, DeleteWorker,
SortWorker, SearchMetadataWorker, the thumbnail-benchmark dialog, and the
sort/subdir-tag-build dialogs (now simple set_message(str) passthroughs of
the worker-built string instead of building their own count/total text).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(workspace): modal progress dialog for network cache hydrate on open
All checks were successful
CI / lint (push) Successful in 19s
CI / test (push) Successful in 7m24s
CI / windows-exe (push) Successful in 16m43s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 20m54s
CI / build-appimage (push) Successful in 0s
8549699256
Opening a directory on a network share could freeze the (already-shown) main
window with no feedback and no way to cancel while the local cache hydrated
from the share, especially during a legacy metadata merge (which had no
progress callback at all). Add NetworkHydrateDialog — a modal QDialog with
a real progress bar and the standard status-message format — shown only
when a hydrate is actually needed, wired into open_directory()'s hydrate
block with a per-run rolling-rate tracker.

Thread should_continue cancellation through
copy_sqlite_database/prepare_network_workspace_cache/import_share_metadata
in core/workspace_cache.py (new HydrateCancelled exception; a cancelled
copy removes its partial destination file). Cancelling the dialog aborts
open_directory() entirely via a new _abort_network_hydrate() cleanup,
reverting the in-progress workspace assignment so the app ends in the
"no directory open" state rather than a half-hydrated one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(ui): rework Create-from-Sub-directories dialog + progress bars everywhere
Some checks failed
CI / lint (push) Successful in 16s
CI / test (push) Successful in 4m41s
CI / build-appimage (push) Has been cancelled
CI / build-windows-exe (push) Has been cancelled
CI / windows-exe (push) Has been cancelled
CI / appimage (push) Has been cancelled
b470dbc47b
The "Create from Sub-directories" dialog only appeared after
plan_tags_from_subdirs() had already run synchronously, so large workspaces
froze with no feedback before the dialog was even visible. Show the dialog
immediately and split the work into two visible stages: "Scanning
Directories" (planning) then "Assigning Tags" (apply, unchanged mechanism).
apply_subdir_tags_incremental() now accepts a precomputed plan to avoid
recomputing it a second time. Also fix an N+1 query in
plan_tags_from_subdirs() (per-image get_tags_for_image() loop -> one batched
get_tags_for_images() call) and skip loading thumbnail BLOBs there, since
only paths/tags are needed — the real source of the "large directory" slowness.

Add a QProgressBar to every dialog that shows a status counter
(SortProgressDialog, SubdirTagBuildDialog — NetworkHydrateDialog already had
one), each laid out message-label -> progress-bar -> buttons.

Add core/status_message.dialog_message(): splits a build_status_message()
string into "{action}[stage]}\n{count/rate/name}" for dialog display, while
the shared builder itself (and the main window's status bar) stay single-line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
fix(workspace): show network hydrate dialog before touching the share at all
All checks were successful
CI / lint (push) Successful in 17s
CI / test (push) Successful in 4m26s
CI / windows-exe (push) Successful in 17m27s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 17m56s
CI / build-appimage (push) Successful in 0s
09a0b0d94d
predict_hydrate_action() was called before the NetworkHydrateDialog was even
constructed. That function does real network I/O (stat calls on the share
path, plus a SELECT against the remote share DB to check for thumbnail
BLOBs) — on a slow/high-latency share this stalled open_directory() with
nothing visible at all: no dialog, and (since the deferred auto-open can
fire before the main window has painted) sometimes not even the main
window's own UI, just an unpainted frame. Show the dialog first, before any
network-touching call, whenever the workspace is a network location with a
share path — not just when a hydrate turns out to be needed.

Also pump the event loop once at the top of open_directory(), before the
heavier per-directory work starts, so the main window gets a chance to
paint even on the very first directory open triggered by the deferred
auto-open-last-directory timer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
fix(scan): fix N+1 query hang in post-hydrate grid preload
All checks were successful
CI / lint (push) Successful in 23s
CI / test (push) Successful in 9m46s
CI / windows-exe (push) Successful in 16m19s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 22m43s
CI / build-appimage (push) Successful in 0s
24713a63fa
After the network hydrate dialog closes (or immediately on a local open),
open_directory() preloads the grid from the working DB before launching the
scan. That preload built each row's dict via TagManager.image_dict_with_tags()
in a per-image loop -- one get_tags_for_image() round trip per image, with
zero progress feedback -- so a large workspace hung silently between the
hydrate dialog closing and the scan's own "Discovering" stage taking over.
Same anti-pattern already fixed for the sub-directory tag planner; the fix
here is the same: switch to the existing bulk image_dicts_with_tags() (one
query for every record) instead of the per-record variant.

Also surface this whole post-hydrate block (recent-open bookkeeping, stale
type pruning, preload) in the status/progress stream via a "Scan Directory:
Preparing workspace..." indeterminate message, so it no longer looks frozen
even if it still takes a moment on a very large workspace.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(workspace): show a modal dialog for share sync on close, not just on load
All checks were successful
CI / lint (push) Successful in 23s
CI / test (push) Successful in 4m38s
CI / windows-exe (push) Successful in 17m30s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 18m48s
CI / build-appimage (push) Successful in 0s
6e09fa910e
Sync-to-share on directory close, directory switch, and app close already
ran synchronously and blocked before this change -- they just reported
progress as bottom-status-bar text (or nothing, for the app-close case's
extra pre-status line). Give those three call sites a NetworkSyncDialog,
mirroring NetworkHydrateDialog's load-side treatment: modal, own progress
bar, standard status message.

No cancel button on this one: copy_sqlite_database() replaces the
destination file before writing the new one, so for the pull/hydrate
direction a cancelled copy just removes the local (recoverable) cache, but
for this push direction the destination is the *shared* file other
machines rely on -- interrupting it partway would leave that share copy
empty or truncated instead of at its last-known-good state. Since the app
already waited for this synchronously either way, making the wait visible
carries no new behavior change, just no destructive-cancellation risk.

_sync_workspace_cache_to_share_if_needed() gains a `modal` kwarg alongside
the existing `show_ui`; the post-scan and background-timer sync paths keep
the original non-modal/silent behavior since they run mid-session while the
user may still be interacting with the app.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(ui): build the Sort into Folders preview in-dialog with status/progress
All checks were successful
CI / lint (push) Successful in 26s
CI / test (push) Successful in 8m57s
CI / windows-exe (push) Successful in 16m16s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 23m3s
CI / build-appimage (push) Successful in 0s
af9646c750
The "Sort into Folders by Tags" confirmation dialog built its entire listing
(one DB round trip per eligible image via get_image_by_path(), plus
synchronous thumbnail decode/scale for every image) inside its own
constructor, before the caller ever got to show() or exec() it -- so on a
large workspace the app just looked locked up with nothing on screen at
all, same class of bug as the earlier network-hydrate and sub-directory-tag
cases. Fix the underlying N+1 in
WorkingDB.get_sort_eligible_images_by_tag() (batch get_images_by_paths()
instead of one get_image_by_path() per image, matching the existing
issue #118 bulk-fetch pattern), and restructure the dialog itself around a
QStackedWidget: a loading page (standard status message, progress bar,
Cancel) shown immediately, swapped for the real listing page once load()
finishes -- rather than a separate modal dialog like the network-sync work.
Toggling the "Create Multi-Tag Directories" checkbox re-triggers the same
loading page before repopulating, instead of rebuilding silently in place.

main_window._on_sort_into_folders() now does dlg.show() -> load() ->
exec() instead of exec() alone, so the loading page actually paints before
the (now chunked, periodically-pumping) build runs. Cancelling mid-build
rejects the dialog outright, since there's nothing meaningful to confirm
from a partial preview.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
perf(db): fix remaining N+1 query loops found by a full-repo audit
All checks were successful
CI / lint (push) Successful in 26s
CI / test (push) Successful in 9m36s
CI / windows-exe (push) Successful in 17m9s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 20m46s
CI / build-appimage (push) Successful in 0s
556ff6467e
A full audit of every remaining bulk-action/status-message loop (prompted
after this session's third unrelated N+1 fix) found four more instances of
the same shape, all fixed the same way (batch fetch instead of one query per
item), matching this codebase's existing issue #118 bulk-fetch precedent:

- workspace_cache.import_share_metadata(): two loops (image upsert, tag-pair
  assignment) each called get_image_by_path()/get_tag_by_name() per item;
  now bulk-fetched once via get_images_by_paths() and one get_all_tags()
  read, and a redundant duplicate get_all_images() call was removed.
- TagManager.apply_subdir_tags_incremental()'s auto-tag loop called
  get_tags_for_image() per image (its plan_tags_from_subdirs() sibling was
  already fixed, this loop wasn't); now uses get_tags_for_images() once,
  plus include_thumbnails=False since blobs are never read here.
- main_window._on_dupe_bulk_actions() called get_image_dicts_for_dupe_tag()
  once per duplicate group; added get_image_dicts_for_dupe_tags() (one query
  for every group, same shape as get_dupe_group_representatives()) and
  switched the loop to it.

Also two small get_all_images()-just-for-a-count call sites (post-scan
recent-dir bookkeeping, delete-all-tags' affected-paths list) switched to
get_image_count() / include_thumbnails=False respectively, avoiding loading
every thumbnail BLOB just to discard it.

The audit's other angle (loops still missing status-message reporting)
turned up nothing actionable: every worker already reports progress via the
established standard, and the handful of unreported loops are either
single-item (dupe sharpness scoring, rotation writes) or a single bulk
filesystem call (purge_originals_directory), where a progress concept
doesn't apply.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
fix(ui): force new modal progress dialogs to the front after a prior one closes
All checks were successful
CI / lint (push) Successful in 17s
CI / test (push) Successful in 3m56s
CI / appimage (push) Successful in 17m12s
CI / build-appimage (push) Successful in 0s
CI / windows-exe (push) Successful in 17m54s
CI / build-windows-exe (push) Successful in 0s
463ef15847
Switching between two open network shares showed the NetworkSyncDialog for
closing the old one, then silently ran the hydrate for the new one with no
dialog visible at all (the load itself completed correctly, just invisibly)
-- show() alone doesn't reliably raise/focus a new dialog opened immediately
after a previous one was hidden in the same call stack.

Add MainWindow._show_modal_dialog() (show() + raise_() + activateWindow())
and use it everywhere a progress dialog is driven by show() + manual
_pump_ui_events() rather than exec() (which already raises/activates on its
own): NetworkHydrateDialog, NetworkSyncDialog, SubdirTagBuildDialog,
SortProgressDialog, and SortIntoFoldersDialog's initial show() before load().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
fix(ui): clear the old directory's grid before syncing/closing it, not after
Some checks failed
CI / lint (push) Successful in 16s
CI / test (push) Successful in 6m44s
CI / build-appimage (push) Has been cancelled
CI / build-windows-exe (push) Has been cancelled
CI / appimage (push) Has been cancelled
CI / windows-exe (push) Has been cancelled
7b67ab9d6b
Both open_directory() (switching directories) and _finalize_workspace_close()
(Close Directory and Delete Cache) cleared the grid/window title only after
the sync-to-share dialog (and, when switching, the new directory's hydrate
dialog too) had already run to completion -- so the old directory's grid
stayed fully populated on screen through both dialogs, made it look like
nothing was happening (or like the old content was what was being worked
on), with no visible "closing" step before the new directory's load began.

Move self.model.clear()/setWindowTitle(APP_NAME) to right before the
sync-to-share call in both places, so the old directory visibly closes out
first. A first regression test caught that an earlier attempt at this same
turn had the ordering backwards (clear placed after the sync call instead
of before it) -- the final placement is verified by a test that reads
grid row count and window title at the exact moment the sync dialog's
show() fires.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
feat(status): give the filename its own line in dialog status messages
All checks were successful
CI / lint (push) Successful in 21s
CI / test (push) Successful in 4m4s
CI / windows-exe (push) Successful in 16m21s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 17m14s
CI / build-appimage (push) Successful in 0s
34245e3d07
dialog_message() previously split a build_status_message() string onto two
lines: action/stage, then everything else (count/total, rate/eta, AND the
item name) crammed onto one second line. Per request, a dialog showing
progress and a filename should show three: action, status (count/rate/eta),
and filename, each on its own line, above the progress bar and buttons.

Since build_status_message()'s single-line wire format (used unchanged by
the main status bar and as the string carried across worker Qt signals)
always appends the item name last, separated by a space, after a
count[/total][ (rate/eta)] chunk with a fixed grammar, dialog_message() can
reliably regex-match that leading chunk and treat whatever text follows as
the filename -- no changes needed to build_status_message() itself or to
any of the ~15 call sites that build these strings. A body with no leading
digits (e.g. "Preparing workspace..." used as a bare status phrase, not a
real filename) is left on a single status line rather than being split
incorrectly.

Only SortProgressDialog currently displays a real per-item filename today
(via SortWorker's item_name), so it's the only dialog whose test assertions
changed; NetworkHydrateDialog, NetworkSyncDialog, SubdirTagBuildDialog, and
SortIntoFoldersDialog don't pass item_name today and are unaffected, but
will automatically render correctly if they ever do.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
ui(scan): relabel directory-open scan progress into 3 stages
All checks were successful
CI / lint (push) Successful in 15s
CI / test (push) Successful in 4m32s
CI / windows-exe (push) Successful in 17m11s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 17m23s
CI / build-appimage (push) Successful in 0s
699c39922b
Splits "Stage 1/2 Discovering" into "Scanning Directory" and "Updating
Database" (the placeholder scan already runs as two passes internally
-- walk, then batch-upsert -- this just surfaces that as two distinct
stages instead of one label covering both) and renames the deep-scan
stage from "Reading Metadata" to "Generating Thumbnails" for clarity.
No change to the underlying scan process (issue #176 follow-up
investigation).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
docs: PR-prep for status-message standard + progress dialogs (0.9.0)
Some checks failed
CI / lint (push) Successful in 18s
CI / test (push) Successful in 6m13s
CI / appimage (push) Failing after 10s
CI / build-appimage (push) Failing after 0s
CI / windows-exe (push) Successful in 18m36s
CI / build-windows-exe (push) Successful in 0s
5de563fd38
Bumps VERSION to the next canonical release (0.9.0) since this branch
touched compiled inputs, adds the 0.9.0 CHANGELOG section, records
DR-044 for the status-message standard and the four operations moved
into foreground progress dialogs, and updates USER_GUIDE.md for the
now-visible network sync/hydrate dialogs, the reworked Create from
Sub-directories and Sort into Folders dialogs, and the status bar's
narrower scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ
ValleyGeek deleted branch 0.8.0/dupe-compare-progress 2026-08-26 05:24:56 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ai-collab/bulk-image-organizer!180
No description provided.