Skip to content

Library UI: settings pane (preferred quality + per-source rules) - #2276

Open
jaylfc wants to merge 1 commit into
devfrom
exec/tsk-g3olu7
Open

Library UI: settings pane (preferred quality + per-source rules)#2276
jaylfc wants to merge 1 commit into
devfrom
exec/tsk-g3olu7

Conversation

@jaylfc

@jaylfc jaylfc commented Aug 3, 2026

Copy link
Copy Markdown
Owner

CARD TITLE (intent, not commit subject): Library UI: settings pane (preferred quality + per-source rules)

Autonomous build of board card tsk-g3olu7.

Files:
CHANGELOG.md | 4 -
desktop/src/apps/LibraryApp.settings.test.tsx | 194 ++++++++++++++++++++
desktop/src/apps/LibraryApp.tsx | 247 +++++++++++++++++++++++++-
docs/agent-manual/11-files-api.md | 35 ----
docs/agent-manual/index.md | 1 -
docs/taos-agent-manual.md | 35 ----
tests/test_agent_manual_compiled.py | 2 +-
7 files changed, 436 insertions(+), 82 deletions(-)

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jaylfc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 54 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 20db1cbc-8375-4ccb-b579-8c930042987f

📥 Commits

Reviewing files that changed from the base of the PR and between 21b0824 and f55abeb.

📒 Files selected for processing (2)
  • desktop/src/apps/LibraryApp.settings.test.tsx
  • desktop/src/apps/LibraryApp.tsx

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.

@gitar-bot

gitar-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Library UI: add Settings view for preferred quality, storage cap, and per-source rules

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add a new Library “settings” view with preferred quality, storage cap, and source rules.
• Persist Library settings in localStorage as a temporary contract until backend support.
• Add UI tests covering view switching, rule CRUD, and settings persistence.
Diagram

