Merged
Conversation
Adds a table-based compact view for torrents with: - Table layout with columns: Name, Progress, Down, Up, ETA, Peers - Action bar with bulk Resume/Pause/Delete buttons - Bottom detail pane with Overview/Files/Peers tabs - Single and multi-select support via checkboxes - View mode toggle (persisted to localStorage) - Defaults to compact mode on large screens (>=1024px) New files: - stores/uiStore.ts - view mode and selection state - hooks/useIsLargeScreen.ts - responsive breakpoint hook - components/compact/* - table, action bar, detail pane, tabs - components/ViewModeToggle.tsx - mode switch button Co-Authored-By: Claude Opus 4.5 <[email protected]>
Documents the webui codebase structure, patterns, and common tasks to help future Claude sessions work more efficiently with less context-gathering. Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add peer stats API types (PeerStatsSnapshot, PeerStats, PeerCounters)
- Add getPeerStats() API method for /torrents/{id}/peer_stats endpoint
- Replace large stat cards with compact inline badges
- Implement sortable table with IP, connection type, speeds, and totals
- Compute download/upload speeds in JS from byte deltas between polls
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add clickable column headers (ID, Name, Progress, Down, Up, ETA, Peers) - Default sort by ID descending (newest first) - Persist sort preference to localStorage - Extract reusable SortIcon component shared with PeersTab - Add ID column visible to the left of Name Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Backend: Add total_pieces field to TorrentDetailsResponse
- Backend: Modify /torrents/{id}/haves to return binary bitmap when
Accept: application/octet-stream header is present
- Frontend: Add PiecesCanvas component that renders piece bitmap as
a compact horizontal bar with green (have) and gray (missing) colors
- Frontend: Integrate into OverviewTab in CompactUI
The visualization adapts to piece count: few pieces get rectangles,
many pieces (thousands) aggregate into per-pixel columns with partial
completion shown in light green.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add keyboard navigation: up/down arrows move selection, shift-click selects a range of torrents - Make details pane divider draggable with height persisted to localStorage - Improve pause/resume: refresh after each operation for immediate feedback, skip already paused/live torrents - Average peer speeds over 5 seconds instead of just last poll delta Co-Authored-By: Claude Opus 4.5 <[email protected]>
Use /torrents?with_stats=true to fetch all torrent data in a single call instead of polling individual details/stats endpoints for each torrent. This reduces HTTP calls from 2N to 1 per polling interval. - Add TorrentListItem type for bulk response with embedded stats - Update listTorrents API to support withStats parameter - Refactor components to use store data instead of individual fetching - Implement adaptive polling (1s for active torrents, 5s otherwise) - Fetch file details lazily only when extended view is opened - Remove unused torrentDataCache from uiStore - Fix React warning about setState during render Co-Authored-By: Claude Opus 4.5 <[email protected]>
This was referenced Jan 12, 2026
Closed
- Add GET /torrents/limits endpoint to read current rate limits - Add getLimits/setLimits API methods to webui http-api - Create TabbedConfigModal component for reusable tabbed config dialogs - Create RateLimitsTab component shared between desktop and webui - Add configure button to webui with Rate Limits and Other tabs - Refactor desktop configure.tsx to use shared TabbedConfigModal Desktop shows full 6-tab config (requires server restart), while webui shows rate limits (live API) plus an "Other" tab explaining CLI config. Co-Authored-By: Claude Opus 4.5 <[email protected]>
- OverviewTab now takes TorrentListItem directly from the store (no API call needed) - DetailPane caches TorrentDetails per torrent ID - Details are only fetched when Files tab is clicked (not on torrent selection) - This avoids unnecessary API calls for the Overview and Peers tabs Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Added detailsCache, getDetails, setDetails to torrentStore (pure cache) - Both CardLayout and CompactLayout now share the same cache - Components fetch with loopUntilSuccess and store results via setDetails - TorrentCardContent now takes TorrentListItem directly Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Simplify CSS class naming: text-text is now default (via body style), text-text-secondary → text-secondary, text-text-tertiary → text-tertiary, border-border → border-divider - Add explicit --color-divider CSS vars for proper dark mode support - Fix PiecesCanvas missing pieces color (use surface-sunken instead of border) - Deduplicate TorrentTable sorting logic with getSortValue() helper - Remove duplicate column width classes from TorrentTableRow (th controls width) - Fix typo: ext-text-secondary → text-secondary Co-Authored-By: Claude Opus 4.5 <[email protected]>
Fixes desktop styling after CSS variable renames by importing the shared globals.css from webui, which includes all color definitions and base styles. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Read CSS custom properties from document.body instead of document.documentElement since the .dark class is applied to body. Also use --color-divider instead of --color-surface-sunken for missing pieces as it provides better visibility in dark mode. Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add mock API with 1000 generated torrents (npm run dev:mock on port 3032) - ~30 active torrents, rest paused, with simulated progress - Stable peer IPs with incrementing counters for speed calculations - Fix table columns wrapping by adding whitespace-nowrap Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Compact layout: search in ActionBar (always visible) - Card layout: search shown when > 10 torrents - Uses CSS visibility instead of filtering for performance - Debounced input (150ms) with clear button - Keyboard nav and select-all respect search filter Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add status filter to both views (All/Downloading/Seeding/Paused/Error) - Add sort dropdown to card view (column + direction) - Extract shared filter/sort utilities to helper/torrentFilters.ts - Add performance guidelines to CLAUDE.md - Uses visibility-based filtering for performance Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ON-COMPLEX] Performance improvement for 1000+ torrents: - LCP: 1,175ms -> 141ms (8x faster) - DOM elements: 44,228 -> ~500 (99% reduction) Both card and table views now use react-window virtualization. See architecture/virtualization.md for implementation details and hacks. Key changes: - CardLayout: FixedSizeList with AutoSizer, hidden scrollbar - TorrentTable: itemData pattern to prevent Row flickering - TorrentTableRow: Nested table structure for column alignment - Added hide-scrollbar CSS utility Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace inline extended view with a modal that uses existing DetailPane and ActionBar components. This fixes two issues with virtualization: - Dynamic height problem (modal is overlay, card stays fixed height) - State reset on refresh (modal state stored in uiStore) The modal is rendered once in CardLayout instead of per-card to avoid remounting on list refresh. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Define --border-color-* CSS variables directly in :root and .dark with actual color values, rather than using var(--color-*) in @theme which gets resolved at compile time. This ensures border-primary, border-divider etc. utilities work correctly in both light and dark modes. Also removes the global border-color rule that was causing CSS cascade layer conflicts with Tailwind utilities. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Unify tab styling between DetailPane and TabbedConfigModal by creating a reusable Tabs.tsx component with TabButton and TabList exports. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove the SEARCH_THRESHOLD requirement that only showed the search input, status filter, and sort dropdown when there were >10 torrents. Co-Authored-By: Claude Opus 4.5 <[email protected]>
…tems react-virtuoso measures item heights dynamically, which fixes the poor mobile experience where card heights vary significantly. No more fixed CARD_HEIGHT or ROW_HEIGHT constants needed. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move padding from the scroll container to individual card items so the scrollbar appears at the right edge of the screen rather than next to the torrent cards. Also removes the hide-scrollbar utility class. Co-Authored-By: Claude Opus 4.5 <[email protected]>
…to mock - Make modals responsive: full width with margins on mobile, max-width on larger screens - Truncate long titles in modal header so close button is always accessible - Increase close button tap target size for mobile usability - Add long torrent names to mock API for testing UI with realistic scene-style names Co-Authored-By: Claude Opus 4.5 <[email protected]>
Settings like view mode, sort order, and panel height are no longer persisted across sessions. They reset to sensible defaults on reload. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Set up npm scripts to format TypeScript/TSX files: - npm run format: format all files - npm run format:check: check without writing Updated CLAUDE.md files with instructions to always run prettier after modifying webui/desktop code.
Capture selected torrents when opening the modal instead of deriving from live selectedTorrentIds state. This prevents the modal from receiving an empty torrents array when clearSelection() is called during deletion, which would cause it to return null before close() could be called.
- Remove flex-wrap to prevent wrapping to 2 lines on narrow screens - Change search input min-width to 0 so it can shrink - Reduce gaps and padding on mobile with responsive sm: prefixes - Shorten search placeholder to "Search..." for mobile
Add background-color to body element so Android Chrome picks up the correct surface color for the system navigation bar.
Use dvh (dynamic viewport height) instead of vh to account for mobile browser chrome. On Android Chrome, 100vh includes the address bar space, pushing the footer off-screen until the user scrolls.
Reduce padding, gaps, text sizes, and icon sizes on small screens to fit more cards in the viewport. Changes include: - Smaller card padding and gaps on mobile - Smaller status icon and torrent name text - Line clamping for long names (max 2 lines on mobile) - Stats row uses flex-wrap instead of grid for better space efficiency - Smaller stats text and icons on mobile - Tighter spacing between action buttons
Use h-full instead of hardcoded h-[calc(100dvh-95px)] to properly fill the parent container via flexbox constraints.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Major WebUI overhaul adding a compact table view, performance optimizations for large torrent lists, and improved UX.
New Features:
npm run dev:mockfor UI testing without backend (1000 simulated torrents)make testserverruns a local rqbit instance that simulates torrent traffic for developmentImprovements: