Skip to content

fix bug in batches where sometimes it would grab the wrong photo when uploading a batch of images#45

Merged
AlanRockefeller merged 10 commits intomainfrom
test
Mar 6, 2026
Merged

fix bug in batches where sometimes it would grab the wrong photo when uploading a batch of images#45
AlanRockefeller merged 10 commits intomainfrom
test

Conversation

@AlanRockefeller
Copy link
Copy Markdown
Owner

@AlanRockefeller AlanRockefeller commented Feb 24, 2026

Summary by CodeRabbit

  • New Features

    • Added a "Todo" flag: toggle with D, filterable in Filter dialog, shown on thumbnails (badge, tile visuals, sparkline), and displayed as "Todo since {date}" in the UI.
  • Bug Fixes

    • Fixed batch range alignment after deletions to prevent stale/misaligned UI state.
    • Improved cross‑platform thumbnail path matching, more robust shutdown/teardown, and reduced eviction-related UI races.
  • Chores

    • Removed various debug/repro/test scripts and cleaned recorded test-output artifacts.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)

Walkthrough

Removed many test/repro/smoke artifacts and a pytest transcript; added per-image "todo" metadata, UI bindings, and keybinding; changed cache eviction callback semantics and eviction-time context; extended AppController deletion/rollback logic and added a safe executor shutdown helper.

Changes

