Skip to content

feat(ui): implement Download Details Panel - #18

Merged
mpiton merged 3 commits into
mainfrom
feat/19-download-details-panel
Apr 10, 2026
Merged

feat(ui): implement Download Details Panel#18
mpiton merged 3 commits into
mainfrom
feat/19-download-details-panel

Conversation

@mpiton

@mpiton mpiton commented Apr 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • Right sidebar panel displaying detailed info for the selected download, with 8 collapsible sections: File Info, Metrics, Segments, Speed History, Source, Integrity, Module, Logs
  • Real-time metrics from Zustand downloadStore.progressMap (speed, ETA, downloaded/total, connections) with dynamic ETA calculation
  • SVG speed sparkline sampling from the store every 2s, rendering a 2-minute polyline chart
  • Segment visualization with colored progress bars per segment and download state indicators
  • Auto-opens panel when a download is selected (selectDownload now sets detailsPanelOpen: true)
  • Integrated into DownloadsView as a flex-row split layout (table left, panel right)

New files

  • src/views/DownloadDetailsPanel/ — 9 components (panel + 8 sections) + barrel export
  • src/hooks/useDownloadDetail.ts — TanStack Query wrapper (500ms staleTime)
  • src/hooks/useSpeedHistory.ts — Speed sampling hook (2s interval, 2min window)

Modified files

  • src/stores/uiStore.tsselectDownload auto-opens details panel
  • src/views/DownloadsView/DownloadsView.tsx — Flex-row layout with panel
  • CHANGELOG.md — Added entry for Download Details Panel

Test plan

  • TypeScript strict mode: 0 errors
  • oxlint: 0 warnings, 0 errors
  • 178/178 tests passing (18 new tests for panel components + hooks)
  • Manual: select download, verify panel appears with all sections
  • Manual: watch metrics update in real-time during active download
  • Manual: close panel via X button, verify it hides
  • Manual: switch between downloads, verify panel content updates

Summary by cubic

Adds a right sidebar Download Details Panel for the selected download with real-time metrics, speed history, segments, and logs. Improves accuracy, accessibility, and keeps the header/close control visible during loading and errors.

  • New Features

    • 8 sections: File Info, Metrics, Segments, Speed History, Source, Integrity, Module, Logs.
    • Live metrics from zustand progress map with dynamic ETA.
    • 2-minute SVG speed sparkline sampled every 2s (samples immediately on mount).
    • Segment progress bars and a logs viewer (last 20 lines).
    • Auto-opens on selection; closable via X; integrated as a split layout in DownloadsView.
    • Hooks: useDownloadDetail (500ms stale, enabled guard) and useSpeedHistory (2s sampling, 2-min window).
  • Bug Fixes

    • Progress clamped to [0, 100]; connections count filters active segments only.
    • Integrity shows algorithm/status only when a checksum is present.
    • Logs handle loading state separately from empty state; header and close button stay visible in loading/error states.
    • File Info MIME detection handles extensionless filenames.
    • Close button has an aria-label; empty state includes a close control.

Written for commit 05c4588. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Right-side Download Details panel with eight sections (File Info, Metrics, Segments, Speed History, Source, Integrity, Module, Logs); auto-opens on selection and includes a close control.
    • Real-time speed/ETA/progress updates, per-segment colored progress bars, 2-minute speed sparkline sampled every 2s, MIME detection, tooltips, checksum status, and scrollable last-20 logs.
  • Integration
    • Panel added alongside the downloads list in the main view.
  • Tests
    • New test suites covering hooks and all panel sections.

