Skip to content

refactor(app): remove unused status line and use logging for load state#30

Merged
timcogan merged 4 commits intomasterfrom
refactor/remove-status-line-use-logging
Mar 7, 2026
Merged

refactor(app): remove unused status line and use logging for load state#30
timcogan merged 4 commits intomasterfrom
refactor/remove-status-line-use-logging

Conversation

@timcogan
Copy link
Owner

@timcogan timcogan commented Mar 7, 2026

Summary by CodeRabbit

  • Refactor
    • Startup and status handling simplified; in-app status text replaced by log-driven handling.
  • New Features
    • Transient, dismissible load-error overlay added to the UI to surface loading problems.
  • Bug Fixes
    • Consolidated error and progress reporting across load paths; overlays clear on successful loads to reduce stale messages.
  • Tests
    • Updated tests to validate overlay behavior and log-driven status handling.

@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97ec8b66-521f-4358-8dc7-afb35ff01b16

📥 Commits

Reviewing files that changed from the base of the PR and between d3692c7 and c32ac41.

📒 Files selected for processing (1)
  • src/app.rs

📝 Walkthrough

Walkthrough

Replaced status_line with load_error_message: Option<String>, routed status updates to logging, added helper methods to set/clear load errors, updated constructor to new(initial_request: Option<LaunchRequest>), and added a dismissible UI overlay plus related test updates.

Changes

Cohort / File(s) Summary
App core & UI
src/app.rs
Removed public DicomViewerApp.status_line; added load_error_message: Option<String>, private helpers clear_load_error and set_load_error; changed constructor signature to new(initial_request: Option<LaunchRequest>); replaced direct status mutations with log::{info,warn,error,debug} and a dismissible load-error overlay in the main UI flow. Tests updated to reflect new error surface and logging-driven behavior.
Application bootstrap
src/main.rs
Simplified startup to derive a single initial_request from parse_launch_request_from_args, map parse failures to an AppCreation io::Error, and call DicomViewerApp::new(initial_request) (removed initial_status plumbing).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant App as DicomViewerApp
participant Loader as Loaders (DICOMweb / Local / History / GSPS)
participant Logger as log:: (info,warn,error,debug)
participant UI as UI Overlay

User->>App: trigger load (file / URL / restore)
App->>Loader: start load/poll
Loader-->>App: progress / success / error
alt success
    App->>Logger: info/debug (clear errors)
    App->>UI: clear load_error_message
else error
    App->>Logger: warn/error (record message)
    App->>App: set_load_error(message)
    App->>UI: show dismissible load_error_message
end
UI->>App: dismiss overlay
App->>UI: clear load_error_message

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I swapped the status line for a softer, fleecy note,
A pop-up with a message when a loader comes afloat.
Logs sing to the meadow, errors hop in place,
Dismiss, and then we scurry on—no trace, no frantic pace.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% 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 accurately describes the main changes: removing the status_line field and replacing it with logging for load state management and error reporting.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/remove-status-line-use-logging

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.

@timcogan
Copy link
Owner Author

timcogan commented Mar 7, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/app.rs (2)

1773-1779: ⚠️ Potential issue | 🟠 Major

Avoid logging raw local DICOM paths.

Line 1850 and Line 1901 log path.display() directly, and Line 1778 forwards worker errors that already embed the path. For a medical viewer, local paths can contain patient identifiers, so this change moves potentially sensitive data from transient UI state into durable logs.

Also applies to: 1850-1850, 1901-1901

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