Cohort / File(s) Summary
Eviction & cache semantics
faststack/imaging/cache.py
Made on_evict variadic (2- or 3-arg) with arity detection; added eviction info context (reason, usage, counts, thread_id); added pressure-eviction tracking; deferred/batched callback execution for some paths to avoid races.
App controller, deletion & shutdown
faststack/app.py
Saved pre-mutation batch snapshots for delete jobs; added _recompute_batches_after_deletions and enhanced rollback to restore batches; extended _on_cache_evict signature; added @staticmethod _safe_shutdown_executor and refactored shutdown_nonqt to use it; added toggle_todo.
Metadata, thumbnail model & UI
faststack/models.py, faststack/thumbnail_view/model.py, faststack/thumbnail_view/folder_stats.py, faststack/ui/provider.py, faststack/ui/keystrokes.py, faststack/qml/*
Added todo and todo_date to EntryMetadata; introduced is_todo on ThumbnailEntry and IsTodoRole; expanded coverage buckets to include todo ratios; exposed isTodo/todoDate to UI; added D keybinding and QML tile/badge, filter dialog, and main label bindings.
Thumbnail path normalization / loupe lookup
faststack/thumbnail_view/model.py
Normalized lookups in _get_loupe_index_for_entry to use absolute normalized paths to match _rebuild_path_to_index format (cross-platform consistency).
Tests updated
faststack/tests/test_cache_replacement_callback.py, faststack/tests/thumbnail_view/test_folder_stats.py
Adjusted tests to new eviction semantics (evict_paths suppresses callbacks) and expanded coverage-buckets return shape (now includes todo component).
Deleted repro/test/smoke artifacts & transcript
faststack/all_verification_results_utf8.txt, faststack/check_daemon.py, faststack/check_scipy.py, faststack/repro_cache_lock.py, faststack/repro_daemon_bug.py, faststack/repro_imports.py, faststack/repro_type_error.py, faststack/test_prespawn_strategy.py, faststack/verify_cache_fix.py, faststack/verify_wb.py, scripts/smoke_verify.py
Removed numerous standalone test/repro scripts and a recorded pytest session; no production APIs added via these files.
Changelog
ChangeLog.md
Added entry describing a bug fix related to deletion corrupting batch ranges when deletes are cancelled/undone.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI / QML
    participant App as AppController
    participant Cache as ByteLRUCache
    participant Exec as ThreadPoolExecutor
    participant Worker as WorkerThread

    UI->>App: toggle_todo() or delete action
    App->>Cache: mutate / __delitem__ (may trigger eviction)
    Cache->>Cache: detect pressure, build eviction info
    Cache->>App: call _on_cache_evict(key, value, info)
    App->>Exec: submit DeleteJob (captures pre-mutation snapshots)
    Exec->>Worker: run DeleteJob (may recompute batches)
    Worker-->>App: report completion / enable rollback restore
Loading
sequenceDiagram
    participant App as AppController
    participant Safe as _safe_shutdown_executor
    participant Exec as ThreadPoolExecutor
    participant Log as Logger

    App->>Safe: _safe_shutdown_executor(executor, name, wait?, cancel_futures?)
    Safe->>Exec: executor.shutdown(wait=..., cancel_futures=...)
    Exec->>Exec: cancel/finish pending work
    Exec-->>Safe: return/raise
    Safe->>Log: log shutdown outcome
    Safe-->>App: return
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Update image editor #26: Overlaps executor lifecycle changes; both add/refactor safe shutdown and executor management code in app.py.
  • fix some bugs #31: Overlaps deletion/rollback and recycle-bin batch handling changes affecting delete job and batch recomputation logic.
  • Release versi #43: Related ByteLRUCache eviction semantics edits — both modify eviction callback behavior and context.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 74.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title describes a bug fix related to batch uploads and photo selection, which aligns with significant changes to batch/rollback mechanics in app.py including _recompute_batches_after_deletions and enhanced batch state restoration. However, the changeset is substantially broader, encompassing a new todo feature across multiple components (UI, models, cache), removal of test/debug scripts, and cache eviction improvements. The title focuses on only one aspect of a much larger change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 741eeaa92b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread faststack/app.py
Comment on lines +4331 to +4333
if new_batches != self.batches:
self.batches = new_batches
self._invalidate_batch_cache()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve batch state before mutating it for optimistic deletes

This eagerly rewrites self.batches, but non-batch delete jobs never store a pre-delete batch snapshot (DeleteJob.saved_batches is only populated in delete_batch_images), so rollback paths restore image_files without restoring batch ranges. In practice, if a user has batches defined and performs a normal delete that is later undone/cancelled (or fails and is rolled back), batch indices remain shifted and subsequent batch operations can target the wrong photos.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@faststack/app.py`:
- Around line 4302-4334: Before mutating self.batches in the delete path, take a
snapshot (e.g., saved_batches and saved_batch_start_index) and use that snapshot
to restore self.batches if the delete is rolled back or undone; ensure the
mutation logic that builds new_batches (including _shift, first_ok/last_ok logic
and the call to self._invalidate_batch_cache()) writes only after the snapshot
is taken, and add restoration of saved_batches and saved_batch_start_index in
the pending_delete undo path so batch markers are re-aligned whenever
image_files are restored.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a5cdbe and 741eeaa.

📒 Files selected for processing (19)
  • faststack/all_verification_results.txt
  • faststack/all_verification_results_utf8.txt
  • faststack/app.py
  • faststack/check_daemon.py
  • faststack/check_scipy.py
  • faststack/integration_results.txt
  • faststack/integration_traceback.txt
  • faststack/path_check.txt
  • faststack/repro_cache_lock.py
  • faststack/repro_daemon_bug.py
  • faststack/repro_imports.py
  • faststack/repro_type_error.py
  • faststack/rotation_error.txt
  • faststack/test_prespawn_strategy.py
  • faststack/thumbnail_view/model.py
  • faststack/traceback.txt
  • faststack/verify_cache_fix.py
  • faststack/verify_wb.py
  • scripts/smoke_verify.py
💤 Files with no reviewable changes (11)
  • faststack/check_scipy.py
  • faststack/repro_imports.py
  • faststack/verify_cache_fix.py
  • scripts/smoke_verify.py
  • faststack/repro_daemon_bug.py
  • faststack/all_verification_results_utf8.txt
  • faststack/repro_type_error.py
  • faststack/test_prespawn_strategy.py
  • faststack/check_daemon.py
  • faststack/verify_wb.py
  • faststack/repro_cache_lock.py

Comment thread faststack/app.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
faststack/app.py (1)

4308-4338: ⚠️ Potential issue | 🟠 Major

Batch reindexing is still not rollback-safe for non-batch deletes.

Line 4308 mutates self.batches optimistically, but no snapshot is attached to the DeleteJob in _delete_indices. If the operation is undone/cancelled/fails, image_files can be restored while batch ranges remain shifted, which can still target the wrong photos.

🛠️ Proposed fix
@@
-        # --- PHASE 1: OPTIMISTIC UI UPDATE (instant, no I/O) ---
+        # --- PHASE 1: OPTIMISTIC UI UPDATE (instant, no I/O) ---
+        # Snapshot batch state for rollback/undo before any mutation.
+        saved_batches = list(self.batches) if self.batches is not None else None
+        saved_batch_start_index = self.batch_start_index
@@
-        self._pending_delete_jobs[job_id] = DeleteJob(
+        self._pending_delete_jobs[job_id] = DeleteJob(
             job_id=job_id,
             removed_items=removed_items,
             action_type=action_type,
             timestamp=timestamp,
             cancel_event=cancel_event,
             previous_index=previous_index,
             images_to_delete=images_to_delete,
         )
+        self._pending_delete_jobs[job_id].saved_batches = saved_batches
+        self._pending_delete_jobs[job_id].saved_batch_start_index = saved_batch_start_index
@@ def undo_delete(self):
         if action_type == "pending_delete":
             job_id = action_data
             job = self._pending_delete_jobs.get(job_id)
@@
                 self._rebuild_path_to_index()
+
+                # Restore batch markers/ranges to pre-delete state.
+                if getattr(job, "saved_batches", None) is not None:
+                    self.batches = job.saved_batches
+                    self.batch_start_index = getattr(job, "saved_batch_start_index", None)
+                    self._invalidate_batch_cache()
+
                 self.sync_ui_state()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@faststack/app.py` around lines 4308 - 4338, The batch reindexing currently
mutates self.batches inside the delete flow which can leave batch ranges shifted
if a non-batch delete is undone or fails; modify _delete_indices (and the
DeleteJob it creates) to take and store a snapshot of the original self.batches
before any mutation, perform the reindexing only after the delete has committed
(or else apply the mutation in a transactional/commit hook), and on
cancel/failure restore the saved snapshot back to self.batches and call
self._invalidate_batch_cache(); reference self.batches, DeleteJob,
_delete_indices, and _invalidate_batch_cache when locating and implementing this
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@faststack/app.py`:
- Around line 4308-4338: The batch reindexing currently mutates self.batches
inside the delete flow which can leave batch ranges shifted if a non-batch
delete is undone or fails; modify _delete_indices (and the DeleteJob it creates)
to take and store a snapshot of the original self.batches before any mutation,
perform the reindexing only after the delete has committed (or else apply the
mutation in a transactional/commit hook), and on cancel/failure restore the
saved snapshot back to self.batches and call self._invalidate_batch_cache();
reference self.batches, DeleteJob, _delete_indices, and _invalidate_batch_cache
when locating and implementing this change.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 741eeaa and e3dd937.

📒 Files selected for processing (1)
  • faststack/app.py

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
faststack/app.py (1)

4422-4423: ⚠️ Potential issue | 🟠 Major

Pending-delete undo still doesn’t restore saved batch state.

Line 4422 and Line 4423 persist batch snapshots, but the "pending_delete" branch in undo_delete() restores only image_files/current_index. If undo happens mid-flight, batches can stay shifted/cleared and later target the wrong images.

🛠️ Suggested fix
@@ def undo_delete(self):
                 self._rebuild_path_to_index()
+                if job.saved_batches is not None:
+                    self.batches = [b[:] for b in job.saved_batches]
+                    self.batch_start_index = job.saved_batch_start_index
+                    self._invalidate_batch_cache()
                 self.sync_ui_state()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@faststack/app.py` around lines 4422 - 4423, The "pending_delete" branch in
undo_delete() only restores image_files and current_index but omits restoring
the saved batch state (saved_batches/pre_batch_snapshot and
saved_batch_start_index/pre_batch_start_snapshot), so undo mid-flight leaves
batches shifted; update the pending_delete path in undo_delete() to also restore
the saved_batches (use pre_batch_snapshot) and saved_batch_start_index (use
pre_batch_start_snapshot), and ensure any batch-related pointers or offsets that
depend on saved_batches/current_index are recalculated or reassigned so
subsequent operations target the correct images.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@faststack/app.py`:
- Around line 4422-4423: The "pending_delete" branch in undo_delete() only
restores image_files and current_index but omits restoring the saved batch state
(saved_batches/pre_batch_snapshot and
saved_batch_start_index/pre_batch_start_snapshot), so undo mid-flight leaves
batches shifted; update the pending_delete path in undo_delete() to also restore
the saved_batches (use pre_batch_snapshot) and saved_batch_start_index (use
pre_batch_start_snapshot), and ensure any batch-related pointers or offsets that
depend on saved_batches/current_index are recalculated or reassigned so
subsequent operations target the correct images.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3dd937 and a13fa59.

📒 Files selected for processing (1)
  • faststack/app.py

…ic from _rollback_ui_items but missed the batch restore block.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
ChangeLog.md (1)

14-14: Nit: use more formal language consistent with the rest of the changelog.

"mess up" is colloquial compared to the surrounding entries. Consider replacing with "corrupt" or "invalidate".

✏️ Proposed wording
-- Fixed a bug where deleting an image could mess up the batch selection ranges if the delete was cancelled, failed, or undone.
+- Fixed a bug where deleting an image could corrupt the batch selection ranges if the delete was cancelled, failed, or undone.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ChangeLog.md` at line 14, Update the ChangeLog entry that currently reads
"Fixed a bug where deleting an image could mess up the batch selection ranges if
the delete was cancelled, failed, or undone." to use formal wording by replacing
the colloquial phrase "mess up" with a more professional term such as "corrupt"
or "invalidate" (e.g., "Fixed a bug where deleting an image could corrupt the
batch selection ranges if the delete was cancelled, failed, or undone.").
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@faststack/app.py`:
- Around line 4422-4423: The current rollback restores the entire pre-delete
snapshot (job.saved_batches and job.saved_batch_start_index) even for partial
rollbacks, which can reintroduce stale/out-of-range spans; in _rollback_ui_items
detect whether the rollback is full by comparing restored = {idx for idx,_ in
items} with original = {idx for idx,_ in job.removed_items} and only do the
direct restore of self.batches = [b[:] for b in job.saved_batches] and
self.batch_start_index = job.saved_batch_start_index when restored == original;
otherwise compute still_deleted = sorted(original - restored) and rebuild
self.batches from job.saved_batches using a helper like
recompute_batches_after_deletions(job.saved_batches, still_deleted), then call
self._invalidate_batch_cache() in both branches to refresh caches.
- Around line 4297-4307: The shift/reindex math uses unvalidated sorted_indices
which may contain out-of-range values; before computing deleted_set or shift,
capture the original_count = len(self.image_files) (before any removals) and
compute validated_sorted = sorted(i for i in sorted_indices if 0 <= i <
original_count), then use deleted_set = set(validated_sorted) and compute shift
= sum(1 for d in validated_sorted if d < previous_index); use deleted_set and
shift (and validated_sorted) everywhere you currently reference sorted_indices
(including the previous_index membership check and the shift computation) so
only valid indices affect current_index.

---

Nitpick comments:
In `@ChangeLog.md`:
- Line 14: Update the ChangeLog entry that currently reads "Fixed a bug where
deleting an image could mess up the batch selection ranges if the delete was
cancelled, failed, or undone." to use formal wording by replacing the colloquial
phrase "mess up" with a more professional term such as "corrupt" or "invalidate"
(e.g., "Fixed a bug where deleting an image could corrupt the batch selection
ranges if the delete was cancelled, failed, or undone.").

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a13fa59 and c53ee36.

📒 Files selected for processing (2)
  • ChangeLog.md
  • faststack/app.py

Comment thread faststack/app.py Outdated
Comment thread faststack/app.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
faststack/tests/thumbnail_view/test_folder_stats.py (1)

273-273: Add one positive todo bucket assertion.

These updates verify tuple arity, but they only cover todo_ratio == 0.0. Please add one case with {"todo": True} so regressions in todo accumulation are caught.

Proposed test addition
+    def test_single_file_todo(self):
+        """Test with single todo file."""
+        jpg_files = ["a.jpg"]
+        entries = {"a": {"uploaded": False, "stacked": False, "todo": True}}
+
+        buckets = _compute_coverage_buckets(jpg_files, entries, num_buckets=1)
+
+        assert len(buckets) == 1
+        assert buckets[0] == (0.0, 0.0, 1.0)

Also applies to: 283-283

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@faststack/tests/thumbnail_view/test_folder_stats.py` at line 273, Add an
assertion that covers a positive todo bucket so we don't only test todo_ratio ==
0.0: after the existing buckets check (variable buckets) insert an assertion
that when the input includes {"todo": True} one of the tuples equals
(uploaded_ratio, stacked_ratio, 1.0) — specifically assert buckets[...] == (1.0,
0.0, 1.0) for the case that previously asserted (1.0, 0.0, 0.0); apply the same
additional assertion in the other similar test block that mirrors the assertion
at the other location so both places validate todo accumulation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@faststack/app.py`:
- Around line 4386-4422: The batch_start_index isn't adjusted after deletions;
update it after you compute new_batches: if pre_batch_start_snapshot is not None
then if pre_batch_start_snapshot is in deleted_set set self.batch_start_index =
None (start was deleted) else set self.batch_start_index =
_shift(pre_batch_start_snapshot) to reindex it for removed entries; if the
reindexed value differs from the current self.batch_start_index call
self._invalidate_batch_cache() (same cache invalidation path used for
self.batches). Ensure you reference the existing _shift helper,
pre_batch_start_snapshot, deleted_set, and self._invalidate_batch_cache() when
implementing this change.
- Around line 5110-5138: The _on_cache_evict callback currently has a default
info=None which prevents _detect_arity from recognizing the handler's third
parameter so _fire_evict only calls it with (key, value); remove the default so
the signature is def _on_cache_evict(self, key, value, info): to ensure the
evict info dict is passed through; update references to info usage (e.g.,
eviction_usage = info.get(...)) to assume info is provided and adjust any
callers or tests expecting None accordingly, and run tests that exercise
_fire_evict, _detect_arity, and thrash detection to verify behavior.

In `@faststack/imaging/cache.py`:
- Around line 93-110: _detect_arity currently counts only required positional
parameters (checks p.default is inspect.Parameter.empty), so bound callbacks
like def f(key, value, info=None) are seen as arity=2; change the counting logic
in _detect_arity to count all parameters that can accept positional arguments
(kinds POSITIONAL_ONLY or POSITIONAL_OR_KEYWORD) regardless of defaults, so a
signature with info=None yields count=3 and self._on_evict_arity will be >=3 and
_fire_evict will pass the info arg; update the generator in _detect_arity
accordingly and keep references to _detect_arity, self._on_evict_arity, and
_fire_evict when making the change.

---

Nitpick comments:
In `@faststack/tests/thumbnail_view/test_folder_stats.py`:
- Line 273: Add an assertion that covers a positive todo bucket so we don't only
test todo_ratio == 0.0: after the existing buckets check (variable buckets)
insert an assertion that when the input includes {"todo": True} one of the
tuples equals (uploaded_ratio, stacked_ratio, 1.0) — specifically assert
buckets[...] == (1.0, 0.0, 1.0) for the case that previously asserted (1.0, 0.0,
0.0); apply the same additional assertion in the other similar test block that
mirrors the assertion at the other location so both places validate todo
accumulation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9899064a-0e36-4b48-bed8-6b1d4bfbc2b8

📥 Commits

Reviewing files that changed from the base of the PR and between c53ee36 and 6ecac39.

📒 Files selected for processing (13)
  • faststack/app.py
  • faststack/imaging/cache.py
  • faststack/models.py
  • faststack/qml/FilterDialog.qml
  • faststack/qml/Main.qml
  • faststack/qml/ThumbnailGridView.qml
  • faststack/qml/ThumbnailTile.qml
  • faststack/tests/test_cache_replacement_callback.py
  • faststack/tests/thumbnail_view/test_folder_stats.py
  • faststack/thumbnail_view/folder_stats.py
  • faststack/thumbnail_view/model.py
  • faststack/ui/keystrokes.py
  • faststack/ui/provider.py

Comment thread faststack/app.py
Comment thread faststack/app.py Outdated
Comment thread faststack/imaging/cache.py
@AlanRockefeller
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 6, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
faststack/ui/provider.py (1)

1619-1633: Reuse refreshRecycleBinStats() from cleanupRecycleBins().

This slot now defines the canonical recycle-bin notify set, but cleanupRecycleBins() still emits the same three signals manually on Lines 1631-1633. Calling the helper there keeps the refresh path from drifting.

♻️ Suggested cleanup
     `@Slot`()
     def cleanupRecycleBins(self):
         """Deletes all tracked recycle bins."""
         self.app_controller.cleanup_recycle_bins()
-
-        self.recycleBinStatsTextChanged.emit()
-        self.recycleBinDetailedTextChanged.emit()
-        self.hasRecycleBinItemsChanged.emit()
+        self.refreshRecycleBinStats()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@faststack/ui/provider.py` around lines 1619 - 1633, cleanupRecycleBins()
currently duplicates the signal emissions that refreshRecycleBinStats() already
encapsulates; replace the three manual emits in cleanupRecycleBins() with a
single call to self.refreshRecycleBinStats() after
self.app_controller.cleanup_recycle_bins() so the canonical notify logic lives
in refreshRecycleBinStats() (update cleanupRecycleBins to call
refreshRecycleBinStats rather than emitting recycleBinStatsTextChanged,
recycleBinDetailedTextChanged, and hasRecycleBinItemsChanged directly).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@faststack/qml/Main.qml`:
- Around line 1019-1023: The footer Label shows "Todo since " when
uiState.todoDate is an empty string; update the Label's text binding to check
uiState.todoDate (normalized from EntryMetadata.todo_date) and render "Todo
since {uiState.todoDate}" only when todoDate is non-empty, otherwise render
"Todo" (or an empty string if you prefer hiding the label), keeping the existing
visibility logic that uses uiState.imageCount and uiState.isTodo; locate the
Label block and change its text expression to branch on uiState.todoDate while
leaving the visible condition unchanged.

---

Nitpick comments:
In `@faststack/ui/provider.py`:
- Around line 1619-1633: cleanupRecycleBins() currently duplicates the signal
emissions that refreshRecycleBinStats() already encapsulates; replace the three
manual emits in cleanupRecycleBins() with a single call to
self.refreshRecycleBinStats() after self.app_controller.cleanup_recycle_bins()
so the canonical notify logic lives in refreshRecycleBinStats() (update
cleanupRecycleBins to call refreshRecycleBinStats rather than emitting
recycleBinStatsTextChanged, recycleBinDetailedTextChanged, and
hasRecycleBinItemsChanged directly).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9c2ecd94-f9cf-4807-9442-80f23c4e783f

📥 Commits

Reviewing files that changed from the base of the PR and between 6ecac39 and d4125f7.

📒 Files selected for processing (2)
  • faststack/qml/Main.qml
  • faststack/ui/provider.py

Comment thread faststack/qml/Main.qml
@Dj-Shortcut
Copy link
Copy Markdown

Directionally the batch fix looks useful, but this PR is still harder to review than it needs to be because it mixes
behavior changes with generated verification/traceback artifacts. As a small non-functional cleanup, I’d drop the
output files from the diff so the actual code changes are easier to validate in isolation.

@AlanRockefeller
Copy link
Copy Markdown
Owner Author

@coderabbitai I made some updates - please re-check the issues you have identified to see if they are still present.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 6, 2026

@AlanRockefeller Sure! I'll kick off a fresh review of the PR right away to check whether the previously identified issues have been addressed.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@AlanRockefeller
Copy link
Copy Markdown
Owner Author

Directionally the batch fix looks useful, but this PR is still harder to review than it needs to be because it mixes behavior changes with generated verification/traceback artifacts. As a small non-functional cleanup, I’d drop the output files from the diff so the actual code changes are easier to validate in isolation.

Yea you are right - I made some changes last week and forgot to close out the PR and push to main before I made some more yesterday.

@AlanRockefeller AlanRockefeller merged commit 8bf7f58 into main Mar 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants