Skip to content

feat: restructure detections view as run-based browser#2

Merged
tphakala merged 4 commits intomainfrom
feat/detections-run-browser
Feb 7, 2026
Merged

feat: restructure detections view as run-based browser#2
tphakala merged 4 commits intomainfrom
feat/detections-run-browser

Conversation

@tphakala
Copy link
Copy Markdown
Owner

@tphakala tphakala commented Feb 7, 2026

Summary

  • Restructured app flow to separate analysis configuration from results display, following a ChatGPT/Claude conversation-history pattern:
    • Analysis tab always shows the configuration UI (file/folder selection, model, coordinates, confidence, start button) — never results
    • Detections tab shows a sidebar listing past analysis runs with source name, model, detection count, location, and date. Selecting a run loads its detections in the main area with species search, confidence filter, and the existing AnalysisTable
    • After analysis completes, the app auto-navigates to Detections and selects the new run
  • Fixed stale "Running" status — on startup, any analysis runs stuck in running state (from a crash or force-quit) are automatically marked as failed
  • Removed unused components: FilterPanel, DetectionsTable, catalog store
  • Added new RunList sidebar component and RunWithStats type with aggregated detection counts

Test plan

  • Start the app — Analysis tab shows configuration UI with file/folder selection
  • Select a file and run analysis — progress displays normally
  • On completion — app switches to Detections tab with the new run selected in the sidebar
  • Run list shows source name, model, detection count, location, date
  • Detection table works with species search and confidence slider filters
  • Click different runs in sidebar — detections update correctly
  • Navigate back to Analysis — always shows config, never results
  • Force-quit during analysis, reopen — stale run shows as "Failed" not "Running"

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Runs list view showing runs with status badges, detection counts, and location info; post-analysis now opens Detections and selects the new run.
    • Added UI translations for the Runs section.
  • Bug Fixes

    • Startup maintenance automatically marks stale/incomplete runs as failed.
  • Chores

    • Simplified Analysis/Detections UI: removed legacy filters, table and audio player components in favor of the new run-driven layout.

tphakala and others added 2 commits February 7, 2026 20:06
Separate analysis configuration from results display following a
ChatGPT/Claude conversation-history pattern:

- Analysis tab now always shows configuration (file/folder, model,
  coordinates, confidence) — never results
- Detections tab shows a sidebar of past analysis runs with a detail
  view for the selected run's detections
- After analysis completes, auto-navigate to Detections and select
  the new run

New components: RunList sidebar. Removed: FilterPanel, DetectionsTable,
catalog store (replaced by run-scoped queries).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
If the app was closed or crashed during an analysis, the run status
remains 'running' in the database forever. On startup, mark any such
stale runs as 'failed' so they display correctly in the run list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 7, 2026

Warning

Rate limit exceeded

@tphakala has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 52 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Adds a Runs list feature: backend DB queries to fetch runs with detection counts and mark stale runs failed, a new IPC channel, renderer IPC helper and UI components to list/select runs, and refactors detections UI/state to load detections per selected run.

Changes

Cohort / File(s) Summary
Translations
messages/en.json
Added 12 new translation keys for the Runs UI (titles, empty states, detection count labels, statuses).
Shared Types
shared/types.ts
Added RunWithStats interface (extends AnalysisRun) with detection_count: number and `location_name: string
DB Logic
src/main/db/runs.ts
Added markStaleRunsAsFailed() to mark running runs as failed and getRunsWithStats() to return runs joined with detection counts and location names.
Main Startup & IPC
src/main/index.ts, src/main/ipc/catalog.ts, src/preload/index.ts
Call markStaleRunsAsFailed() on startup; register catalog:get-runs IPC handler returning getRunsWithStats(); whitelist catalog:get-runs in preload allowed channels.
Renderer IPC util
src/renderer/src/lib/utils/ipc.ts
Added getRuns(): Promise<RunWithStats[]> that invokes catalog:get-runs.
App State
src/renderer/src/lib/stores/app.svelte.ts
Added `selectedRunId: number
New UI Component
src/renderer/src/lib/components/RunList.svelte
New sidebar component rendering runs list with selection callback, status badges, source, model, location and detection count.
Removed UI & Store
src/renderer/src/lib/components/DetectionsTable.svelte, src/renderer/src/lib/components/FilterPanel.svelte, src/renderer/src/lib/stores/catalog.svelte.ts, src/renderer/src/lib/components/AudioPlayer.svelte
Removed old detections table, filter panel, catalog store (load/reset detections), and audio player component; their logic/UI and exports were deleted.
Pages / UI Flow
src/renderer/src/pages/DetectionsPage.svelte, src/renderer/src/pages/AnalysisPage.svelte, src/renderer/src/App.svelte
DetectionsPage: replaced FilterPanel+DetectionsTable flow with RunList + per-run detection loading (uses getRuns and getDetections); AnalysisPage: removed table and detection-loading responsibility; App.svelte: after analysis sets activeTab to detections, assigns selectedRunId, and removed automatic loadDetections() call.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant DetectionsPage as DetectionsPage (UI)
    participant RunList as RunList (Component)
    participant IPC as Preload / IPC
    participant Main as Main Process
    participant DB as Database
    participant AnalysisTable as AnalysisTable (UI)

    User->>DetectionsPage: Open Detections page
    DetectionsPage->>IPC: getRuns()
    IPC->>Main: invoke 'catalog:get-runs'
    Main->>DB: query runs with detection counts & location
    DB-->>Main: runs data
    Main-->>IPC: RunWithStats[]
    IPC-->>DetectionsPage: RunWithStats[]
    DetectionsPage->>RunList: render runs

    User->>RunList: select run
    RunList->>DetectionsPage: onselect(runId)
    DetectionsPage->>IPC: getDetections(filter runId, paging, sort)
    IPC->>Main: invoke 'get-detections'
    Main->>DB: query detections for run
    DB-->>Main: detections
    Main-->>IPC: EnrichedDetection[]
    IPC-->>DetectionsPage: EnrichedDetection[]
    DetectionsPage->>AnalysisTable: render detections
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% 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 'feat: restructure detections view as run-based browser' accurately captures the main change—refactoring the detections interface to use a run-based selection model instead of a flat detection list.

✏️ 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 feat/detections-run-browser

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.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @tphakala, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant architectural and UI overhaul, transforming how users interact with analysis results. By creating a dedicated, run-based browser within the 'Detections' tab, it provides a more organized and intuitive way to manage and review historical analysis data. The 'Analysis' tab is now streamlined for initiating new analyses, enhancing the overall clarity and efficiency of the application's workflow.

Highlights

  • UI Restructuring: The application flow has been redesigned to clearly separate analysis configuration from results display. The 'Analysis' tab now exclusively handles configuration, while a new 'Detections' tab is dedicated to viewing results.
  • Run-Based Detections Browser: A new 'Detections' tab introduces a sidebar that lists all past analysis runs. Users can select any run from this list to view its associated detections, which can then be filtered by species and confidence.
  • Stale Run Cleanup: The application now automatically detects and marks any analysis runs that were left in a 'running' state (e.g., due to an unexpected shutdown) as 'failed' upon startup, ensuring data consistency.
  • Component Refactoring and Removal: Several legacy components, including FilterPanel, DetectionsTable, and the catalog store, have been removed. A new RunList component and RunWithStats data type were introduced to support the new run-based view and its associated statistics.
Changelog
  • messages/en.json
    • Added new localization strings for the 'Runs' feature, including titles, empty states, detection counts, and run statuses.
  • shared/types.ts
    • Introduced the RunWithStats interface, extending AnalysisRun to include detection_count and location_name for enhanced run statistics.
  • src/main/db/runs.ts
    • Implemented markStaleRunsAsFailed function to update analysis runs stuck in a 'running' state to 'failed' on application startup.
    • Added getRunsWithStats function to retrieve all analysis runs along with their aggregated detection counts and associated location names.
  • src/main/index.ts
    • Integrated the markStaleRunsAsFailed function into the application's startup sequence to ensure cleanup of incomplete runs from previous sessions.
  • src/main/ipc/catalog.ts
    • Added a new IPC handler, catalog:get-runs, to expose the getRunsWithStats function to the renderer process, allowing the UI to fetch run data.
  • src/preload/index.ts
    • Whitelisted the new catalog:get-runs IPC channel to enable secure communication between the renderer and main processes for fetching run data.
  • src/renderer/src/App.svelte
    • Removed the loadDetections import and call, as detection loading is now handled within the DetectionsPage.
    • Modified the post-analysis navigation logic to automatically set the selectedRunId and switch to the 'detections' tab upon completion of an analysis.
  • src/renderer/src/lib/components/DetectionsTable.svelte
    • Removed the DetectionsTable component, as its functionality has been refactored and integrated into the DetectionsPage using a generic AnalysisTable.
  • src/renderer/src/lib/components/FilterPanel.svelte
    • Removed the FilterPanel component, as detection filtering is now directly managed within the DetectionsPage.
  • src/renderer/src/lib/components/RunList.svelte
    • Added the new RunList component, which serves as a sidebar to display a list of analysis runs with their key details and status.
  • src/renderer/src/lib/stores/app.svelte.ts
    • Added selectedRunId to the global appState to track the currently active analysis run in the UI.
  • src/renderer/src/lib/stores/catalog.svelte.ts
    • Removed the catalog.svelte.ts store, centralizing detection loading and filtering logic within the respective page components.
  • src/renderer/src/lib/utils/ipc.ts
    • Added a new getRuns utility function to facilitate fetching analysis run data from the main process via IPC.
  • src/renderer/src/pages/AnalysisPage.svelte
    • Refactored the AnalysisPage.svelte to remove all detection results display logic, including related state, functions, and component imports (e.g., AnalysisTable, getDetections).
    • Streamlined the template to focus solely on analysis configuration, file/folder selection, model choice, and location/date settings.
  • src/renderer/src/pages/DetectionsPage.svelte
    • Completely refactored the page to act as a run-based browser, incorporating the new RunList sidebar and integrating detection filtering and display directly.
    • Implemented state management for runs, detections, and filtering parameters, along with functions to refresh runs and load detections based on the selected run and filters.
    • Added reactive effects to automatically load detections when the selected run or confidence filter changes, and to refresh the run list when navigating to the page.
Activity
  • The author, tphakala, has undertaken a significant refactoring effort to separate analysis configuration from results viewing, introducing a new run-based browsing experience.
  • New data structures and backend functions were implemented to support the tracking and retrieval of analysis runs with aggregated statistics.
  • IPC handlers and preload scripts were updated to enable secure communication for the new run-related data.
  • Frontend components were extensively modified, with some being removed and new ones introduced, to align with the redesigned UI flow.
  • Logic was added to handle stale analysis runs, marking them as failed on startup to maintain data integrity.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully restructures the application flow by separating the analysis configuration from the results view, introducing a run-based browser in the Detections tab. This is a significant improvement to the user experience. The implementation is clean, and the fix for stale 'running' statuses is a great addition. I've provided a couple of suggestions for the new DetectionsPage to improve efficiency and restore previous state management behavior for the confidence filter. Overall, this is a well-executed refactoring.

const limit = 200;
let speciesQuery = $state('');
let ignoreConfidence = $state(false);
let minConfidence = $state(0.5);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The confidence filter's state (minConfidence) is managed locally within this component. This is a change from the previous implementation where it was part of the global appState. As a result, the selected confidence value is not persisted when navigating between tabs. To restore the global nature of this filter, I suggest using appState.minConfidence instead of this local state. This would require removing this line and updating references to minConfidence throughout the component to use appState.minConfidence (e.g., in loadRunDetections at line 50, the confidence slider at line 198, and the $effect block for confidence changes at lines 115-125).

Comment on lines +110 to +111
// Refresh runs list when navigating here (e.g. after analysis completes)
void refreshRuns();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The list of analysis runs is re-fetched from the database every time the user selects a different run from the list. This is inefficient as it causes an unnecessary database query and re-render. The list of runs should only be refreshed when it's likely to have changed, for example when a new run is created.

A better approach is to only call refreshRuns() if the newly selected run is not already present in the local runs array. This will handle the case of a new analysis completing and adding a run, without the overhead of re-fetching on every click between existing runs.

      // Refresh runs list only if the selected run is not already in our list.
      // This handles new runs after analysis without re-fetching on every selection.
      if (appState.selectedRunId && !runs.some((r) => r.id === appState.selectedRunId)) {
        void refreshRuns();
      }

try {
const result = await getDetections({
run_id: appState.selectedRunId,
min_confidence: ignoreConfidence && speciesQuery ? undefined : minConfidence,

This comment was marked as outdated.

Comment on lines +102 to +109
let prevSelectedRunId: number | null = null;
$effect(() => {
if (appState.selectedRunId !== prevSelectedRunId) {
prevSelectedRunId = appState.selectedRunId;
offset = 0;
speciesQuery = '';
ignoreConfidence = false;
void loadRunDetections();

This comment was marked as outdated.

- Remove unused AudioPlayer component (was only used by deleted
  DetectionsTable)
- Remove unused formatTimeRange export from format.ts
- Use appState.minConfidence instead of local state for cross-tab
  persistence of the confidence filter
- Make ignoreConfidence checkbox work independently of species search
- Only refresh runs list when selected run isn't already loaded

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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

🤖 Fix all issues with AI agents
In `@src/renderer/src/pages/DetectionsPage.svelte`:
- Around line 116-126: The effect watching appState.minConfidence currently
calls loadRunDetections() on every intermediate slider change (variables:
prevConfidence, $effect, appState.minConfidence, loadRunDetections, offset),
causing many IPC calls while dragging; fix by debouncing or committing only on
change/end: either wrap the $effect handler so it delays calling
loadRunDetections() using a debounce timer (e.g., 200–300ms) and cancels/resets
the timer on subsequent changes, or change the slider binding so it updates a
transient value during input and only assigns to appState.minConfidence (or
triggers loadRunDetections()) on the slider's change/pointerup event; ensure
offset reset and selectedRunId check remain the same.
- Around line 100-133: The component is triggering loadRunDetections() and
refreshRuns() redundantly on mount; remove the explicit calls to
loadRunDetections() and refreshRuns() from the onMount handler and rely on the
existing $effect blocks that compare prevSelectedRunId and prevConfidence to
appState.selectedRunId and appState.minConfidence to perform the initial load
and refresh; ensure onMount keeps any other necessary initialization but does
not call loadRunDetections() or refreshRuns() to avoid the triple-fetch.
🧹 Nitpick comments (2)
src/renderer/src/pages/DetectionsPage.svelte (2)

86-92: Debounce timer not cleared on unmount.

If the component unmounts within the 250 ms window, the pending setTimeout callback will still fire and attempt to mutate destroyed state. Consider clearing it in an onDestroy (or returning a cleanup from an $effect) to be safe.


33-64: Silent error swallowing in both fetch functions.

Both refreshRuns and loadRunDetections have empty catch blocks that discard errors without any user feedback. Consider showing a toast or inline error state so users know something went wrong, especially for the detections fetch where the UI will simply appear empty.

- Initialize prevConfidence to current value so the confidence effect
  doesn't fire redundantly on mount
- Remove loadRunDetections() from onMount since the selectedRunId
  effect already handles the initial load
- Debounce confidence slider changes (200ms) to avoid rapid IPC calls
  during drag

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tphakala tphakala merged commit 7f242bc into main Feb 7, 2026
5 checks passed
@tphakala tphakala deleted the feat/detections-run-browser branch February 7, 2026 18:27
tphakala added a commit that referenced this pull request Feb 15, 2026
Issue #1 (HIGH): Ensure CPU provider always available
- Combine birda providers with default CPU and deduplicate
- Prevents losing CPU fallback if birda doesn't include it

Issue #2 (MEDIUM): Remove duplicate GpuCapabilities type
- Import GpuCapabilities from shared/types.ts in ipc.ts
- Eliminates inline type duplication
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