In `@src/app.rs` around lines 1773 - 1779, The code logs raw local DICOM paths
(including in the receiver.try_recv() error branch and other places that call
path.display()), which may expose patient-identifying data; update the error
logging in the receiver.try_recv() match (the Err(err) arm) and any direct uses
of path.display() to avoid writing the full path to durable logs: instead log a
generic, non-identifying message (e.g., "failed to load image" or "path
redacted"), or redact the path (keep only a hashed/obfuscated identifier) before
including it; specifically modify the match around receiver.try_recv(), the call
site that invokes apply_loaded_single(pending.path, ...), and the two other log
sites that directly use path.display() so they no longer emit raw filesystem
paths.

1773-1791: ⚠️ Potential issue | 🟠 Major

Keep a user-visible error path for failed opens and invalid selections.

These branches now only write to the logger. In the GUI, a bad file / unsupported selection then falls back to the same generic empty state, so the user gets no on-screen explanation of what failed or how to recover.

Also applies to: 1818-1841

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

In `@src/app.rs` around lines 1773 - 1791, Update the error-handling branches of
the receiver.try_recv() match to set a user-visible error state instead of only
logging: when result is Err(_) or when Err(TryRecvError::Disconnected) assign a
descriptive message to a new or existing field (e.g. self.single_load_error:
Option<String>) and call ctx.request_repaint(); ensure the success path in
Ok(Ok(pending)) clears that field (e.g. self.single_load_error = None) after
calling self.apply_loaded_single(pending.path, pending.image, ctx). Apply the
same change to the other analogous receiver block referenced (lines ~1818-1841)
so all failed opens/invalid selections populate the UI-visible error state
rather than only writing to log.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main.rs`:
- Around line 13-18: The code currently swallows parse_launch_request_from_args
errors (in the initial_request match) and continues startup; change this to fail
fast or surface the error: when
launch::parse_launch_request_from_args(&cli_args) returns Err(err) do not return
None silently—either call process::exit with a non-zero status or propagate the
error so the caller can abort before window creation, or invoke your UI error
display routine to show the failure to the user; update the handling of
initial_request so invalid launches do not result in a blank window.

---

Outside diff comments:
In `@src/app.rs`:
- Around line 1773-1779: The code logs raw local DICOM paths (including in the
receiver.try_recv() error branch and other places that call path.display()),
which may expose patient-identifying data; update the error logging in the
receiver.try_recv() match (the Err(err) arm) and any direct uses of
path.display() to avoid writing the full path to durable logs: instead log a
generic, non-identifying message (e.g., "failed to load image" or "path
redacted"), or redact the path (keep only a hashed/obfuscated identifier) before
including it; specifically modify the match around receiver.try_recv(), the call
site that invokes apply_loaded_single(pending.path, ...), and the two other log
sites that directly use path.display() so they no longer emit raw filesystem
paths.
- Around line 1773-1791: Update the error-handling branches of the
receiver.try_recv() match to set a user-visible error state instead of only
logging: when result is Err(_) or when Err(TryRecvError::Disconnected) assign a
descriptive message to a new or existing field (e.g. self.single_load_error:
Option<String>) and call ctx.request_repaint(); ensure the success path in
Ok(Ok(pending)) clears that field (e.g. self.single_load_error = None) after
calling self.apply_loaded_single(pending.path, pending.image, ctx). Apply the
same change to the other analogous receiver block referenced (lines ~1818-1841)
so all failed opens/invalid selections populate the UI-visible error state
rather than only writing to log.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b98bbae0-9f5d-47f7-9bcd-c23dab05ba91

📥 Commits

Reviewing files that changed from the base of the PR and between 36a2bea and ef0273e.

📒 Files selected for processing (2)
  • src/app.rs
  • src/main.rs

Copy link

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/app.rs (2)

1039-1065: ⚠️ Potential issue | 🟡 Minor

Clear stale load errors after successful history restores.

A previous load_error_message survives both cache-hit paths here, so the error banner can stay visible even after the user opens a valid study from history.

Suggested fix
                 self.rebuild_texture(ctx);
+                self.clear_load_error();
                 log::info!("Loaded study from memory cache.");
                 ctx.request_repaint();
@@
                 self.mammo_selected_index = selected_index
                     .unwrap_or(group.selected_index)
                     .min(self.mammo_group.len().saturating_sub(1));
+                self.clear_load_error();
                 log::info!("Loaded grouped study from memory cache.");
                 ctx.request_repaint();

Also applies to: 1097-1105

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

In `@src/app.rs` around lines 1039 - 1065, The history-restore handlers (e.g., the
HistoryKind::Single branch and the other history branch around lines 1097-1105)
don't clear self.load_error_message after a successful restore, leaving stale
error banners visible; update both restore-success paths to set
self.load_error_message = None once the image/series has been loaded and view
state reset (before calling self.rebuild_texture and ctx.request_repaint) so
that any prior load error is cleared; refer to symbols HistoryKind::Single,
load_error_message, rebuild_texture, ctx.request_repaint,
reset_single_view_transform (and the analogous reset for the other branch) when
making the change.

1588-1646: ⚠️ Potential issue | 🟠 Major

Don't mark grouped DICOMweb loads successful before the active study is actually ready.

This branch runs when the grouped download worker finishes, but the active group may still be decoding, may have failed validation in load_local_groups, or may already have set a user-visible error from the streaming path. The unconditional clear_load_error() and success log here can therefore erase a real failure and emit a false success signal.

Suggested fix
-                        self.clear_load_error();
-                        log::info!("Loaded grouped study from DICOMweb.");

Move the success clear/log to the branches that actually finish loading the active study.

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

In `@src/app.rs` around lines 1588 - 1646, The code unconditionally calls
clear_load_error() and logs success at the end of the
DicomWebDownloadResult::Grouped handling, which can erase real failures;
instead, remove the unconditional clear_load_error() and log::info! call and
move them into the concrete success paths: after a successful local load
returned by load_local_groups (i.e., the branch where you call
self.load_local_groups(...)) and into the branch(s) where the active group is
known-ready (the path where streamed_active_complete is true or where you finish
preparing the active group via preload_non_active_groups_into_history,
mammo_group_complete(), reorder_complete_mammo_group(),
push_group_history_entry(), and move_current_history_to_front()). Ensure
clear_load_error() and the log::info!("Loaded grouped study from DICOMweb.") are
only invoked when the active study is actually ready and not in the general
end-of-branch cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/app.rs`:
- Around line 1039-1065: The history-restore handlers (e.g., the
HistoryKind::Single branch and the other history branch around lines 1097-1105)
don't clear self.load_error_message after a successful restore, leaving stale
error banners visible; update both restore-success paths to set
self.load_error_message = None once the image/series has been loaded and view
state reset (before calling self.rebuild_texture and ctx.request_repaint) so
that any prior load error is cleared; refer to symbols HistoryKind::Single,
load_error_message, rebuild_texture, ctx.request_repaint,
reset_single_view_transform (and the analogous reset for the other branch) when
making the change.
- Around line 1588-1646: The code unconditionally calls clear_load_error() and
logs success at the end of the DicomWebDownloadResult::Grouped handling, which
can erase real failures; instead, remove the unconditional clear_load_error()
and log::info! call and move them into the concrete success paths: after a
successful local load returned by load_local_groups (i.e., the branch where you
call self.load_local_groups(...)) and into the branch(s) where the active group
is known-ready (the path where streamed_active_complete is true or where you
finish preparing the active group via preload_non_active_groups_into_history,
mammo_group_complete(), reorder_complete_mammo_group(),
push_group_history_entry(), and move_current_history_to_front()). Ensure
clear_load_error() and the log::info!("Loaded grouped study from DICOMweb.") are
only invoked when the active study is actually ready and not in the general
end-of-branch cleanup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: da1e9097-cf38-4ba3-8270-428ab6c3dc8b

📥 Commits

Reviewing files that changed from the base of the PR and between ef0273e and 2433044.

📒 Files selected for processing (2)
  • src/app.rs
  • src/main.rs

Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app.rs (1)

1579-1589: ⚠️ Potential issue | 🟠 Major

Don't clear the error state before the single DICOMweb load actually succeeds.

load_selected_paths can still fail synchronously here. The unconditional clear_load_error() then erases that failure before poll_single_load has produced a real success.

💡 Suggested change
                     DicomWebDownloadResult::Single(paths) => {
                         self.load_selected_paths(paths, ctx);
                         self.dicomweb_active_group_expected = None;
                         self.dicomweb_active_group_paths.clear();
                         self.dicomweb_active_pending_paths.clear();
                         self.dicomweb_active_path_receiver = None;
                         self.mammo_load_sender = None;
                         self.history_pushed_for_active_group = false;
-                        self.clear_load_error();
-                        log::info!("Loaded study from DICOMweb.");
                     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app.rs` around lines 1579 - 1589, The code unconditionally calls
clear_load_error() after invoking load_selected_paths() inside the
DicomWebDownloadResult::Single branch, but load_selected_paths may fail
synchronously; change this so you only clear the error when the single DICOMweb
load truly succeeds: have the DicomWebDownloadResult::Single branch inspect the
result/return value of load_selected_paths (or propagate its Result), and on Err
leave the existing error state and avoid resetting dicomweb_active_* flags; only
call clear_load_error() (and reset dicomweb_active_group_expected,
dicomweb_active_group_paths, dicomweb_active_pending_paths,
dicomweb_active_path_receiver, mammo_load_sender,
history_pushed_for_active_group) after poll_single_load confirms success (or
when load_selected_paths returns Ok). Ensure you update error handling paths in
load_selected_paths, poll_single_load, and the Single branch so failures are
preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app.rs`:
- Around line 1858-1864: When paths.is_empty() currently only handles the GSPS
case, add a branch to also report when the user's selection consisted solely of
DicomPathKind::Other items so it doesn't silently return: detect this by
checking prepared (e.g. a prepared.other_files_found or by inspecting the
original selection for DicomPathKind::Other), and in that case call
self.set_load_error(...) with a user-facing message, log::warn!(...) with the
same context, and call ctx.request_repaint(); keep the existing GSPS handling
intact (use the same symbols: paths, prepared, DicomPathKind::Other,
set_load_error, log::warn, ctx.request_repaint).

---

Outside diff comments:
In `@src/app.rs`:
- Around line 1579-1589: The code unconditionally calls clear_load_error() after
invoking load_selected_paths() inside the DicomWebDownloadResult::Single branch,
but load_selected_paths may fail synchronously; change this so you only clear
the error when the single DICOMweb load truly succeeds: have the
DicomWebDownloadResult::Single branch inspect the result/return value of
load_selected_paths (or propagate its Result), and on Err leave the existing
error state and avoid resetting dicomweb_active_* flags; only call
clear_load_error() (and reset dicomweb_active_group_expected,
dicomweb_active_group_paths, dicomweb_active_pending_paths,
dicomweb_active_path_receiver, mammo_load_sender,
history_pushed_for_active_group) after poll_single_load confirms success (or
when load_selected_paths returns Ok). Ensure you update error handling paths in
load_selected_paths, poll_single_load, and the Single branch so failures are
preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8634bc56-ba88-47e6-87c9-eed0443ac87f

📥 Commits

Reviewing files that changed from the base of the PR and between 2433044 and d3692c7.

📒 Files selected for processing (1)
  • src/app.rs

@timcogan timcogan merged commit 583ceee into master Mar 7, 2026
7 checks passed
@timcogan timcogan deleted the refactor/remove-status-line-use-logging branch March 7, 2026 17:17
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.

1 participant