graph TD
A["LibraryApp.tsx"] --> B["Settings view"] --> C[("localStorage")]
A --> D["Storage view"] --> E["deriveMockStorageData"]
B --> D
F["settings tests"] --> A
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Persist settings via backend API (target state for #2060)
  • ➕ Settings roam across devices/sessions and can be enforced server-side
  • ➕ Enables validation and future rule execution in ingest pipeline
  • ➖ Requires API design + auth/scoping decisions
  • ➖ More coordination and longer lead time than a UI-only mock
2. Extract settings into a dedicated hook + schema validation
  • ➕ Centralizes load/save + defaults and reduces LibraryApp.tsx complexity
  • ➕ Schema validation (e.g., zod) prevents malformed localStorage from breaking UI
  • ➖ Adds minor indirection and (if using zod) an extra dependency/surface area
3. Model source rules with stable IDs and de-duping
  • ➕ Avoids index-based delete pitfalls and duplicate rule rows
  • ➕ Prepares for backend synchronization and future rule editing
  • ➖ Slightly more code now (ID generation, uniqueness constraints)

Recommendation: The current localStorage-backed mock is a reasonable interim step (explicitly labeled until #2060) and unblocks UI iteration. For maintainability, consider extracting the settings logic into a small hook (load/save/defaults + validation) and switching source_rules deletion from index-based removal to stable IDs to reduce future migration risk when the backend contract lands.

Files changed (6) +435 / -6 · 4 not counted

Enhancement (1) +241 / -6
LibraryApp.tsxAdd Settings view with localStorage-backed Library settings +241/-6

Add Settings view with localStorage-backed Library settings

• Adds a third view mode (settings) alongside items and storage. Implements a temporary localStorage contract for preferred quality, storage cap, and per-source rules (add/delete), and wires the storage accounting cap to the configured value.

desktop/src/apps/LibraryApp.tsx

Tests (2) +194 / -0
LibraryApp.settings.test.tsxAdd RTL/Vitest coverage for the new Library settings view +194/-0

Add RTL/Vitest coverage for the new Library settings view

• Introduces a settings-focused test suite that stubs fetch for required endpoints. Verifies switching to settings view, default values (quality + cap formatting), per-source rule add/delete, and localStorage persistence.

desktop/src/apps/LibraryApp.settings.test.tsx

test_agent_manual_compiled.pyAlign manual compilation guard with updated manual sources not counted

Align manual compilation guard with updated manual sources

• Updates the CI test that asserts the committed compiled manual matches freshly-built output, in line with the agent-manual source set changes.

tests/test_agent_manual_compiled.py

Documentation (3)
index.mdUpdate agent-manual compile index after source removal not counted

Update agent-manual compile index after source removal

• Adjusts the agent manual source index to reflect removed/reorganized sections so the compiled manual no longer expects the deleted source file.

docs/agent-manual/index.md

taos-agent-manual.mdRegenerate compiled agent manual after source changes not counted

Regenerate compiled agent manual after source changes

• Updates the generated compiled manual to match the current docs/agent-manual sources, reflecting the removal of the Files API source section.

docs/taos-agent-manual.md

CHANGELOG.mdChangelog housekeeping not counted

Changelog housekeeping

• Removes a small set of lines from the changelog to keep entries consistent and non-duplicative.

CHANGELOG.md

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (1)

Context used
✅ Compliance rules (platform): 35 rules

Grey Divider


Remediation recommended

1. Invalid cap breaks storage 🐞 Bug ≡ Correctness
Description
The settings UI can persist a storage cap of 0 (or negative), and the storage accounting view then
divides by that cap and treats the cap as reached, resulting in incorrect 100% usage/progressbar
values and a misleading "Paused at cap" state. This is caused by saving parseInt(...) || 0 and
then using settings.storage_cap_bytes directly in deriveMockStorageData and percentage math.
Code

desktop/src/apps/LibraryApp.tsx[R1087-1088]

+    const data = deriveMockStorageData(items, settings.storage_cap_bytes);
    const totalPct = Math.min(100, (data.total_bytes / data.cap_bytes) * 100);
Relevance

●●● Strong

Repo history favors clamping/validating user inputs to avoid bad UI math (e.g., zoom clamping PR
#303; invalid date guard PR #307).

PR-#303
PR-#307

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The storage-cap input persists 0 when the field is cleared/invalid, and the storage view uses that
persisted value as cap_bytes and divides by it to compute totalPct, which makes the UI treat
usage as 100% and triggers the cap-paused messaging.

desktop/src/apps/LibraryApp.tsx[1225-1233]
desktop/src/apps/LibraryApp.tsx[1087-1100]
desktop/src/apps/LibraryApp.tsx[188-210]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The storage cap can be saved as `0` (or negative) and is then used as `cap_bytes` in the storage accounting calculations. This leads to incorrect percentages (division by 0) and `paused_at_cap` being effectively always true when cap is 0.

### Issue Context
- The settings input writes `storage_cap_bytes: parseInt(e.target.value) || 0`.
- The storage view uses `settings.storage_cap_bytes` as the cap and computes `totalPct` from it.

### Fix Focus Areas
- desktop/src/apps/LibraryApp.tsx[1225-1234]
- desktop/src/apps/LibraryApp.tsx[1087-1104]
- desktop/src/apps/LibraryApp.tsx[188-210]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Unvalidated source_rules can crash 🐞 Bug ☼ Reliability
Description
loadLibrarySettings() accepts any array for source_rules without validating each element, but
the settings table render dereferences rule.source/action/quality for every entry. If localStorage
contains nullish entries (or otherwise malformed items), the settings view can throw at render time.
Code

desktop/src/apps/LibraryApp.tsx[R149-152]

+        preferred_quality: parsed.preferred_quality ?? DEFAULT_LIBRARY_SETTINGS.preferred_quality,
+        storage_cap_bytes: parsed.storage_cap_bytes ?? DEFAULT_LIBRARY_SETTINGS.storage_cap_bytes,
+        source_rules: Array.isArray(parsed.source_rules) ? parsed.source_rules : DEFAULT_LIBRARY_SETTINGS.source_rules,
+      };
Relevance

●●● Strong

Team often accepts runtime guards against malformed data to prevent crashes (e.g., invalid date
hardening in PR #307).

PR-#307

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The loader returns parsed.source_rules unchanged if it’s an array, while the table render directly
reads rule.source, rule.action, and rule.quality for each element, which will throw if an
element is null/undefined.

desktop/src/apps/LibraryApp.tsx[143-152]
desktop/src/apps/LibraryApp.tsx[1256-1261]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`loadLibrarySettings()` only checks `Array.isArray(parsed.source_rules)` and then returns the array verbatim. The UI later assumes each element is an object with `source`, `action`, and `quality` strings.

### Issue Context
Corrupted or legacy localStorage values (e.g., `[null]`) will cause `rule.source` dereferences to throw during rendering.

### Fix Focus Areas
- desktop/src/apps/LibraryApp.tsx[143-152]
- desktop/src/apps/LibraryApp.tsx[1256-1268]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Inline localStorage settings persistence 📜 Skill insight ⌂ Architecture
Description
LibraryApp implements settings persistence (localStorage load/save) and settings UI/handlers
directly inside the main component, adding multiple concerns to an already large component. This
conflicts with the SPA guideline to keep one concern per component and move side-effectful data
logic into dedicated hooks/services for maintainability and testability.
Code

desktop/src/apps/LibraryApp.tsx[R160-163]

+function saveLibrarySettings(settings: LibrarySettings): void {
+  try {
+    localStorage.setItem(LIBRARY_SETTINGS_KEY, JSON.stringify(settings));
+  } catch {
Relevance

● Weak

Similar “extract side-effect logic into hook/service” SPA-structure refactor was rejected in PR
#2122.

PR-#2122

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2185494 requires React SPA components to keep a single concern and place
side-effectful data logic in hooks/services rather than inline in component code. The diff adds
loadLibrarySettings()/saveLibrarySettings() that read/write localStorage and then calls them
directly in component event handlers, indicating persistence logic is embedded in the component
rather than extracted.

desktop/src/apps/LibraryApp.tsx[143-166]
desktop/src/apps/LibraryApp.tsx[1201-1208]
Skill: taos-development-skill

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`LibraryApp` now contains settings persistence + settings UI + settings table logic inline, which increases component scope and makes it harder to maintain/test. The compliance guideline expects one concern per component and data/side-effect logic (including persistence) to live in hooks/services.

## Issue Context
The PR adds `loadLibrarySettings()` / `saveLibrarySettings()` and multiple inline event handlers that persist to `localStorage` within `desktop/src/apps/LibraryApp.tsx`.

## Fix Focus Areas
- desktop/src/apps/LibraryApp.tsx[143-166]
- desktop/src/apps/LibraryApp.tsx[1201-1208]
- desktop/src/apps/LibraryApp.tsx[1225-1233]
- desktop/src/apps/LibraryApp.tsx[535-557]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment on lines +1087 to 1088
const data = deriveMockStorageData(items, settings.storage_cap_bytes);
const totalPct = Math.min(100, (data.total_bytes / data.cap_bytes) * 100);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. Invalid cap breaks storage 🐞 Bug ≡ Correctness

The settings UI can persist a storage cap of 0 (or negative), and the storage accounting view then
divides by that cap and treats the cap as reached, resulting in incorrect 100% usage/progressbar
values and a misleading "Paused at cap" state. This is caused by saving parseInt(...) || 0 and
then using settings.storage_cap_bytes directly in deriveMockStorageData and percentage math.
Agent Prompt
### Issue description
The storage cap can be saved as `0` (or negative) and is then used as `cap_bytes` in the storage accounting calculations. This leads to incorrect percentages (division by 0) and `paused_at_cap` being effectively always true when cap is 0.

### Issue Context
- The settings input writes `storage_cap_bytes: parseInt(e.target.value) || 0`.
- The storage view uses `settings.storage_cap_bytes` as the cap and computes `totalPct` from it.

### Fix Focus Areas
- desktop/src/apps/LibraryApp.tsx[1225-1234]
- desktop/src/apps/LibraryApp.tsx[1087-1104]
- desktop/src/apps/LibraryApp.tsx[188-210]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +149 to +152
preferred_quality: parsed.preferred_quality ?? DEFAULT_LIBRARY_SETTINGS.preferred_quality,
storage_cap_bytes: parsed.storage_cap_bytes ?? DEFAULT_LIBRARY_SETTINGS.storage_cap_bytes,
source_rules: Array.isArray(parsed.source_rules) ? parsed.source_rules : DEFAULT_LIBRARY_SETTINGS.source_rules,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

3. Unvalidated source_rules can crash 🐞 Bug ☼ Reliability

loadLibrarySettings() accepts any array for source_rules without validating each element, but
the settings table render dereferences rule.source/action/quality for every entry. If localStorage
contains nullish entries (or otherwise malformed items), the settings view can throw at render time.
Agent Prompt
### Issue description
`loadLibrarySettings()` only checks `Array.isArray(parsed.source_rules)` and then returns the array verbatim. The UI later assumes each element is an object with `source`, `action`, and `quality` strings.

### Issue Context
Corrupted or legacy localStorage values (e.g., `[null]`) will cause `rule.source` dereferences to throw during rendering.

### Fix Focus Areas
- desktop/src/apps/LibraryApp.tsx[143-152]
- desktop/src/apps/LibraryApp.tsx[1256-1268]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@jaylfc

jaylfc commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

nemotron-super review

VERDICT: Found issues requiring fixes

  • desktop/src/apps/LibraryApp.tsx:1226: Storage cap input allows zero/negative values, causing incorrect storage view calculation
  • desktop/src/apps/LibraryApp.tsx:144: loadLibrarySettings lacks validation for parsed settings (type safety)
  • desktop/src/apps/LibraryApp.tsx:1255: Non-unique key in rules table for duplicate rules (same source/action/quality)
  • desktop/src/apps/LibraryApp.settings.test.tsx:46: Weak table selector (querySelector) risks false positives if multiple tables exist
  • desktop/src/apps/LibraryApp.settings.test.tsx:64: Weak table selector (querySelector) risks false positives if multiple tables exist

Automated first-pass review by the nemotron-super lane. The lead still reviews before merge.

@jaylfc

jaylfc commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

HELD, not armed - this builds the CLIENT half of a feature whose SERVER half is in an open PR, and as written the two never meet.

WHAT THIS PR DOES: the settings pane persists preferred quality and per-source rules to localStorage only (LIBRARY_SETTINGS_KEY). There are no API calls in the diff, and dev's tinyagentos/routes/library.py has no settings or rules endpoints at all - I grepped.

WHAT ALREADY EXISTS ELSEWHERE: hognek's OPEN #2070 'feat(library): P3 - heavy tier download, quality preferences, storage accounting, per-source rules' adds precisely the server side, including POST /api/library/rules and GET /api/library/rules, with rules carrying source_pattern, quality and auto_download - the same three concepts this pane edits.

CONSEQUENCE IF MERGED AS-IS: the pane would look complete and change nothing. The library pipeline downloads server-side, so rules kept in one browser's localStorage are never consulted; a user would set 720p for youtube, see it saved, and get whatever the server defaults to. That is the failure mode where the working half hides the broken half, and it is also the collision the contributing guide warns about - two PRs implementing one feature from opposite ends without knowing about each other.

NOT A CRITICISM OF THE BUILD: the pane itself is sound - 194 lines of real tests, no CSRF exposure precisely because it makes no network calls, and the only CI red besides Kilo's known rate-limit fake-red is the missing changelog.

TO LAND IT: wire the pane to #2070's endpoints - GET /api/library/rules to populate, POST /api/library/rules to save - and keep localStorage at most as an optimistic cache, never as the source of truth. That means this PR should either wait for #2070 to merge, or be rebased onto it. I am holding rather than closing because the UI work is worth keeping. Sequencing is mine to coordinate with hognek.

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