Adopt Biome and reformat the frontend - #215
Conversation
The project had no frontend linter or formatter, so style drifted file by file. This adds Biome with the config the rest of my repos use, and runs it once over the existing sources. Everything here is mechanical: line rewrapping to the 100-column width and import sorting. No behaviour changes, and typecheck, tests, and the production build all pass unchanged. Kept separate from the work that follows because a formatting pass touches almost every file, which buries a real diff — and pushes a combined PR past CodeRabbit's 100-file review limit.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughBiome configuration and npm scripts were added. The repository’s TypeScript, TSX, CSS, store, hook, library, and test files were reformatted, with existing behavior generally preserved. The Advanced settings UI also removes the ffmpeg/ffprobe subsection. ChangesBiome adoption and application formatting
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai review |
|
@codex review |
✅ Action performedReview finished.
|
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/SettingsPanel.tsx (1)
1229-1318: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFfmpeg/ffprobe settings become unreachable in the UI.
The Advanced tab's ffmpeg/ffprobe subsection (inputs for
ffprobe_timeout_secsandffmpeg_bitrate_timeout_secs) is removed, butAppSettingsandScanPresetConfigstill define both fields, andapplyScanPresetConfigstill copies them from presets. With no remaining UI control, users can no longer directly adjust these timeouts — they're now frozen at whatever value a loaded preset (or the initial default) provides. This is a real behavior change bundled into a PR described as "mechanical... no behavior changes." Please confirm this removal is intentional and that there's an alternate path (e.g., preset-only configuration) for users who need to tune these timeouts.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/SettingsPanel.tsx` around lines 1229 - 1318, Restore the Advanced tab’s ffmpeg/ffprobe subsection containing the `ffprobe_timeout_secs` and `ffmpeg_bitrate_timeout_secs` inputs so users can continue adjusting both settings directly. Keep their existing `updateSetting` handlers and validation bounds, and preserve the surrounding `AppSettings`, `ScanPresetConfig`, and `applyScanPresetConfig` behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@biome.jsonc`:
- Around line 3-6: Update the Biome files.includes configuration to exclude
shell scripts from scanning by narrowing the scripts/** pattern to
supported-language files such as scripts/**/*.ts, while preserving the existing
src/**, tests/**, worktree exclusion, and dist exclusion entries.
In `@src/components/HistoryPanel.tsx`:
- Around line 46-53: Update the dialog implementations in
src/components/HistoryPanel.tsx lines 46-53 and
src/components/KeyboardShortcutsDialog.tsx lines 77-83 to use native dialog
behavior with focus trapping via showModal()/close(), while preserving existing
close behavior. In HistoryPanel, add Escape handling and make the backdrop
dismissal keyboard accessible; in KeyboardShortcutsDialog, retain its existing
Escape listener and add a keyboard-accessible backdrop handler.
In `@src/components/SavedPlaylistEditorDialog.tsx`:
- Line 164: Update the Display Name and Username label/input pairs in
SavedPlaylistEditorDialog to use matching htmlFor and id attributes, following
the existing Xtream password field pattern; keep each label associated with its
adjacent input.
In `@src/components/SettingsPanel.tsx`:
- Line 743: Associate every affected label with its form control in
SettingsPanel by adding a unique id to each preset select and timeout,
concurrency, retries, and threshold input, then setting the corresponding label
htmlFor to that id. Apply the same pairing consistently at the referenced
control blocks without changing their existing behavior.
In `@src/components/ThumbnailPanel.tsx`:
- Around line 620-637: Update the theater-mode toggle button in the
ThumbnailPanel JSX to add an aria-label that matches its current action, using
the same conditional “Exit fullscreen”/“Fullscreen” text as the title while
preserving the existing icon and click behavior.
---
Outside diff comments:
In `@src/components/SettingsPanel.tsx`:
- Around line 1229-1318: Restore the Advanced tab’s ffmpeg/ffprobe subsection
containing the `ffprobe_timeout_secs` and `ffmpeg_bitrate_timeout_secs` inputs
so users can continue adjusting both settings directly. Keep their existing
`updateSetting` handlers and validation bounds, and preserve the surrounding
`AppSettings`, `ScanPresetConfig`, and `applyScanPresetConfig` behavior.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 286ed6c3-12dd-4102-adbc-787aa4fca6ed
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (79)
biome.jsoncpackage.jsonscripts/benchmark-ui-filter.tssrc/App.tsxsrc/SettingsWindow.tsxsrc/components/AppBanners.tsxsrc/components/CastMenu.tsxsrc/components/ChannelRow.tsxsrc/components/ChannelTable.tsxsrc/components/ErrorBoundary.tsxsrc/components/ExportMenu.tsxsrc/components/FilterBar.tsxsrc/components/HistoryPanel.tsxsrc/components/KeyboardShortcutsDialog.tsxsrc/components/LogWindowContent.tsxsrc/components/OpenSourceDialog.tsxsrc/components/PasswordField.tsxsrc/components/PlaylistReportPanel.tsxsrc/components/ProgressBar.tsxsrc/components/SFSymbols.tsxsrc/components/SavedPlaylistEditorDialog.tsxsrc/components/SavedPlaylistsDialog.tsxsrc/components/SettingsPanel.tsxsrc/components/StartScreen.tsxsrc/components/StatsPanel.tsxsrc/components/StatusBadge.tsxsrc/components/StreamPlayer.tsxsrc/components/ThumbnailPanel.tsxsrc/components/Toolbar.tsxsrc/hooks/useChromecast.tssrc/hooks/useMenuEventBridge.tssrc/hooks/usePlaylistSources.tssrc/hooks/useScan.helpers.tssrc/hooks/useScan.tssrc/hooks/useStreamPlayer.tssrc/hooks/useUpdateCheck.tssrc/index.csssrc/lib/cast.tssrc/lib/channelResults.tssrc/lib/duplicates.tssrc/lib/errors.tssrc/lib/extinf.tssrc/lib/filters.tssrc/lib/format.tssrc/lib/haptics.tssrc/lib/languageDistribution.tssrc/lib/logger.tssrc/lib/logoCache.tssrc/lib/perf.tssrc/lib/playback.tssrc/lib/playlistReportVisibility.tssrc/lib/recentPlaylists.tssrc/lib/runtimeMonitor.tssrc/lib/savedPlaylists.tssrc/lib/scanState.tssrc/lib/shortcuts.tssrc/lib/sourceFilter.tssrc/lib/tableColumns.tssrc/lib/tauri.tssrc/lib/thumbnailState.tssrc/lib/workerSupport.tssrc/main.tsxsrc/store/slices/settingsSlice.tssrc/store/slices/uiSlice.tssrc/store/store.tssrc/store/types.tstests/channelResults.test.tstests/duplicates.test.tstests/errors.test.tstests/exportScope.test.tstests/filters.logic.test.tstests/format.test.tstests/playlistReportVisibility.test.tstests/savedPlaylists.test.tstests/scanErrorEvents.test.tstests/sourceFilter.test.tstests/tableColumns.test.tstests/useScan.helpers.test.tstests/useStreamPlayer.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Define agent interfaces and implementations in TypeScript for agent systems
Use clear naming conventions for agent classes and methods
Document agent behavior and responsibilities in comments or docstrings
Implement error handling in agent methods
Files:
tests/useScan.helpers.test.tstests/format.test.tssrc/lib/scanState.tsscripts/benchmark-ui-filter.tstests/channelResults.test.tstests/duplicates.test.tstests/tableColumns.test.tssrc/components/StatusBadge.tsxsrc/lib/languageDistribution.tstests/playlistReportVisibility.test.tstests/errors.test.tssrc/hooks/useScan.helpers.tssrc/components/PasswordField.tsxtests/scanErrorEvents.test.tssrc/lib/logoCache.tssrc/components/ErrorBoundary.tsxsrc/lib/duplicates.tssrc/lib/thumbnailState.tstests/exportScope.test.tssrc/lib/format.tssrc/lib/cast.tssrc/components/KeyboardShortcutsDialog.tsxsrc/lib/haptics.tssrc/components/SavedPlaylistsDialog.tsxsrc/store/slices/uiSlice.tssrc/lib/channelResults.tssrc/lib/savedPlaylists.tssrc/lib/perf.tstests/filters.logic.test.tstests/savedPlaylists.test.tssrc/store/types.tssrc/lib/workerSupport.tssrc/lib/recentPlaylists.tssrc/SettingsWindow.tsxsrc/lib/logger.tssrc/lib/tableColumns.tssrc/main.tsxsrc/components/FilterBar.tsxsrc/components/ProgressBar.tsxsrc/store/store.tssrc/lib/shortcuts.tssrc/components/ExportMenu.tsxsrc/components/SavedPlaylistEditorDialog.tsxsrc/lib/extinf.tssrc/hooks/useChromecast.tssrc/components/HistoryPanel.tsxsrc/lib/filters.tssrc/components/AppBanners.tsxsrc/store/slices/settingsSlice.tstests/sourceFilter.test.tssrc/components/StatsPanel.tsxsrc/components/ChannelRow.tsxsrc/components/SFSymbols.tsxsrc/lib/playback.tssrc/components/CastMenu.tsxsrc/lib/sourceFilter.tssrc/hooks/useMenuEventBridge.tssrc/components/StreamPlayer.tsxsrc/components/StartScreen.tsxsrc/lib/errors.tssrc/hooks/useUpdateCheck.tstests/useStreamPlayer.test.tssrc/lib/tauri.tssrc/components/LogWindowContent.tsxsrc/lib/playlistReportVisibility.tssrc/lib/runtimeMonitor.tssrc/components/OpenSourceDialog.tsxsrc/components/ThumbnailPanel.tsxsrc/hooks/useScan.tssrc/components/PlaylistReportPanel.tsxsrc/hooks/useStreamPlayer.tssrc/components/Toolbar.tsxsrc/components/ChannelTable.tsxsrc/components/SettingsPanel.tsxsrc/hooks/usePlaylistSources.tssrc/App.tsx
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use strict TypeScript with no unused locals or parameters.
Files:
src/lib/scanState.tssrc/components/StatusBadge.tsxsrc/lib/languageDistribution.tssrc/hooks/useScan.helpers.tssrc/components/PasswordField.tsxsrc/lib/logoCache.tssrc/components/ErrorBoundary.tsxsrc/lib/duplicates.tssrc/lib/thumbnailState.tssrc/lib/format.tssrc/lib/cast.tssrc/components/KeyboardShortcutsDialog.tsxsrc/lib/haptics.tssrc/components/SavedPlaylistsDialog.tsxsrc/store/slices/uiSlice.tssrc/lib/channelResults.tssrc/lib/savedPlaylists.tssrc/lib/perf.tssrc/store/types.tssrc/lib/workerSupport.tssrc/lib/recentPlaylists.tssrc/SettingsWindow.tsxsrc/lib/logger.tssrc/lib/tableColumns.tssrc/main.tsxsrc/components/FilterBar.tsxsrc/components/ProgressBar.tsxsrc/store/store.tssrc/lib/shortcuts.tssrc/components/ExportMenu.tsxsrc/components/SavedPlaylistEditorDialog.tsxsrc/lib/extinf.tssrc/hooks/useChromecast.tssrc/components/HistoryPanel.tsxsrc/lib/filters.tssrc/components/AppBanners.tsxsrc/store/slices/settingsSlice.tssrc/components/StatsPanel.tsxsrc/components/ChannelRow.tsxsrc/components/SFSymbols.tsxsrc/lib/playback.tssrc/components/CastMenu.tsxsrc/lib/sourceFilter.tssrc/hooks/useMenuEventBridge.tssrc/components/StreamPlayer.tsxsrc/components/StartScreen.tsxsrc/lib/errors.tssrc/hooks/useUpdateCheck.tssrc/lib/tauri.tssrc/components/LogWindowContent.tsxsrc/lib/playlistReportVisibility.tssrc/lib/runtimeMonitor.tssrc/components/OpenSourceDialog.tsxsrc/components/ThumbnailPanel.tsxsrc/hooks/useScan.tssrc/components/PlaylistReportPanel.tsxsrc/hooks/useStreamPlayer.tssrc/components/Toolbar.tsxsrc/components/ChannelTable.tsxsrc/components/SettingsPanel.tsxsrc/hooks/usePlaylistSources.tssrc/App.tsx
src/components/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Implement components as functional React components using hooks, and use Tailwind CSS for styling instead of CSS-in-JS.
Files:
src/components/StatusBadge.tsxsrc/components/PasswordField.tsxsrc/components/ErrorBoundary.tsxsrc/components/KeyboardShortcutsDialog.tsxsrc/components/SavedPlaylistsDialog.tsxsrc/components/FilterBar.tsxsrc/components/ProgressBar.tsxsrc/components/ExportMenu.tsxsrc/components/SavedPlaylistEditorDialog.tsxsrc/components/HistoryPanel.tsxsrc/components/AppBanners.tsxsrc/components/StatsPanel.tsxsrc/components/ChannelRow.tsxsrc/components/SFSymbols.tsxsrc/components/CastMenu.tsxsrc/components/StreamPlayer.tsxsrc/components/StartScreen.tsxsrc/components/LogWindowContent.tsxsrc/components/OpenSourceDialog.tsxsrc/components/ThumbnailPanel.tsxsrc/components/PlaylistReportPanel.tsxsrc/components/Toolbar.tsxsrc/components/ChannelTable.tsxsrc/components/SettingsPanel.tsx
src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use a virtualized table via
@tanstack/react-virtualfor playlists containing 1000 or more channels.
Files:
src/components/StatusBadge.tsxsrc/components/PasswordField.tsxsrc/components/ErrorBoundary.tsxsrc/components/KeyboardShortcutsDialog.tsxsrc/components/SavedPlaylistsDialog.tsxsrc/components/FilterBar.tsxsrc/components/ProgressBar.tsxsrc/components/ExportMenu.tsxsrc/components/SavedPlaylistEditorDialog.tsxsrc/components/HistoryPanel.tsxsrc/components/AppBanners.tsxsrc/components/StatsPanel.tsxsrc/components/ChannelRow.tsxsrc/components/SFSymbols.tsxsrc/components/CastMenu.tsxsrc/components/StreamPlayer.tsxsrc/components/StartScreen.tsxsrc/components/LogWindowContent.tsxsrc/components/OpenSourceDialog.tsxsrc/components/ThumbnailPanel.tsxsrc/components/PlaylistReportPanel.tsxsrc/components/Toolbar.tsxsrc/components/ChannelTable.tsxsrc/components/SettingsPanel.tsx
🪛 ast-grep (0.44.1)
src/lib/extinf.ts
[warning] 41-44: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(
\\b${escapedAttribute}=(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'|([^\\s]+)),
"i",
)
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
🪛 OpenGrep (1.25.0)
src/lib/extinf.ts
[ERROR] 47-47: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
🪛 React Doctor (0.7.6)
src/components/KeyboardShortcutsDialog.tsx
[warning] 79-79: Keyboard users can tab out of this role="dialog" modal because it has no built-in focus trapping, so use the native <dialog>, which gives you focus trapping, Escape to close, and the backdrop for free.
Replace the wrapper with <dialog> and open it with dialog.showModal(). For the trigger, prefer <button commandfor="id" command="show-modal"> (Chrome 135+), or a useRef with dialogRef.current?.showModal().
(prefer-html-dialog)
[warning] 83-83: Keyboard users can't trigger this click handler because there's no keyboard one, so add onKeyUp, onKeyDown, or onKeyPress.
Pair onClick with a key handler so keyboard users can trigger it.
(click-events-have-key-events)
[warning] 83-83: Screen reader users can't tell this click handler is interactive because it has no role, so add a role or use a button or link.
Give clickable static elements a role, or use a button or link.
(no-static-element-interactions)
src/components/SavedPlaylistEditorDialog.tsx
[warning] 164-164: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 220-220: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
src/components/HistoryPanel.tsx
[warning] 49-49: Keyboard users can tab out of this role="dialog" modal because it has no built-in focus trapping, so use the native <dialog>, which gives you focus trapping, Escape to close, and the backdrop for free.
Replace the wrapper with <dialog> and open it with dialog.showModal(). For the trigger, prefer <button commandfor="id" command="show-modal"> (Chrome 135+), or a useRef with dialogRef.current?.showModal().
(prefer-html-dialog)
[warning] 53-53: Keyboard users can't trigger this click handler because there's no keyboard one, so add onKeyUp, onKeyDown, or onKeyPress.
Pair onClick with a key handler so keyboard users can trigger it.
(click-events-have-key-events)
[warning] 53-53: Screen reader users can't tell this click handler is interactive because it has no role, so add a role or use a button or link.
Give clickable static elements a role, or use a button or link.
(no-static-element-interactions)
src/components/ThumbnailPanel.tsx
[warning] 134-134: This component misses React Compiler's automatic memoization & re-renders more than it should: This value cannot be modified. Rewrite the flagged code so the compiler can optimize it.
Modifying component props or hook arguments is not allowed. Consider using a local variable instead.
(immutability)
[warning] 542-542: Screen reader users can't tell this click handler is interactive because it has no role, so add a role or use a button or link.
Give clickable static elements a role, or use a button or link.
(no-static-element-interactions)
[warning] 620-620: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
src/components/PlaylistReportPanel.tsx
[warning] 258-258: Screen reader users can't tell this click handler is interactive because it has no role, so add a role or use a button or link.
Give clickable static elements a role, or use a button or link.
(no-static-element-interactions)
src/components/SettingsPanel.tsx
[warning] 555-555: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 743-743: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 844-844: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 847-847: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 861-861: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 886-886: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 920-920: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 923-923: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 940-940: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 964-964: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 990-990: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 1027-1027: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 1111-1111: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 1114-1114: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
[warning] 1131-1131: Screen reader users can't tell which input this label names because it's tied to none, so add htmlFor or wrap the input inside it.
Tie every label to a control with htmlFor, or by nesting the input.
(label-has-associated-control)
[warning] 1134-1134: Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.
Give every interactive control a label screen readers can read.
(control-has-associated-label)
🔇 Additional comments (82)
tests/channelResults.test.ts (1)
67-67: LGTM!tests/duplicates.test.ts (1)
57-57: LGTM!tests/errors.test.ts (1)
23-26: LGTM!Also applies to: 40-42
tests/exportScope.test.ts (1)
3-6: LGTM!Also applies to: 65-65
tests/filters.logic.test.ts (1)
79-87: LGTM!Also applies to: 98-98, 132-132
tests/format.test.ts (1)
12-12: LGTM!tests/useStreamPlayer.test.ts (1)
5-5: LGTM!Also applies to: 16-17, 68-68, 79-79, 90-90, 105-118, 178-179, 239-239
tests/playlistReportVisibility.test.ts (1)
23-24: LGTM!tests/savedPlaylists.test.ts (2)
10-10: LGTM!
104-104: LGTM!tests/scanErrorEvents.test.ts (1)
17-17: LGTM!tests/sourceFilter.test.ts (5)
11-11: LGTM!
44-44: LGTM!Also applies to: 59-59, 74-74
95-96: LGTM!
110-110: LGTM!
130-156: LGTM!tests/tableColumns.test.ts (1)
10-14: LGTM!tests/useScan.helpers.test.ts (1)
2-5: LGTM!biome.jsonc (1)
8-69: LGTM!package.json (1)
16-18: LGTM!Also applies to: 42-42
scripts/benchmark-ui-filter.ts (1)
3-3: LGTM!src/App.tsx (1)
1-51: LGTM!Also applies to: 61-73, 155-157, 303-368, 407-447, 565-617, 708-811, 863-922, 953-1013, 1113-1224, 1273-1516, 1618-1644
src/SettingsWindow.tsx (1)
2-2: LGTM!src/main.tsx (1)
4-11: LGTM!Also applies to: 34-34
src/store/slices/settingsSlice.ts (1)
3-7: LGTM!Also applies to: 40-40, 62-80
src/store/slices/uiSlice.ts (1)
4-4: LGTM!Also applies to: 74-74
src/store/store.ts (1)
2-10: LGTM!src/store/types.ts (1)
1-3: LGTM!src/components/AppBanners.tsx (1)
3-8: LGTM!Also applies to: 55-55
src/components/FilterBar.tsx (1)
4-12: LGTM!Also applies to: 27-30
src/components/StartScreen.tsx (1)
2-5: LGTM!Also applies to: 74-98, 112-119
src/hooks/useMenuEventBridge.ts (1)
3-4: LGTM!Also applies to: 108-110
src/hooks/usePlaylistSources.ts (1)
2-15: LGTM!Also applies to: 25-47, 71-71, 130-130, 152-152, 201-206, 221-221, 279-287, 314-314, 336-342, 441-449, 469-479, 521-521, 543-569, 593-616, 683-688, 757-758, 820-820
src/hooks/useUpdateCheck.ts (1)
2-13: LGTM!Also applies to: 66-67, 85-158
src/index.css (1)
5-7: LGTM!Also applies to: 160-162, 175-176, 281-281, 328-341, 373-375, 405-405, 439-448, 469-471, 504-516
src/lib/errors.ts (1)
22-28: LGTM!Also applies to: 45-50
src/lib/recentPlaylists.ts (1)
21-26: LGTM!src/lib/savedPlaylists.ts (1)
77-77: LGTM!src/lib/sourceFilter.ts (1)
1-1: LGTM!Also applies to: 49-49, 58-58, 122-125
src/components/CastMenu.tsx (1)
2-4: LGTM!Also applies to: 47-47, 139-141, 199-199, 296-297
src/components/PlaylistReportPanel.tsx (1)
2-11: LGTM!Also applies to: 45-45, 76-77, 86-91, 118-128, 176-190, 251-276, 303-326, 351-359, 371-373, 397-399, 422-443, 459-461, 474-485, 504-508, 526-527, 546-557
src/components/ProgressBar.tsx (1)
20-24: LGTM!Also applies to: 39-39, 68-68
src/components/SFSymbols.tsx (1)
8-30: LGTM!Also applies to: 43-45, 59-66
src/components/SavedPlaylistEditorDialog.tsx (1)
2-3: LGTM!Also applies to: 47-47, 110-110, 273-273
src/components/StatsPanel.tsx (1)
1-13: LGTM!Also applies to: 82-82
src/components/StatusBadge.tsx (1)
2-6: LGTM!src/components/StreamPlayer.tsx (1)
1-17: LGTM!Also applies to: 110-113, 142-142, 155-162
src/components/ThumbnailPanel.tsx (1)
1-22: LGTM!Also applies to: 108-111, 128-146, 230-231, 265-271, 315-317, 342-353, 365-374, 394-394, 411-417, 506-514, 540-619, 621-746
src/lib/cast.ts (1)
1-1: LGTM!Also applies to: 31-31
src/lib/scanState.ts (1)
1-1: LGTM!Also applies to: 3-4
src/lib/thumbnailState.ts (1)
32-32: LGTM!Also applies to: 81-81
src/components/ChannelRow.tsx (1)
2-10: LGTM!Also applies to: 60-69, 79-79, 160-169, 190-200, 233-233
src/components/ChannelTable.tsx (1)
1-37: LGTM!Also applies to: 70-75, 102-108, 152-152, 162-162, 191-192, 293-294, 407-411, 541-541, 643-643, 683-685, 769-769, 832-832, 916-916, 940-940, 985-985, 1104-1104, 1178-1178, 1208-1209, 1241-1253, 1286-1290, 1368-1383, 1449-1486
src/components/SavedPlaylistsDialog.tsx (1)
2-4: LGTM!Also applies to: 48-48
src/hooks/useScan.helpers.ts (1)
55-55: LGTM!src/hooks/useScan.ts (1)
2-11: LGTM!Also applies to: 22-29, 53-53, 89-89, 199-200, 285-301, 311-318, 332-332, 347-347, 357-357, 375-375, 428-434, 485-485, 604-604, 629-644
src/lib/channelResults.ts (1)
44-44: LGTM!Also applies to: 69-69
src/lib/duplicates.ts (1)
20-20: LGTM!src/lib/extinf.ts (1)
36-36: LGTM!Also applies to: 42-50
src/lib/filters.ts (1)
1-2: LGTM!Also applies to: 118-118, 226-226, 315-318
src/lib/shortcuts.ts (1)
34-36: LGTM!Also applies to: 38-38
src/lib/tableColumns.ts (1)
40-60: LGTM!src/components/ErrorBoundary.tsx (1)
1-1: LGTM!src/components/ExportMenu.tsx (1)
2-10: LGTM!Also applies to: 41-43, 308-322
src/components/LogWindowContent.tsx (1)
4-4: LGTM!Also applies to: 15-15, 43-45, 59-59, 88-91, 118-118, 280-283
src/components/OpenSourceDialog.tsx (1)
2-10: LGTM!Also applies to: 119-119, 168-168, 177-178, 192-199, 229-233, 262-272, 328-329, 391-392, 509-509, 522-522, 536-536, 629-629, 684-684
src/components/PasswordField.tsx (1)
2-2: LGTM!src/components/SettingsPanel.tsx (1)
2-12: LGTM!Also applies to: 63-63, 114-114, 145-145, 215-215, 263-263, 365-365, 392-392, 433-433, 494-497, 520-1228
src/components/Toolbar.tsx (1)
12-48: LGTM!Also applies to: 107-112, 141-149, 195-195, 214-214, 233-246, 272-275, 389-389, 405-405, 424-430, 592-606
src/hooks/useChromecast.ts (1)
2-4: LGTM!Also applies to: 36-48
src/lib/tauri.ts (1)
2-24: LGTM!Also applies to: 116-130, 175-175, 269-269
src/hooks/useStreamPlayer.ts (1)
2-26: LGTM!Also applies to: 205-205, 235-236, 254-254, 373-373, 442-442, 652-655, 697-697, 791-791, 811-811, 842-852, 869-869, 901-914
src/lib/format.ts (1)
97-97: LGTM!src/lib/haptics.ts (1)
3-4: LGTM!src/lib/languageDistribution.ts (1)
30-30: LGTM!src/lib/logger.ts (1)
4-6: LGTM!Also applies to: 65-65
src/lib/logoCache.ts (1)
113-113: LGTM!src/lib/perf.ts (1)
87-87: LGTM!src/lib/playback.ts (1)
176-189: LGTM!Also applies to: 222-236, 317-317
src/lib/playlistReportVisibility.ts (1)
21-25: LGTM!src/lib/runtimeMonitor.ts (1)
5-23: LGTM!Also applies to: 153-153, 177-177, 199-199, 220-226, 254-254, 343-346, 370-370, 388-388, 398-398
src/lib/workerSupport.ts (1)
23-23: LGTM!
scripts/ is mostly shell and plain text; only the two benchmark files are TypeScript. Biome already skips the rest by extension, but naming them in the glob is misleading about what the config covers.
Mechanical prep, split out of #214 so that PR's real diff is reviewable.
The project had no frontend linter or formatter, so style had drifted file by
file. This adds Biome with the config used across my other repos, and runs it
once over the existing sources.
Everything here is mechanical: line rewrapping to the 100-column width, and
import sorting. No behaviour changes.
Why separate
A formatting pass touches almost every file, which buries a real diff. It also
pushed #214 to 121 files — past CodeRabbit's 100-file limit, so it declined to
review that PR at all:
Landing the formatting on its own drops #214 to roughly 30 files, so the
substantive changes there can actually be reviewed.
Validation
bun run typecheck,bun run test:frontend(90 pass), andbun run buildallpass unchanged. The lint/format scripts are added here; CI enforcement of them
lands with #214, together with the clippy and rustfmt gates.
Review with whitespace hidden — GitHub's
?w=1, orgit diff -w.Summary by CodeRabbit