Right sidebar panel showing detailed info for the selected download:
8 sections (File Info, Metrics, Segments, Speed History, Source,
Integrity, Module, Logs) with real-time updates from Zustand store,
SVG speed sparkline, segment visualization, and scrollable logs.
@github-actions github-actions Bot added documentation Improvements or additions to documentation frontend labels Apr 10, 2026
@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Added a right-side Download Details Panel with eight sections (file info, metrics, segments, speed history, source, integrity, module, logs). Introduced hooks useDownloadDetail and useSpeedHistory, tests for components/hooks, and integrated the panel into DownloadsView; selecting a download now auto-opens the panel.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Documented the new Download Details Panel and related hooks/behavior.
Core hooks & tests
src/hooks/useDownloadDetail.ts, src/hooks/useSpeedHistory.ts, src/hooks/__tests__/*
Added useDownloadDetail (tauri query, 500ms staleTime) and useSpeedHistory (2s sampling, 2min capped history) plus unit tests mocking Tauri and store state.
Panel entry & integration
src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx, src/views/DownloadDetailsPanel/index.ts, src/views/DownloadsView/DownloadsView.tsx
New panel component and re-export; integrated into DownloadsView layout so panel renders alongside table.
Section components
src/views/DownloadDetailsPanel/FileInfoSection.tsx, .../MetricsSection.tsx, .../SegmentVisualization.tsx, .../SpeedSparkline.tsx, .../SourceInfoSection.tsx, .../IntegritySection.tsx, .../ModuleSection.tsx, .../LogsSection.tsx
Eight focused components added: MIME/type detection and tooltips, live metrics (store fallback), per-segment progress bars, SVG speed sparkline from sampled history, source parsing, integrity checksum display, module/account, and scrollable logs via IPC query.
Panel tests
src/views/DownloadDetailsPanel/__tests__/*
Comprehensive tests for panel rendering, sections, sampling/streaming states, and store/Tauri interactions.
UI store change
src/stores/uiStore.ts
selectDownload(id) now also toggles detailsPanelOpen (opens when id provided, closes when null).

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as DownloadsView
    participant Store as uiStore / downloadStore
    participant Panel as DownloadDetailsPanel
    participant Hook as useDownloadDetail
    participant SpeedHook as useSpeedHistory
    participant Tauri as Tauri API

    User->>UI: Click download row
    UI->>Store: selectDownload(id)
    Store->>Store: selectedDownloadId = id\ndetailsPanelOpen = true
    Store-->>Panel: state update (selectedDownloadId, detailsPanelOpen)
    Panel->>Hook: useDownloadDetail(downloadId)
    Hook->>Tauri: invoke('query_download_detail', { id })
    Tauri-->>Hook: DownloadDetailView
    Hook-->>Panel: detail data
    Panel->>Panel: render sections (FileInfo, Metrics, Segments, Speed, Source, Integrity, Module, Logs)
    Panel->>SpeedHook: useSpeedHistory(downloadId)
    SpeedHook->>Store: read progressMap every 2s
    Store-->>SpeedHook: progress entry
    SpeedHook-->>Panel: speed samples
    Panel->>Panel: update SpeedSparkline
    User->>Panel: Click close (X)
    Panel->>Store: selectDownload(null)
    Store->>Store: selectedDownloadId = null\ndetailsPanelOpen = false
    Panel->>Panel: unmount
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

ui

Poem

🐰 A drawer fluffs open with a click,
Segments, speeds, and logs so quick—
Checksums hum and sparklines gleam,
Files and hosts hop through the stream.
Click a download, nibble the view!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 change: implementation of a Download Details Panel UI component as a new feature.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/19-download-details-panel

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

@greptile-apps

greptile-apps Bot commented Apr 10, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces a Download Details Panel — a fixed right-side sidebar with 8 collapsible sections (File Info, Metrics, Segments, Speed History, Source, Integrity, Module, Logs) — plus two supporting hooks (useDownloadDetail, useSpeedHistory). The integration is clean: selectDownload now auto-opens the panel, and DownloadsView adopts a flex-row split layout.

A couple of issues are worth addressing before merge:

  • Hardcoded "SHA-256" in IntegritySection — the label is hard-coded with no corresponding field in DownloadDetailView, so it will display incorrect algorithm information if the backend uses MD5, SHA-1, or similar.
  • "Connections" metric shows total segment count, not active (Downloading-state) connections, which conflicts with what users expect from that label in a download manager.

Confidence Score: 4/5

Mostly safe to merge; one P1 concern (hardcoded SHA-256) should be fixed before shipping to avoid showing users incorrect integrity metadata.

The implementation is solid overall — hooks are correct, the store change is clean, and all 178 tests pass. The hardcoded SHA-256 algorithm label in IntegritySection is a P1 because it will actively display wrong information to users if the backend ever uses a different algorithm, and the DownloadDetailView type provides no field to resolve the actual algorithm. The Connections mislabelling is a P2 cosmetic/UX issue.

src/views/DownloadDetailsPanel/IntegritySection.tsx — hardcoded SHA-256 algorithm label needs to be removed or made conditional on actual data.

Important Files Changed

Filename Overview
src/views/DownloadDetailsPanel/IntegritySection.tsx Displays a hardcoded "SHA-256" algorithm label that has no backing field in DownloadDetailView, risking incorrect information for users if other algorithms are used.
src/views/DownloadDetailsPanel/MetricsSection.tsx "Connections" label shows total segment count instead of active (Downloading-state) segments; ETA and progress math is otherwise correct.
src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx Well-structured panel with loading, empty, and error states; defensive "Select a download" aside has no close button but is unreachable in normal UI flow.
src/hooks/useSpeedHistory.ts Correct interval-based sampling with ref accumulation; resets cleanly on downloadId change and clears interval on unmount.
src/views/DownloadDetailsPanel/SpeedSparkline.tsx SVG polyline chart is correctly normalised; hardcoded WIDTH=300 fits the w-80 panel; handles fewer than 2 samples gracefully.
src/views/DownloadDetailsPanel/SegmentVisualization.tsx computeProgress correctly guards zero/null totalBytes; totalBytes param is only used as a guard, not in the core formula, which is a minor clarity issue.
src/stores/uiStore.ts selectDownload now sets detailsPanelOpen based on whether id is non-null; logic is consistent and the X-button calling setDetailsPanelOpen(false) without clearing selectedDownloadId is intentional.
src/views/DownloadsView/DownloadsView.tsx Clean flex-row integration of DownloadDetailsPanel alongside the existing table layout.
src/hooks/useDownloadDetail.ts Thin TanStack Query wrapper with 500 ms staleTime; correct and minimal.
src/views/DownloadDetailsPanel/SourceInfoSection.tsx URL parsing with try/catch fallback is safe; disabled checkbox for resumeSupported lacks an aria-label.

Sequence Diagram

sequenceDiagram
    participant User
    participant DownloadsTable
    participant uiStore
    participant DownloadDetailsPanel
    participant useDownloadDetail
    participant useSpeedHistory
    participant TauriBackend

    User->>DownloadsTable: click row
    DownloadsTable->>uiStore: selectDownload(id)
    uiStore-->>uiStore: set selectedDownloadId=id, detailsPanelOpen=true

    uiStore-->>DownloadDetailsPanel: detailsPanelOpen=true, selectedDownloadId=id
    DownloadDetailsPanel->>useDownloadDetail: useDownloadDetail(id)
    useDownloadDetail->>TauriBackend: invoke(query_download_detail, {id})
    TauriBackend-->>useDownloadDetail: DownloadDetailView
    useDownloadDetail-->>DownloadDetailsPanel: data

    DownloadDetailsPanel->>useSpeedHistory: useSpeedHistory(id)
    loop every 2s
        useSpeedHistory->>uiStore: downloadStore.getState().progressMap[id]
        uiStore-->>useSpeedHistory: SpeedSample
        useSpeedHistory-->>DownloadDetailsPanel: SpeedSample[]
    end

    User->>DownloadDetailsPanel: click X
    DownloadDetailsPanel->>uiStore: setDetailsPanelOpen(false)
    uiStore-->>DownloadDetailsPanel: detailsPanelOpen=false, renders null
Loading

Fix All in Claude Code

Reviews (1): Last reviewed commit: "feat(ui): implement Download Details Pan..." | Re-trigger Greptile

Comment on lines +18 to +20
</div>
<div>
<p className="text-muted-foreground">Expected Hash</p>

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 Hardcoded algorithm label is incorrect

"SHA-256" is always shown regardless of what algorithm the backend actually uses. DownloadDetailView has no checksumAlgorithm field, so this will display wrong information whenever the backend uses MD5, SHA-1, or any other algorithm. At minimum, show "—" when the algorithm is unknown, or derive it from the data.

Suggested change
</div>
<div>
<p className="text-muted-foreground">Expected Hash</p>
<div>
<p className="text-muted-foreground">Algorithm</p>
<p className="font-mono"></p>
</div>

Fix in Claude Code

Comment on lines +50 to +53
<div className="text-muted-foreground">Connections</div>
<div className="font-mono font-semibold">{download.segments.length}</div>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 "Connections" shows total segments, not active connections

download.segments.length is the total segment count including Completed, Pending, and Error segments. In download manager UIs "Connections" conventionally means currently active connections — i.e. segments in the 'Downloading' state. Showing the total count overstates the number of live connections for any non-trivially progressed download.

Suggested change
<div className="text-muted-foreground">Connections</div>
<div className="font-mono font-semibold">{download.segments.length}</div>
</div>
<div className="col-span-2 rounded bg-background p-2">
<div className="text-muted-foreground">Connections</div>
<div className="font-mono font-semibold">
{download.segments.filter((s) => s.state === 'Downloading').length}
</div>
</div>

Fix in Claude Code

Comment on lines +22 to +27
if (!selectedDownloadId) {
return (
<aside className="w-80 shrink-0 border-l bg-muted/30 p-4 text-center text-sm text-muted-foreground">
Select a download to view details
</aside>
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Empty-state aside has no close/dismiss button

When detailsPanelOpen is true but selectedDownloadId is null, the panel renders with no way to dismiss it. This state is unreachable today (because selectDownload sets both atomically), but the defensive branch exists — so it should be consistent with the rest of the panel UX and include a close button to avoid trapping users if the state is ever reachable in the future.

Fix in Claude Code

Comment on lines +53 to +60
<p className="text-muted-foreground">Resume Supported</p>
<input
type="checkbox"
disabled
checked={download.resumeSupported}
readOnly
className="mt-1"
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Unlabelled checkbox is inaccessible to screen readers

A bare <input type="checkbox" disabled /> without an associated <label> or aria-label won't be announced meaningfully by assistive technology. Consider replacing it with a visible text indicator or adding an aria-label.

Suggested change
<p className="text-muted-foreground">Resume Supported</p>
<input
type="checkbox"
disabled
checked={download.resumeSupported}
readOnly
className="mt-1"
/>
<input
type="checkbox"
disabled
checked={download.resumeSupported}
readOnly
aria-label="Resume supported"
className="mt-1"
/>

Fix in Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (4)
src/hooks/useSpeedHistory.ts (1)

21-33: Sample once immediately to avoid initial 2s blank history.

Current logic waits one interval before first datapoint. Triggering one immediate sample improves perceived responsiveness when opening/switching details.

♻️ Suggested refactor
-    const interval = setInterval(() => {
+    const sample = () => {
       const progress = useDownloadStore.getState().progressMap[downloadId];
       const speed = progress?.speedBytesPerSec ?? 0;
       const now = Date.now();
       const cutoff = now - MAX_AGE_MS;
@@
       setSamples([...samplesRef.current]);
-    }, SAMPLE_INTERVAL_MS);
+    };
+
+    sample();
+    const interval = setInterval(sample, SAMPLE_INTERVAL_MS);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/useSpeedHistory.ts` around lines 21 - 33, The hook currently waits
SAMPLE_INTERVAL_MS before the first datapoint; immediately sample once before
starting the setInterval to avoid a 2s blank history: extract the sampling logic
that reads useDownloadStore.getState().progressMap[downloadId], computes now,
cutoff (MAX_AGE_MS), updates samplesRef.current (filter by s.time > cutoff,
append {time: now, speed}, slice(-MAX_SAMPLES)) and calls
setSamples([...samplesRef.current]) into a small helper (or call the same block)
and invoke it once immediately, then start the existing setInterval that repeats
the same logic every SAMPLE_INTERVAL_MS; keep references to samplesRef,
downloadId, MAX_AGE_MS, MAX_SAMPLES, and setSamples unchanged.
src/hooks/useDownloadDetail.ts (1)

5-10: Consider guarding against empty downloadId.

If downloadId is an empty string, the query will still execute and likely fail or return unexpected results. Consider adding an enabled option to prevent unnecessary requests.

♻️ Proposed fix
 export function useDownloadDetail(downloadId: string) {
   return useTauriQuery<DownloadDetailView>(
     'query_download_detail',
     { id: downloadId },
-    { queryKey: downloadQueries.detail(downloadId), staleTime: 500 },
+    { queryKey: downloadQueries.detail(downloadId), staleTime: 500, enabled: !!downloadId },
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/useDownloadDetail.ts` around lines 5 - 10, The hook
useDownloadDetail currently runs the useTauriQuery even when downloadId is
empty; update useDownloadDetail to prevent the query from executing for
falsy/empty ids by passing an enabled flag (e.g., enabled: Boolean(downloadId))
into the options object passed to useTauriQuery (preserving existing staleTime
and queryKey usage like downloadQueries.detail(downloadId)); reference
useDownloadDetail, useTauriQuery, downloadQueries.detail and DownloadDetailView
when making the change.
src/views/DownloadDetailsPanel/SourceInfoSection.tsx (1)

54-60: Redundant attributes on checkbox; consider a non-interactive indicator.

The readOnly attribute is redundant when disabled is already set. Additionally, using a checkbox for a read-only boolean display is unconventional—a text label or icon might be clearer.

♻️ Proposed fix using text indicator
         <div>
           <p className="text-muted-foreground">Resume Supported</p>
-          <input
-            type="checkbox"
-            disabled
-            checked={download.resumeSupported}
-            readOnly
-            className="mt-1"
-          />
+          <p className="font-mono">{download.resumeSupported ? 'Yes' : 'No'}</p>
         </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/views/DownloadDetailsPanel/SourceInfoSection.tsx` around lines 54 - 60,
In SourceInfoSection replace the disabled checkbox input used to show
download.resumeSupported with a non-interactive indicator: remove the redundant
readOnly attribute (if you keep the input) and preferably replace the <input
type="checkbox" ... /> with a plain text/icon element (e.g., a <span> or an SVG
icon) that displays "Supported"/"Not supported" or a check/x symbol based on
download.resumeSupported; ensure accessibility by adding an aria-label or
role="status" so screen readers can read the state, and update any className
styling applied to the original input to the new element.
src/views/DownloadDetailsPanel/IntegritySection.tsx (1)

15-18: Hardcoded algorithm may not reflect actual checksum type.

The algorithm is fixed to "SHA-256", but if the backend supports multiple hash algorithms (MD5, SHA-1, etc.), this could be misleading. Consider deriving the algorithm from the data if available, or clarifying this is an assumed default.

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

In `@src/views/DownloadDetailsPanel/IntegritySection.tsx` around lines 15 - 18,
The UI in IntegritySection currently hardcodes "SHA-256"; update the component
to read the actual algorithm from the incoming data (e.g., a prop or object like
integrity.algorithm or checksumAlgorithm) and render that value, falling back to
"SHA-256" only if no algorithm is provided; update any related prop types or
interface (IntegritySection props) so the algorithm field is optional and used
in the display, and ensure the displayed label shows the resolved algorithm
string rather than a hardcoded literal.
🤖 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/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx`:
- Around line 71-73: The close button in DownloadDetailsPanel is icon-only and
lacks an accessible name; update the Button (the element rendering <X
className="size-3.5" /> and using onClose) to provide an accessible label—e.g.,
add an aria-label like "Close" or include a visually-hidden text node inside the
Button—so assistive technologies can announce the button’s purpose.

In `@src/views/DownloadDetailsPanel/LogsSection.tsx`:
- Around line 9-21: The component currently treats unresolved query data as an
empty state by checking logs directly; update the useTauriQuery call to also
destructure the loading state (e.g., isLoading or isFetching) and change the
render logic in LogsSection (where logs is used) to show a loading indicator or
placeholder when isLoading is true, and only render the "No logs" message when
isLoading is false and logs is empty; reference the useTauriQuery invocation and
the logs variable in your change and ensure the conditional branch inside the
ScrollArea checks isLoading before deciding between loading UI, "No logs", or
the logs list.

In `@src/views/DownloadDetailsPanel/MetricsSection.tsx`:
- Around line 16-17: The computed progressPercent can exceed 0-100 and should be
clamped before render: wrap the existing calculation for progressPercent (the
expression using total, downloaded, and download.progressPercent) with a clamp
to the [0,100] range (e.g., Math.min(Math.max(..., 0), 100)), and apply the same
clamping to the other progress computation referenced at the second occurrence
(around the usage at line ~56) so both places always output a value between 0
and 100.

---

Nitpick comments:
In `@src/hooks/useDownloadDetail.ts`:
- Around line 5-10: The hook useDownloadDetail currently runs the useTauriQuery
even when downloadId is empty; update useDownloadDetail to prevent the query
from executing for falsy/empty ids by passing an enabled flag (e.g., enabled:
Boolean(downloadId)) into the options object passed to useTauriQuery (preserving
existing staleTime and queryKey usage like downloadQueries.detail(downloadId));
reference useDownloadDetail, useTauriQuery, downloadQueries.detail and
DownloadDetailView when making the change.

In `@src/hooks/useSpeedHistory.ts`:
- Around line 21-33: The hook currently waits SAMPLE_INTERVAL_MS before the
first datapoint; immediately sample once before starting the setInterval to
avoid a 2s blank history: extract the sampling logic that reads
useDownloadStore.getState().progressMap[downloadId], computes now, cutoff
(MAX_AGE_MS), updates samplesRef.current (filter by s.time > cutoff, append
{time: now, speed}, slice(-MAX_SAMPLES)) and calls
setSamples([...samplesRef.current]) into a small helper (or call the same block)
and invoke it once immediately, then start the existing setInterval that repeats
the same logic every SAMPLE_INTERVAL_MS; keep references to samplesRef,
downloadId, MAX_AGE_MS, MAX_SAMPLES, and setSamples unchanged.

In `@src/views/DownloadDetailsPanel/IntegritySection.tsx`:
- Around line 15-18: The UI in IntegritySection currently hardcodes "SHA-256";
update the component to read the actual algorithm from the incoming data (e.g.,
a prop or object like integrity.algorithm or checksumAlgorithm) and render that
value, falling back to "SHA-256" only if no algorithm is provided; update any
related prop types or interface (IntegritySection props) so the algorithm field
is optional and used in the display, and ensure the displayed label shows the
resolved algorithm string rather than a hardcoded literal.

In `@src/views/DownloadDetailsPanel/SourceInfoSection.tsx`:
- Around line 54-60: In SourceInfoSection replace the disabled checkbox input
used to show download.resumeSupported with a non-interactive indicator: remove
the redundant readOnly attribute (if you keep the input) and preferably replace
the <input type="checkbox" ... /> with a plain text/icon element (e.g., a <span>
or an SVG icon) that displays "Supported"/"Not supported" or a check/x symbol
based on download.resumeSupported; ensure accessibility by adding an aria-label
or role="status" so screen readers can read the state, and update any className
styling applied to the original input to the new element.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a75b1290-7a0d-4959-8910-8c46136f7b16

📥 Commits

Reviewing files that changed from the base of the PR and between a987dd7 and 9b0c084.

📒 Files selected for processing (23)
  • CHANGELOG.md
  • src/hooks/__tests__/useDownloadDetail.test.ts
  • src/hooks/__tests__/useSpeedHistory.test.ts
  • src/hooks/useDownloadDetail.ts
  • src/hooks/useSpeedHistory.ts
  • src/stores/uiStore.ts
  • src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx
  • src/views/DownloadDetailsPanel/FileInfoSection.tsx
  • src/views/DownloadDetailsPanel/IntegritySection.tsx
  • src/views/DownloadDetailsPanel/LogsSection.tsx
  • src/views/DownloadDetailsPanel/MetricsSection.tsx
  • src/views/DownloadDetailsPanel/ModuleSection.tsx
  • src/views/DownloadDetailsPanel/SegmentVisualization.tsx
  • src/views/DownloadDetailsPanel/SourceInfoSection.tsx
  • src/views/DownloadDetailsPanel/SpeedSparkline.tsx
  • src/views/DownloadDetailsPanel/__tests__/DownloadDetailsPanel.test.tsx
  • src/views/DownloadDetailsPanel/__tests__/FileInfoSection.test.tsx
  • src/views/DownloadDetailsPanel/__tests__/LogsSection.test.tsx
  • src/views/DownloadDetailsPanel/__tests__/MetricsSection.test.tsx
  • src/views/DownloadDetailsPanel/__tests__/SegmentVisualization.test.tsx
  • src/views/DownloadDetailsPanel/__tests__/SpeedSparkline.test.tsx
  • src/views/DownloadDetailsPanel/index.ts
  • src/views/DownloadsView/DownloadsView.tsx

Comment thread src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx Outdated
Comment thread src/views/DownloadDetailsPanel/LogsSection.tsx Outdated
Comment on lines +16 to +17
const progressPercent =
total && total > 0 ? (downloaded / total) * 100 : download.progressPercent;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clamp computed progress to [0, 100] before rendering.

At Line 16-17, transient data can produce values above 100. Clamping avoids visual overflow and keeps the progress bar stable.

Suggested fix
-  const progressPercent =
-    total && total > 0 ? (downloaded / total) * 100 : download.progressPercent;
+  const rawProgressPercent =
+    total && total > 0 ? (downloaded / total) * 100 : download.progressPercent;
+  const progressPercent = Math.max(0, Math.min(100, rawProgressPercent));

Also applies to: 56-56

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

In `@src/views/DownloadDetailsPanel/MetricsSection.tsx` around lines 16 - 17, The
computed progressPercent can exceed 0-100 and should be clamped before render:
wrap the existing calculation for progressPercent (the expression using total,
downloaded, and download.progressPercent) with a clamp to the [0,100] range
(e.g., Math.min(Math.max(..., 0), 100)), and apply the same clamping to the
other progress computation referenced at the second occurrence (around the usage
at line ~56) so both places always output a value between 0 and 100.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 23 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/views/DownloadDetailsPanel/MetricsSection.tsx">

<violation number="1" location="src/views/DownloadDetailsPanel/MetricsSection.tsx:51">
P2: The "Connections" value should represent active connections, but this counts every segment. Filter to `Downloading` segments so the metric reflects live connections.</violation>
</file>

<file name="src/views/DownloadDetailsPanel/FileInfoSection.tsx">

<violation number="1" location="src/views/DownloadDetailsPanel/FileInfoSection.tsx:10">
P2: Extension parsing treats filenames without `.` as if the whole name were an extension, producing incorrect MIME values (e.g. `README` -> `application/readme`).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/views/DownloadDetailsPanel/MetricsSection.tsx Outdated
Comment thread src/views/DownloadDetailsPanel/FileInfoSection.tsx Outdated
- IntegritySection: show algorithm only when checksum is present
- MetricsSection: clamp progressPercent to [0,100], filter active connections
- DownloadDetailsPanel: add close button to empty state, aria-label on close
- SourceInfoSection: replace inaccessible checkbox with Yes/No text
- LogsSection: handle loading state separately from empty state
- FileInfoSection: fix MIME detection for extensionless filenames
- useSpeedHistory: sample immediately on mount (avoid 2s blank)
- useDownloadDetail: add enabled guard for empty downloadId

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx`:
- Around line 55-73: The panel header and close control are being removed in the
isLoading and !detail branches; always render the DownloadDetailsPanel header
(and its close button) outside those early returns and only conditionally render
the body content. Move the header JSX (the element that contains the close
control) above the isLoading/detail checks inside the DownloadDetailsPanel
component, keep the loading skeleton when isLoading is true, show a distinct
error message when a fetch error exists (use the existing error/fetchError prop
or state if available, or add one) instead of conflating it with "Download not
found", and only show "Download not found" when the fetch succeeded but returned
no detail. Ensure references to isLoading, detail, and the header/close button
JSX (the header element) are updated accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fcdc300e-22bc-4194-af41-bbb3c6b95dc1

📥 Commits

Reviewing files that changed from the base of the PR and between 9b0c084 and ecae7bd.

📒 Files selected for processing (10)
  • src/hooks/__tests__/useSpeedHistory.test.ts
  • src/hooks/useDownloadDetail.ts
  • src/hooks/useSpeedHistory.ts
  • src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx
  • src/views/DownloadDetailsPanel/FileInfoSection.tsx
  • src/views/DownloadDetailsPanel/IntegritySection.tsx
  • src/views/DownloadDetailsPanel/LogsSection.tsx
  • src/views/DownloadDetailsPanel/MetricsSection.tsx
  • src/views/DownloadDetailsPanel/SourceInfoSection.tsx
  • src/views/DownloadDetailsPanel/__tests__/DownloadDetailsPanel.test.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/views/DownloadDetailsPanel/SourceInfoSection.tsx
  • src/views/DownloadDetailsPanel/IntegritySection.tsx
  • src/hooks/tests/useSpeedHistory.test.ts
  • src/views/DownloadDetailsPanel/tests/DownloadDetailsPanel.test.tsx
  • src/views/DownloadDetailsPanel/LogsSection.tsx
  • src/hooks/useDownloadDetail.ts
  • src/hooks/useSpeedHistory.ts
  • src/views/DownloadDetailsPanel/MetricsSection.tsx
  • src/views/DownloadDetailsPanel/FileInfoSection.tsx

Comment thread src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx (1)

25-30: Optional: extract duplicated panel header into a shared subcomponent.

The header markup is duplicated in two places; extracting it would reduce drift risk for future tweaks (title, button props, a11y updates).

♻️ Suggested refactor
+function DetailsPanelHeader({ onClose }: { onClose: () => void }) {
+  return (
+    <div className="flex items-center justify-between border-b px-4 py-2">
+      <h2 className="text-sm font-semibold">Details</h2>
+      <Button variant="ghost" size="icon" className="h-7 w-7" aria-label="Close details panel" onClick={onClose}>
+        <X className="size-3.5" />
+      </Button>
+    </div>
+  );
+}
+
 export function DownloadDetailsPanel() {
@@
-        <div className="flex items-center justify-between border-b px-4 py-2">
-          <h2 className="text-sm font-semibold">Details</h2>
-          <Button variant="ghost" size="icon" className="h-7 w-7" aria-label="Close details panel" onClick={() => setDetailsPanelOpen(false)}>
-            <X className="size-3.5" />
-          </Button>
-        </div>
+        <DetailsPanelHeader onClose={() => setDetailsPanelOpen(false)} />
@@
-      <div className="flex items-center justify-between border-b px-4 py-2">
-        <h2 className="text-sm font-semibold">Details</h2>
-        <Button variant="ghost" size="icon" className="h-7 w-7" aria-label="Close details panel" onClick={onClose}>
-          <X className="size-3.5" />
-        </Button>
-      </div>
+      <DetailsPanelHeader onClose={onClose} />

Also applies to: 57-62

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

In `@src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx` around lines 25 -
30, The header markup in DownloadDetailsPanel is duplicated; extract it into a
small shared subcomponent (e.g., PanelHeader) and replace both occurrences to
avoid drift: create a PanelHeader that accepts props for title (string), onClose
(callback) and optional ariaLabel/button props, move the div with h2 and the
Button/X icon into that component, and update DownloadDetailsPanel to render
<PanelHeader title="Details" onClose={() => setDetailsPanelOpen(false)} /> (and
the second location similarly) so title, Button props, and accessibility updates
are centralized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx`:
- Around line 25-30: The header markup in DownloadDetailsPanel is duplicated;
extract it into a small shared subcomponent (e.g., PanelHeader) and replace both
occurrences to avoid drift: create a PanelHeader that accepts props for title
(string), onClose (callback) and optional ariaLabel/button props, move the div
with h2 and the Button/X icon into that component, and update
DownloadDetailsPanel to render <PanelHeader title="Details" onClose={() =>
setDetailsPanelOpen(false)} /> (and the second location similarly) so title,
Button props, and accessibility updates are centralized.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bff6e77e-1336-4b19-b4ad-f39422ada3ed

📥 Commits

Reviewing files that changed from the base of the PR and between ecae7bd and 05c4588.

📒 Files selected for processing (1)
  • src/views/DownloadDetailsPanel/DownloadDetailsPanel.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant