Skip to content

refactor(settings): modularize Settings page (1969→399 lines, all files under 500) - #758

Merged
debpalash merged 2 commits into
mainfrom
refactor/settings-page-modularization
Jun 29, 2026
Merged

refactor(settings): modularize Settings page (1969→399 lines, all files under 500)#758
debpalash merged 2 commits into
mainfrom
refactor/settings-page-modularization

Conversation

@debpalash

@debpalash debpalash commented Jun 29, 2026

Copy link
Copy Markdown
Owner

What & why

Settings.jsx had grown to 1969 lines — every edit reloaded the whole file into context and risked unrelated breakage. This finishes the migration that the existing components/settings/*Panel.jsx pattern started: the page is now a thin orchestrator, and each heavy tab lives in its own file. Pure-mechanical refactor — no behavior change (logic moved byte-for-byte; only import paths and the shared isTauri/askConfirm helper changed).

Result

Before After
pages/Settings.jsx 1969 399

Extracted into components/settings/: GeneralTab (209), ModelStoreTab (439), EnginesTab (52), HotkeyTab (166), CredentialsTab (128), AboutTab (175), PrivacyTab (33), LogsTab (79), shared Row (8) + native.js (16). ModelStoreTab further split into components/settings/models/ (columns.jsx with a makeModelColumns() factory, ModelsTable, runtime, RecoBanner, format).

Every settings file is now under the 500-line cap.

Standard (Phase 0)

So files can't silently regrow:

  • CONTRIBUTING.md — frontend file-structure & size limits (soft 300 / hard 500)
  • eslint.config.js — warn-only max-lines: 500 guardrail (keeps CI green)
  • docs/maintenance-pages-modularization.md — the phased refactor plan

Verification

  • vite build passes — all imports resolve
  • vitest run src/components/settings — 18/18 pass
  • ✅ No new lint errors; the TanStack columns use a factory with the same useMemo dep array, so memoization is unchanged

🤖 Generated with Claude Code

Refactored the Settings page into smaller tab modules and extracted shared helpers.

  • Split pages/Settings.jsx into thin orchestration plus dedicated tabs:
    • GeneralTab
    • ModelStoreTab
    • EnginesTab
    • HotkeyTab
    • CredentialsTab
    • LogsTab
    • AboutTab
    • PrivacyTab
  • Broke model-store internals into smaller modules:
    • models/format.js
    • models/runtime.js
    • models/columns.jsx
    • models/ModelsTable.jsx
    • models/RecoBanner.jsx
  • Moved shared Tauri/native confirm logic into native.js
  • Added guardrails for frontend file size/structure:
    • CONTRIBUTING.md
    • eslint.config.js (max-lines: 500 warn-only)
    • docs/maintenance-pages-modularization.md

UI sketch:

Before

Settings.jsx
├─ General
├─ Model Store
├─ Engines
├─ Hotkey
├─ Credentials
├─ Logs
├─ About
└─ Privacy

After

Settings.jsx
├─ GeneralTab
├─ ModelStoreTab
├─ EnginesTab
├─ HotkeyTab
├─ CredentialsTab
├─ LogsTab
├─ AboutTab
└─ PrivacyTab

components/settings/
├─ tabs
└─ models/*

Verified with build/tests; no behavior changes intended.

mergetest and others added 2 commits June 30, 2026 01:19
…s (1969→602 lines)

Settings.jsx had grown to 1969 lines — every edit reloaded the whole file
into context and risked unrelated breakage. This finishes the migration the
existing components/settings/*Panel.jsx pattern started: the page is now a
thin orchestrator and each heavy tab lives in its own file.

Extracted (logic byte-for-byte identical; only import paths adjusted + the
shared isTauri/askConfirm moved to components/settings/native.js):
- GeneralTab, ModelStoreTab, EnginesTab, HotkeyTab, CredentialsTab
- native.js — shared isTauri() wrapper + askConfirm() Tauri-dialog helper

Also establishes the standard so files can't silently regrow:
- CONTRIBUTING.md: frontend file-structure & size limits (soft 300 / hard 500)
- eslint.config.js: warn-only max-lines:500 guardrail (CI stays green)
- docs/maintenance-pages-modularization.md: the phased refactor plan

Verified: vite build passes (all imports resolve); 18/18 settings tests pass;
no new lint errors introduced (the pruned imports were the only regressions).

Follow-ups (tracked in the plan doc): ModelStoreTab.jsx is 836 lines and
Settings.jsx 602 — both still over the 500 cap (warn-only); split next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…line cap

Follow-up to the tab extraction: bring the two remaining over-cap files into
compliance with the new standard. Pure-mechanical, no behavior change.

Settings.jsx 602 → 399:
- Extract AboutTab, PrivacyTab, LogsTab into components/settings/
- Move the shared Row helper to components/settings/Row.jsx
- LogsTab keeps its state in Settings() (lower-risk); About/Privacy take props

ModelStoreTab.jsx 836 → 439, split into components/settings/models/:
- format.js (fmtBytes/orgColor), runtime.js (computeRowRuntime)
- columns.jsx exposes makeModelColumns(...) — a factory so the TanStack cell
  closures keep working; called with the same useMemo dep array as before
- ModelsTable.jsx (virtualized table view), RecoBanner.jsx

Every settings file is now under 500 lines. Verified: vite build passes;
18/18 settings tests pass; no new lint errors (the 4 remaining in Settings.jsx
are pre-existing — refreshInfo no-op, a catch(e), two set-state-in-effect).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

Failed to post review comments.

GitHub was unavailable or timed out while CodeRabbit was posting the review. Please request a new review later if the pull request still needs one. This happened while posting 17 inline comments. Use @coderabbitai full review to retry the review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 769e07e1-6540-4eb0-85b3-cd708df458c4

📥 Commits

Reviewing files that changed from the base of the PR and between e2f0232 and d6552ed.

📒 Files selected for processing (19)
  • CONTRIBUTING.md
  • docs/maintenance-pages-modularization.md
  • frontend/eslint.config.js
  • frontend/src/components/settings/AboutTab.jsx
  • frontend/src/components/settings/CredentialsTab.jsx
  • frontend/src/components/settings/EnginesTab.jsx
  • frontend/src/components/settings/GeneralTab.jsx
  • frontend/src/components/settings/HotkeyTab.jsx
  • frontend/src/components/settings/LogsTab.jsx
  • frontend/src/components/settings/ModelStoreTab.jsx
  • frontend/src/components/settings/PrivacyTab.jsx
  • frontend/src/components/settings/Row.jsx
  • frontend/src/components/settings/models/ModelsTable.jsx
  • frontend/src/components/settings/models/RecoBanner.jsx
  • frontend/src/components/settings/models/columns.jsx
  • frontend/src/components/settings/models/format.js
  • frontend/src/components/settings/models/runtime.js
  • frontend/src/components/settings/native.js
  • frontend/src/pages/Settings.jsx
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Tests (backend + frontend)
⚠️ CI failures not shown inline (5)

GitHub Actions: Security / Python SAST (bandit): refactor(settings): modularize Settings page (1969→399 lines, all files under 500)

Conclusion: failure

View job details

##[group]Run pipx run --spec 'bandit[sarif]' bandit -r backend/ -ll -ii -f sarif -o bandit.sarif
 �[36;1mpipx run --spec 'bandit[sarif]' bandit -r backend/ -ll -ii -f sarif -o bandit.sarif�[0m
 shell: /usr/bin/bash -e {0}
 env:
   FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
 ##[endgroup]
 creating virtual environment...
 installing bandit from spec 'bandit[sarif]'...
 [main]	INFO	profile include tests: None
 [main]	INFO	profile exclude tests: None
 [main]	INFO	cli include tests: None
 [main]	INFO	cli exclude tests: None
 [main]	INFO	running on Python 3.10.12
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/gallery.py:461
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/gallery.py:461
 [manager]	WARNING	Test in comment: fields is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: are is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: fixed is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: literal is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: assignments is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: term is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: from is not a test name or id, ignoring
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/pronunciation.py:219
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/pronunciation.py:219
 [manager]	WARNING	Test in comment: local is not a test name or id, ignoring...

GitHub Actions: Security / 3_Dependency audit.txt: refactor(settings): modularize Settings page (1969→399 lines, all files under 500)

Conclusion: failure

View job details

##[group]Run uv sync
 �[36;1muv sync�[0m
 �[36;1muv run --with pip-audit pip-audit�[0m
 shell: /usr/bin/bash -e {0}
 env:
   FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
   UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
 ##[endgroup]
 Using CPython 3.11.15 interpreter at: /opt/hostedtoolcache/Python/3.11.15/x64/bin/python3.11
 Creating virtual environment at: .venv
 Resolved 284 packages in 176ms
    Building omnivoice @ file:///home/runner/work/OmniVoice-Studio/OmniVoice-Studio
 Downloading nvidia-cufft-cu12 (184.2MiB)
 Downloading nvidia-cuda-cupti-cu12 (9.8MiB)
 Downloading nvidia-nccl-cu12 (307.4MiB)
 Downloading numpy (16.1MiB)
 Downloading nvidia-cusparse-cu12 (274.9MiB)
 Downloading nvidia-cusolver-cu12 (255.1MiB)
 Downloading nvidia-curand-cu12 (60.7MiB)
 Downloading nvidia-cudnn-cu12 (674.0MiB)
 Downloading nvidia-nvjitlink-cu12 (37.4MiB)
 Downloading nvidia-cublas-cu12 (566.8MiB)
 Downloading sympy (6.0MiB)
 Downloading nvidia-cuda-nvrtc-cu12 (84.0MiB)
 Downloading sherpa-onnx (4.2MiB)
 Downloading triton (148.3MiB)
 Downloading ctranslate2 (35.7MiB)
 Downloading networkx (2.0MiB)
 Downloading pydantic-core (2.0MiB)
 Downloading aiohttp (1.7MiB)
 Downloading kiwisolver (1.4MiB)
 Downloading gradio (41.0MiB)
 Downloading sqlalchemy (3.2MiB)
 Downloading tokenizers (3.1MiB)
 Downloading scipy (33.7MiB)
 Downloading cryptography (4.5MiB)
 Downloading torch (848.0MiB)
 Downloading torchaudio (3.8MiB)
 Downloading imageio-ffmpeg (28.1MiB)
 Downloading hf-xet (4.0MiB)
 Downloading fonttools (4.8MiB)
 Downloading espeakng-loader (9.6MiB)
 Downloading transformers (10.2MiB)
 Downloading ...

GitHub Actions: Security / 0_Python SAST (bandit).txt: refactor(settings): modularize Settings page (1969→399 lines, all files under 500)

Conclusion: failure

View job details

##[group]Run pipx run --spec 'bandit[sarif]' bandit -r backend/ -ll -ii -f sarif -o bandit.sarif
 �[36;1mpipx run --spec 'bandit[sarif]' bandit -r backend/ -ll -ii -f sarif -o bandit.sarif�[0m
 shell: /usr/bin/bash -e {0}
 env:
   FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
 ##[endgroup]
 creating virtual environment...
 installing bandit from spec 'bandit[sarif]'...
 [main]	INFO	profile include tests: None
 [main]	INFO	profile exclude tests: None
 [main]	INFO	cli include tests: None
 [main]	INFO	cli exclude tests: None
 [main]	INFO	running on Python 3.10.12
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/gallery.py:461
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/gallery.py:461
 [manager]	WARNING	Test in comment: fields is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: are is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: fixed is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: literal is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: assignments is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: term is not a test name or id, ignoring
 [manager]	WARNING	Test in comment: from is not a test name or id, ignoring
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/pronunciation.py:219
 [tester]	WARNING	nosec encountered (B608), but no failed test on file backend/api/routers/pronunciation.py:219
 [manager]	WARNING	Test in comment: local is not a test name or id, ignoring...

GitHub Actions: Security / Dependency audit: refactor(settings): modularize Settings page (1969→399 lines, all files under 500)

Conclusion: failure

View job details

##[group]Run uv sync
 �[36;1muv sync�[0m
 �[36;1muv run --with pip-audit pip-audit�[0m
 shell: /usr/bin/bash -e {0}
 env:
   FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
   UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
 ##[endgroup]
 Using CPython 3.11.15 interpreter at: /opt/hostedtoolcache/Python/3.11.15/x64/bin/python3.11
 Creating virtual environment at: .venv
 Resolved 284 packages in 176ms
    Building omnivoice @ file:///home/runner/work/OmniVoice-Studio/OmniVoice-Studio
 Downloading nvidia-cufft-cu12 (184.2MiB)
 Downloading nvidia-cuda-cupti-cu12 (9.8MiB)
 Downloading nvidia-nccl-cu12 (307.4MiB)
 Downloading numpy (16.1MiB)
 Downloading nvidia-cusparse-cu12 (274.9MiB)
 Downloading nvidia-cusolver-cu12 (255.1MiB)
 Downloading nvidia-curand-cu12 (60.7MiB)
 Downloading nvidia-cudnn-cu12 (674.0MiB)
 Downloading nvidia-nvjitlink-cu12 (37.4MiB)
 Downloading nvidia-cublas-cu12 (566.8MiB)
 Downloading sympy (6.0MiB)
 Downloading nvidia-cuda-nvrtc-cu12 (84.0MiB)
 Downloading sherpa-onnx (4.2MiB)
 Downloading triton (148.3MiB)
 Downloading ctranslate2 (35.7MiB)
 Downloading networkx (2.0MiB)
 Downloading pydantic-core (2.0MiB)
 Downloading aiohttp (1.7MiB)
 Downloading kiwisolver (1.4MiB)
 Downloading gradio (41.0MiB)
 Downloading sqlalchemy (3.2MiB)
 Downloading tokenizers (3.1MiB)
 Downloading scipy (33.7MiB)
 Downloading cryptography (4.5MiB)
 Downloading torch (848.0MiB)
 Downloading torchaudio (3.8MiB)
 Downloading imageio-ffmpeg (28.1MiB)
 Downloading hf-xet (4.0MiB)
 Downloading fonttools (4.8MiB)
 Downloading espeakng-loader (9.6MiB)
 Downloading transformers (10.2MiB)
 Downloading ...

GitHub Actions: Security / Dependency audit: refactor(settings): modularize Settings page (1969→399 lines, all files under 500)

Conclusion: failure

View job details

##[group]Run bun install --frozen-lockfile
 �[36;1mbun install --frozen-lockfile�[0m
 �[36;1mbun audit�[0m
 shell: /usr/bin/bash -e {0}
 env:
   FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
   UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
 ##[endgroup]
 bun install v1.2.0 (b0c5a765)
 + `@eslint/js`@10.0.1
 + `@playwright/test`@1.61.0
 + `@tauri-apps/api`@2.11.0
 + `@tauri-apps/cli`@2.11.2
 + `@testing-library/jest-dom`@6.9.1
 + `@testing-library/react`@16.3.2
 + `@types/react`@19.2.17
 + `@types/react-dom`@19.2.3
 + `@vitejs/plugin-react`@6.0.2
 + eslint@10.5.0
 + eslint-plugin-react-hooks@7.1.1
 + eslint-plugin-react-refresh@0.5.3
 + globals@17.6.0
 + jsdom@29.1.1
 + playwright-core@1.61.0
 + typescript@6.0.3
 + vite@8.0.16
 + vitest@4.1.9
 + `@fontsource-variable/inter`@5.2.8
 + `@fontsource-variable/source-serif-4`@5.2.9
 + `@fontsource/ibm-plex-mono`@5.2.7
 + `@radix-ui/react-dialog`@1.1.17
 + `@radix-ui/react-dropdown-menu`@2.1.18
 + `@radix-ui/react-popover`@1.1.17
 + `@radix-ui/react-progress`@1.1.10
 + `@radix-ui/react-select`@2.3.1
 + `@radix-ui/react-slider`@1.4.1
 + `@radix-ui/react-tabs`@1.1.15
 + `@radix-ui/react-toggle-group`@1.1.13
 + `@radix-ui/react-tooltip`@1.2.10
 + `@tailwindcss/vite`@4.3.1
 + `@tanstack/react-query`@5.101.0
 + `@tanstack/react-table`@8.21.3
 + `@tanstack/react-virtual`@3.14.3
 + `@tauri-apps/plugin-dialog`@2.7.1
 + `@tauri-apps/plugin-opener`@2.5.4
 + `@tauri-apps/plugin-process`@2.3.1
 + `@tauri-apps/plugin-updater`@2.10.1
 + `@tauri-apps/plugin-window-state`@2.4.1
 + country-flag-icons@1.6.17
 + i18next@26.3.1
 + i18next-browser-languagedetector@8.2.1
 + lucide-react@1.18.0
 + qrcode@1.5.4
 + react@19.2.7
 +...
🧰 Additional context used
📓 Path-based instructions (7)
{frontend/src/**/*.{js,jsx,ts,tsx},frontend/src/i18n/locales/**/*.{json,js,ts}}

📄 CodeRabbit inference engine (Custom checks)

For every new or changed t('...') key in frontend code, verify the key exists in all 21 files under frontend/src/i18n/locales/. List any locale files missing the key. Also flag hardcoded user-facing strings that bypass i18n entirely.

Files:

  • frontend/src/components/settings/Row.jsx
  • frontend/src/components/settings/models/ModelsTable.jsx
  • frontend/src/components/settings/native.js
  • frontend/src/components/settings/PrivacyTab.jsx
  • frontend/src/components/settings/models/format.js
  • frontend/src/components/settings/EnginesTab.jsx
  • frontend/src/components/settings/models/runtime.js
  • frontend/src/components/settings/AboutTab.jsx
  • frontend/src/components/settings/GeneralTab.jsx
  • frontend/src/components/settings/HotkeyTab.jsx
  • frontend/src/components/settings/models/RecoBanner.jsx
  • frontend/src/components/settings/LogsTab.jsx
  • frontend/src/components/settings/CredentialsTab.jsx
  • frontend/src/components/settings/models/columns.jsx
  • frontend/src/components/settings/ModelStoreTab.jsx
  • frontend/src/pages/Settings.jsx
**

⚙️ CodeRabbit configuration file

**:

Project

OmniVoice Studio

OmniVoice Studio is an open-source, fully-local ElevenLabs alternative — a desktop app for voice cloning, voice design, video dubbing, and real-time dictation across 646 languages. It runs entirely on the user's machine (CUDA/MPS/ROCm/CPU auto-detect), with no API keys, no accounts, and no cloud dependencies. It's an active beta with a growing user base who hit it with real workloads (50-video batches, multi-engine setups, edge-OS platforms) and report friction in GitHub Issues and Discord. The latest stable release is v0.3.5; main rolls ahead at v0.3.6 (latest release + 1 patch — see the Versioning rule below).

Core Value: A first-run that actually works. A user who downloads the installer (or clones the repo) should reach a working voice-cloning or dubbing output without hitting a wall — and when something does go wrong, the error or docs should tell them exactly what to do.

Everything else (new engines, fancy features) is downstream of "the thing installs and runs reliably across platforms, with the engines and pipelines users already depend on staying compatible."

Constraints

  • Existing engine compatibility: Users with already-installed engines (IndexTTS, CosyVoice, etc.) must not have to reinstall. Fixes touching engine code must be backward-compatible with on-disk model state.
  • Cross-platform parity: Every fix must work on macOS (Apple Silicon + Intel), Windows (x64), and Linux (AppImage + deb). No platform-only regressions; the cross-platform bug bash (PR #51) is the baseline.
  • Default features must work on every platform (strict rule, 2026-05-20): A feature that ships in default mode — out-of-the-box, no user customization, no opt-in toggle — must behave identically on macOS, Windows, and Linux. Platform-specific implementation code is allowed for OS APIs / shells / packaging, but the user-visible default behavior cannot diverge. P...

Files:

  • frontend/src/components/settings/Row.jsx
  • frontend/src/components/settings/models/ModelsTable.jsx
  • frontend/src/components/settings/native.js
  • frontend/src/components/settings/PrivacyTab.jsx
  • frontend/src/components/settings/models/format.js
  • frontend/eslint.config.js
  • frontend/src/components/settings/EnginesTab.jsx
  • frontend/src/components/settings/models/runtime.js
  • frontend/src/components/settings/AboutTab.jsx
  • frontend/src/components/settings/GeneralTab.jsx
  • frontend/src/components/settings/HotkeyTab.jsx
  • frontend/src/components/settings/models/RecoBanner.jsx
  • frontend/src/components/settings/LogsTab.jsx
  • CONTRIBUTING.md
  • frontend/src/components/settings/CredentialsTab.jsx
  • frontend/src/components/settings/models/columns.jsx
  • docs/maintenance-pages-modularization.md
  • frontend/src/components/settings/ModelStoreTab.jsx
  • frontend/src/pages/Settings.jsx
**/*.{py,rs,js,jsx,ts,tsx}

⚙️ CodeRabbit configuration file

OmniVoice is fully-local (no cloud, no API keys, no telemetry). Flag any new outbound network call that is not to github.com issues, a HuggingFace model download, or an explicitly opt-in endpoint. Flag any code that persists or logs values matching TOKEN/KEY/SECRET or absolute user home paths (/Users//, C:\Users\\).

Files:

  • frontend/src/components/settings/Row.jsx
  • frontend/src/components/settings/models/ModelsTable.jsx
  • frontend/src/components/settings/native.js
  • frontend/src/components/settings/PrivacyTab.jsx
  • frontend/src/components/settings/models/format.js
  • frontend/eslint.config.js
  • frontend/src/components/settings/EnginesTab.jsx
  • frontend/src/components/settings/models/runtime.js
  • frontend/src/components/settings/AboutTab.jsx
  • frontend/src/components/settings/GeneralTab.jsx
  • frontend/src/components/settings/HotkeyTab.jsx
  • frontend/src/components/settings/models/RecoBanner.jsx
  • frontend/src/components/settings/LogsTab.jsx
  • frontend/src/components/settings/CredentialsTab.jsx
  • frontend/src/components/settings/models/columns.jsx
  • frontend/src/components/settings/ModelStoreTab.jsx
  • frontend/src/pages/Settings.jsx
frontend/src/**/*.{js,jsx,ts,tsx}

⚙️ CodeRabbit configuration file

Review as a product-minded senior frontend engineer. Check: stale state and races (async results landing after unmount or after newer requests); every user-visible failure has an actionable, non-technical error message; loading/disabled states during long operations. Every new user-facing string must be an i18n t('...') key present in ALL 21 frontend/src/i18n/locales/*.json files — flag hardcoded UI strings and keys missing from any locale.

Files:

  • frontend/src/components/settings/Row.jsx
  • frontend/src/components/settings/models/ModelsTable.jsx
  • frontend/src/components/settings/native.js
  • frontend/src/components/settings/PrivacyTab.jsx
  • frontend/src/components/settings/models/format.js
  • frontend/src/components/settings/EnginesTab.jsx
  • frontend/src/components/settings/models/runtime.js
  • frontend/src/components/settings/AboutTab.jsx
  • frontend/src/components/settings/GeneralTab.jsx
  • frontend/src/components/settings/HotkeyTab.jsx
  • frontend/src/components/settings/models/RecoBanner.jsx
  • frontend/src/components/settings/LogsTab.jsx
  • frontend/src/components/settings/CredentialsTab.jsx
  • frontend/src/components/settings/models/columns.jsx
  • frontend/src/components/settings/ModelStoreTab.jsx
  • frontend/src/pages/Settings.jsx
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: HuggingFace token persistence: Use huggingface_hub.login(token=val, add_to_git_credential=False) to write tokens to $HF_HOME/token. Environment variable HF_TOKEN can be set as an override but should not be the only persistence mechanism.
Bug reporting (opt-in): Use the prefilled-URL GitHub Issues pattern: github.com/{owner}/{repo}/issues/new?title=…&body=…&labels=… opened via Tauri's shell.open(). No tokens stored in OmniVoice. User reviews the prefilled form in their browser and submits. Include captured system info (OS, CPU, GPU, Python version, backend git SHA, engine list) but exclude audio file contents, home directory paths, and any token/secret env vars.
Localization (hard rule): No hardcoded non-English user-facing text. All UI strings must go through i18n using t('...') keys in frontend/src/i18n/locales/*.json. Native language names live in frontend/src/i18n/index.ts (LANGUAGES export).
Cross-platform parity (hard rule): Every fix must work on macOS (Apple Silicon + Intel), Windows (x64), and Linux (AppImage + deb). No platform-only regressions. Default features must behave identically on all platforms. Platform-specific implementation is allowed for OS APIs/shells/packaging, but default user-visible behavior cannot diverge. Platform-only features must go behind explicit opt-in (Settings toggle, env var, or CLI flag).

Files:

  • frontend/src/components/settings/native.js
  • frontend/src/components/settings/models/format.js
  • frontend/eslint.config.js
  • frontend/src/components/settings/models/runtime.js
CONTRIBUTING.md

📄 CodeRabbit inference engine (CLAUDE.md)

Docs sync (hard rule): Any change to the contribution process, review standards, or developer workflow described in CONTRIBUTING.md must update this file in the same PR. If a process change is made without docs, the doc fix is the immediate next commit, not backlog.

Files:

  • CONTRIBUTING.md
docs/**

📄 CodeRabbit inference engine (CLAUDE.md)

Docs sync (hard rule): Any change to install flows, Docker tag semantics, platform support, versioning/release behavior, or tutorial content must update the corresponding docs/** files in the same PR. Stale docs are treated as bugs.

Files:

  • docs/maintenance-pages-modularization.md

⚙️ CodeRabbit configuration file

docs/**: # Desktop release plan — OmniVoice Studio

A shippable macOS (and eventually cross-platform) desktop release where the user drags the .app to Applications, double-clicks once, and does everything else from the UI — dependency runtime, model weights, first-run consent, all inside the app.

Stack: Tauri v2 + FastAPI sidecar + PyInstaller. Target: ~500 MB signed + notarized arm64 DMG, with matching Windows .msi/.nsis later. Large optional payloads (CUDA libs, extra model packs) ship as separate lazy-download tarballs, not in the base DMG.


Target architecture

Layer Contents Ships in DMG?
Tauri v2 shell (Rust) Native window, process lifecycle, filesystem paths Yes
Frontend bundle React/Vite build in .app/Contents/Resources/dist/ Yes
FastAPI sidecar binary PyInstaller-frozen omnivoice-backend with Python + torch + mlx + soundfile + demucs + yt_dlp + omnivoice TTS Yes (~400–500 MB bundle)
ffmpeg arm64 binary in .app/Contents/Resources/bin/ Yes (~20 MB)
Model weights (OmniVoice TTS, MLX Whisper) ~/Library/Application Support/OmniVoice/models/ No — first-run download
Optional engine packs (VoxCPM2 CUDA, pyannote, MOSS-TTS) Separate .tar.gz via GitHub Releases manifest No — first-run download if user opts in

Target DMG size: ~500 MB.
First-run model download: ~5 GB one-time.


Four key techniques

1. Sidecar port-reuse dance (dev ergonomics + crash recovery)

Tauri's startup flow:

  1. Check if 127.0.0.1:17493/health responds.
  2. If yes, verify JSON shape: status == "healthy", model_loaded: bool, gpu_available: bool. If valid, attach to the existing process instead of spawning.
  3. If a legacy port (8000) has an orphan, kill via lsof -ti :8000 | xargs kill -9.
  4. Otherwise spawn the frozen backend sidecar via Tauri's externalBin.
  5. On app close: send SIGTERM, wait 2 s, SIGKILL if still alive.

Why this matters:...

Files:

  • docs/maintenance-pages-modularization.md
🧠 Learnings (1)
📚 Learning: 2026-06-02T03:11:49.918Z
Learnt from: debpalash
Repo: debpalash/OmniVoice-Studio PR: 240
File: docs/superpowers/plans/2026-06-02-updates-status-bar.md:363-459
Timestamp: 2026-06-02T03:11:49.918Z
Learning: When reviewing code for OmniVoice Studio’s “fully-local / nothing leaves your machine” guarantee, treat it as targeting telemetry, required cloud services, accounts, and API keys—not every possible network call. Do NOT flag “local-first” violations for read-only, unauthenticated, user-initiated requests that can gracefully degrade if offline. Example: fetching the GitHub Releases list via `api.github.com` when the user opens the Updates panel is acceptable without requiring an extra opt-in gate (and the auto-updater already makes similar calls). Flag only when the network activity involves telemetry, required cloud services/accounts, or API keys/authenticated data flows, or prevents functionality without an opt-in.

Applied to files:

  • frontend/src/components/settings/Row.jsx
  • frontend/src/components/settings/models/ModelsTable.jsx
  • frontend/src/components/settings/native.js
  • frontend/src/components/settings/PrivacyTab.jsx
  • frontend/src/components/settings/models/format.js
  • frontend/eslint.config.js
  • frontend/src/components/settings/EnginesTab.jsx
  • frontend/src/components/settings/models/runtime.js
  • frontend/src/components/settings/AboutTab.jsx
  • frontend/src/components/settings/GeneralTab.jsx
  • frontend/src/components/settings/HotkeyTab.jsx
  • frontend/src/components/settings/models/RecoBanner.jsx
  • frontend/src/components/settings/LogsTab.jsx
  • frontend/src/components/settings/CredentialsTab.jsx
  • frontend/src/components/settings/models/columns.jsx
  • frontend/src/components/settings/ModelStoreTab.jsx
  • frontend/src/pages/Settings.jsx
🪛 ast-grep (0.44.0)
frontend/src/components/settings/models/ModelsTable.jsx

[warning] 33-33: A list component should have a key to prevent re-rendering
Context:
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 34-34: A list component should have a key to prevent re-rendering
Context:
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)

frontend/src/components/settings/AboutTab.jsx

[warning] 153-161: A list component should have a key to prevent re-rendering
Context:
<Badge tone={c.status === 'ok' ? 'success' : c.status === 'warn' ? 'warn' : 'danger'}>
{c.status === 'ok'
?
: } {t(about.self_check_${c.status})}

{' '}{c.detail}
{c.hint && — {c.hint}}

Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 154-158: A list component should have a key to prevent re-rendering
Context: <Badge tone={c.status === 'ok' ? 'success' : c.status === 'warn' ? 'warn' : 'danger'}>
{c.status === 'ok'
?
: } {t(about.self_check_${c.status})}

Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 156-156: A list component should have a key to prevent re-rendering
Context:
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 157-157: A list component should have a key to prevent re-rendering
Context:
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 160-160: A list component should have a key to prevent re-rendering
Context: — {c.hint}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)

frontend/src/components/settings/GeneralTab.jsx

[warning] 61-61: Avoid using the initial state variable in setState
Context: setLocale(id)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 75-75: Avoid using the initial state variable in setState
Context: setEnv('HTTP_PROXY', value)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 78-78: Avoid using the initial state variable in setState
Context: setEnv('HTTPS_PROXY', value)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 79-79: Avoid using the initial state variable in setState
Context: setEnv('ALL_PROXY', value)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 80-80: Avoid using the initial state variable in setState
Context: setEnv('http_proxy', value)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 81-81: Avoid using the initial state variable in setState
Context: setEnv('https_proxy', value)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 82-82: Avoid using the initial state variable in setState
Context: setEnv('all_proxy', value)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)

frontend/src/components/settings/HotkeyTab.jsx

[warning] 70-70: Avoid using the initial state variable in setState
Context: setPending(accel)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 84-84: Avoid using the initial state variable in setState
Context: setCurrent(saved)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 103-103: Avoid using the initial state variable in setState
Context: setCurrent(saved)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)

frontend/src/components/settings/models/RecoBanner.jsx

[warning] 65-65: A list component should have a key to prevent re-rendering
Context: {m.size_gb}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 66-66: A list component should have a key to prevent re-rendering
Context: {t('models.req_tag')}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)

frontend/src/components/settings/CredentialsTab.jsx

[warning] 38-38: Avoid using the initial state variable in setState
Context: setSaving(key)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 84-91: A list component should have a key to prevent re-rendering
Context: <>
{t(field.labelKey)}
{field.key === 'HF_TOKEN' && (
<Badge tone={info?.has_hf_token || saved.HF_TOKEN ? 'success' : 'warn'} size="xs">
{info?.has_hf_token || saved.HF_TOKEN ? t('credentials.saved') : t('credentials.not_set')}

)}
</>
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 87-89: A list component should have a key to prevent re-rendering
Context: <Badge tone={info?.has_hf_token || saved.HF_TOKEN ? 'success' : 'warn'} size="xs">
{info?.has_hf_token || saved.HF_TOKEN ? t('credentials.saved') : t('credentials.not_set')}

Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 94-99: A list component should have a key to prevent re-rendering
Context: <>
{t(field.helpKey)}
{field.link && (
<> <a href="#" onClick={e => { e.preventDefault(); openExternal(field.link); }}>{t('credentials.get_token')}</>
)}
</>
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 97-97: A list component should have a key to prevent re-rendering
Context: <> <a href="#" onClick={e => { e.preventDefault(); openExternal(field.link); }}>{t('credentials.get_token')}</>
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 97-97: A list component should have a key to prevent re-rendering
Context: <a href="#" onClick={e => { e.preventDefault(); openExternal(field.link); }}>{t('credentials.get_token')}
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 102-120: A list component should have a key to prevent re-rendering
Context: <>
<SettingsInput
type={field.isPassword ? 'password' : 'text'}
mono
placeholder={field.placeholderKey}
value={values[field.key] || ''}
onChange={e => setValues(prev => ({ ...prev, [field.key]: e.target.value }))}
onKeyDown={e => e.key === 'Enter' && save(field.key)}
/>
<Button
size="sm"
variant="subtle"
loading={saving === field.key}
onClick={() => save(field.key)}
disabled={!(values[field.key] || '').trim()}
>
{t('credentials.save')}

</>
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 103-110: A list component should have a key to prevent re-rendering
Context: <SettingsInput
type={field.isPassword ? 'password' : 'text'}
mono
placeholder={field.placeholderKey}
value={values[field.key] || ''}
onChange={e => setValues(prev => ({ ...prev, [field.key]: e.target.value }))}
onKeyDown={e => e.key === 'Enter' && save(field.key)}
/>
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)


[warning] 111-119: A list component should have a key to prevent re-rendering
Context: <Button
size="sm"
variant="subtle"
loading={saving === field.key}
onClick={() => save(field.key)}
disabled={!(values[field.key] || '').trim()}
>
{t('credentials.save')}

Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)

🪛 markdownlint-cli2 (0.22.1)
docs/maintenance-pages-modularization.md

[warning] 56-56: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 63-63: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe

(MD055, table-pipe-style)


[warning] 63-63: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe

(MD055, table-pipe-style)


[warning] 63-63: Table column count
Expected: 3; Actual: 1; Too few cells, row will be missing data

(MD056, table-column-count)


[warning] 64-64: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing leading pipe

(MD055, table-pipe-style)


[warning] 64-64: Table pipe style
Expected: leading_and_trailing; Actual: no_leading_or_trailing; Missing trailing pipe

(MD055, table-pipe-style)


[warning] 64-64: Table column count
Expected: 3; Actual: 1; Too few cells, row will be missing data

(MD056, table-column-count)

📝 Walkthrough

Walkthrough

Settings.jsx is refactored from ~1600 lines into a thin tab orchestrator that imports eight new dedicated tab components (GeneralTab, ModelStoreTab, EnginesTab, HotkeyTab, CredentialsTab, LogsTab, AboutTab, PrivacyTab). Shared helpers (native.js, Row.jsx, format.js, runtime.js) and model-store subcomponents (ModelsTable, RecoBanner, columns.jsx) are extracted. An ESLint max-lines warn rule and documentation for the multi-phase modularization plan are added.

Changes

Settings Modularization

Layer / File(s) Summary
ESLint guardrail and modularization docs
frontend/eslint.config.js, CONTRIBUTING.md, docs/maintenance-pages-modularization.md
Adds max-lines warn rule at 500 lines, contributing guidelines for frontend file structure, and a maintenance doc covering the multi-phase modularization plan with constraints and verification steps.
Shared helpers
frontend/src/components/settings/native.js, frontend/src/components/settings/Row.jsx, frontend/src/components/settings/models/format.js, frontend/src/components/settings/models/runtime.js
Introduces isTauri/askConfirm Tauri helpers, a Row wrapper delegating to SettingRow, fmtBytes/orgColor formatters, and computeRowRuntime for SSE-driven download state derivation.
Model store subcomponents
frontend/src/components/settings/models/columns.jsx, frontend/src/components/settings/models/ModelsTable.jsx, frontend/src/components/settings/models/RecoBanner.jsx
Extracts makeModelColumns (TanStack column factory with name/role/size/status/actions definitions), ModelsTable (virtualized renderer), and RecoBanner (recommendation install banner) from the former inline Settings implementation.
Simple tab components
frontend/src/components/settings/GeneralTab.jsx, frontend/src/components/settings/CredentialsTab.jsx, frontend/src/components/settings/EnginesTab.jsx, frontend/src/components/settings/PrivacyTab.jsx, frontend/src/components/settings/LogsTab.jsx
Five new tab components encapsulate locale/theme/proxy/FFmpeg settings, credential save flows with per-field saving state, engine selection with selectEngine wiring, privacy info display, and log source selection/viewing.
Complex tab components
frontend/src/components/settings/ModelStoreTab.jsx, frontend/src/components/settings/HotkeyTab.jsx, frontend/src/components/settings/AboutTab.jsx
ModelStoreTab wires SSE download streaming, TanStack table virtualization, and install/delete/reinstall actions. HotkeyTab captures keydown events and writes Tauri accelerators. AboutTab renders system info rows, Tauri-conditional update controls, self-check results, and diagnostic actions.
Settings.jsx thin orchestrator
frontend/src/pages/Settings.jsx
Drops ~1600 lines of inline tab UI, narrows imports to the eight new tab components plus isTauri/askConfirm from native.js, and retains tab navigation, deep-link state, and callback prop wiring.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • debpalash/OmniVoice-Studio#686: Row.jsx here delegates to the SettingRow primitive introduced in that design-system refactor.
  • debpalash/OmniVoice-Studio#690: Both PRs modify Settings.jsx and depend on the same SettingRow/SettingsInput shared primitives layer.
  • debpalash/OmniVoice-Studio#157: Both PRs directly overlap in Settings.jsx tab rendering — that PR wired i18n text for the same about/privacy/credentials tabs that this PR extracts into components.
🚥 Pre-merge checks | ✅ 6 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning Conventional-commit format is correct, but the title/body lacks the required issue reference. Add the issue key/reference to the title or PR body while keeping the refactor(scope): summary format.
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
I18n Completeness (21 Locales) ⚠️ Warning FAIL: 12 new i18n keys are missing from all 21 locale JSONs, and several settings UI strings still hardcode English (Confirm, theme labels, role labels, placeholders, fallbacks). Add the missing keys to every frontend/src/i18n/locales/*.json file and replace raw strings/default fallbacks with t(...) or translated constants in native.js, GeneralTab, ModelStoreTab, CredentialsTab, and models/columns.jsx.
✅ Passed checks (6 passed)
Check name Status Explanation
Description check ✅ Passed The description covers summary, key changes, verification, and rollout context, though it doesn't mirror every template section.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cross-Platform Default Parity ✅ Passed PASS: Platform-sensitive paths are gated (native.js:10-15, HotkeyTab.jsx:41-160); no new default behavior diverges across macOS/Windows/Linux.
Local-First Guarantee ✅ Passed New network paths are opt-in only—bug reports open prefilled GitHub Issues, model installs use HF downloads, and no telemetry hooks or mandatory cloud auth were added.
Backward Compatibility ✅ Passed Only frontend Settings files changed; backend model discovery still uses scan_cache_dir/on-disk fallback, and DB reconciliation remains additive-only.
✨ 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 refactor/settings-page-modularization

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR mechanically extracts the inline tab components from a 1969-line pages/Settings.jsx into dedicated files under components/settings/, plus a components/settings/models/ sub-package. It also adds a CONTRIBUTING.md size-limit section and an ESLint max-lines warn-only guardrail to prevent regrowth.

  • The Settings page is now a thin orchestrator (399 lines); all tab logic lives in its own file (GeneralTab, ModelStoreTab, EnginesTab, HotkeyTab, CredentialsTab, AboutTab, PrivacyTab, LogsTab).
  • ModelStoreTab is further split into a models/ sub-package — a makeModelColumns() factory, a computeRowRuntime() pure helper, a virtualised ModelsTable, RecoBanner, and formatting helpers.
  • A shared native.js module consolidates the isTauri() guard and askConfirm() Tauri-dialog shim that previously lived inline in Settings.jsx.

Confidence Score: 4/5

Purely mechanical split — logic moved byte-for-byte with no behavior change; all issues found are pre-existing style nits transferred from the original file.

Every changed file is a straight extraction of code that was already live in Settings.jsx. The three pre-existing issues (dead HF_TOKEN badge, t shadowing, missing useCallback dep) were already in production before this PR and carry no new risk. The build and existing tests pass. The only real gap is the stale status line in the planning doc.

CredentialsTab.jsx — the dead HF_TOKEN badge branch is worth cleaning up before the Collapsible section grows further. ModelStoreTab.jsx — the t/tid shadowing is harmless today but worth renaming to avoid future confusion.

Important Files Changed

Filename Overview
frontend/src/pages/Settings.jsx Slimmed to 399 lines — now a thin orchestrator that wires shared state (logs, update channel, sysinfo) and delegates all tab rendering to imported components.
frontend/src/components/settings/ModelStoreTab.jsx Largest extracted component (439L). Pre-existing naming collision: const t = setTimeout(...) inside the lifecycle-terminator useEffect shadows the t translation function from the enclosing scope.
frontend/src/components/settings/CredentialsTab.jsx Extracted from Settings.jsx. Pre-existing dead code: HF_TOKEN is filtered from the field list but the field.key === 'HF_TOKEN' badge branch inside the map is never reachable.
frontend/src/components/settings/EnginesTab.jsx Extracted from Settings.jsx. Pre-existing stale-closure lint issue: t is used inside the useCallback but omitted from the dependency array [].
frontend/src/components/settings/native.js New shared module wrapping the isTauri boolean from utils/media as a callable and providing a Tauri-dialog-safe askConfirm. All callers use it consistently as isTauri().
frontend/src/components/settings/models/columns.jsx Column factory (makeModelColumns) extracted from ModelStoreTab. Dependency array for useMemo in the host is unchanged; logic is identical to the original inline definition.
frontend/src/components/settings/models/runtime.js Pure helper (computeRowRuntime) with no React deps — correctly extracted so it can be unit-tested independently.
docs/maintenance-pages-modularization.md New planning doc whose header still reads Status: Plan (not yet executed) even though Phase 1 (Settings.jsx split) is being executed in this very PR.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    S["pages/Settings.jsx\n399 lines (was 1969)"]

    S --> G["settings/GeneralTab\n209L"]
    S --> M["settings/ModelStoreTab\n439L"]
    S --> E["settings/EnginesTab\n52L"]
    S --> H["settings/HotkeyTab\n166L"]
    S --> C["settings/CredentialsTab\n128L"]
    S --> A["settings/AboutTab\n175L"]
    S --> P["settings/PrivacyTab\n33L"]
    S --> L["settings/LogsTab\n79L"]

    S --> N["settings/native.js\nisTauri() / askConfirm()"]

    M --> MT["models/ModelsTable\n82L"]
    M --> RB["models/RecoBanner\n73L"]
    M --> CO["models/columns.jsx\n244L"]
    M --> RT["models/runtime.js\n75L"]
    M --> FO["models/format.js\n17L"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    S["pages/Settings.jsx\n399 lines (was 1969)"]

    S --> G["settings/GeneralTab\n209L"]
    S --> M["settings/ModelStoreTab\n439L"]
    S --> E["settings/EnginesTab\n52L"]
    S --> H["settings/HotkeyTab\n166L"]
    S --> C["settings/CredentialsTab\n128L"]
    S --> A["settings/AboutTab\n175L"]
    S --> P["settings/PrivacyTab\n33L"]
    S --> L["settings/LogsTab\n79L"]

    S --> N["settings/native.js\nisTauri() / askConfirm()"]

    M --> MT["models/ModelsTable\n82L"]
    M --> RB["models/RecoBanner\n73L"]
    M --> CO["models/columns.jsx\n244L"]
    M --> RT["models/runtime.js\n75L"]
    M --> FO["models/format.js\n17L"]
Loading

Comments Outside Diff (1)

  1. frontend/src/components/settings/CredentialsTab.jsx, line 411-425 (link)

    P2 Dead HF_TOKEN badge inside a filtered loop. The list is built with .filter(f => f.key !== 'HF_TOKEN'), so field.key === 'HF_TOKEN' is always false inside the map — the saved/not-set Badge will never render. This was already dead in the original Settings.jsx and is preserved verbatim here. Since ApiKeysPanel now owns HF-token display, the inner condition can safely be dropped: change the title prop to just {t(field.labelKey)}.

    Fix in Claude Code

Fix All in Claude Code

Reviews (1): Last reviewed commit: "refactor(settings): split ModelStoreTab ..." | Re-trigger Greptile

@debpalash
debpalash merged commit f33bdc7 into main Jun 29, 2026
15 checks passed
@debpalash
debpalash deleted the refactor/settings-page-modularization branch June 29, 2026 22:04
debpalash added a commit that referenced this pull request Jun 29, 2026
…00) (#760)

Phase 3 — same standard as #758/#759, applied to the last three over-cap pages.
Pure-mechanical, no behavior change.

- VoiceGallery.jsx 768 → 205: relocate the already-separate zone components
  (ArchetypesZone, ArchetypeCard, CommunityZone, ImportsZone) + shared helpers
  into components/gallery/.
- CloneDesignTab.jsx 837 → 395: split the ~540-line JSX return into section
  components (ScriptPanel, AudioMethodPanel, DesignMethodPanel, ActionBar) +
  MicButton, under components/clone/. State stays in the page.
- VoiceProfile.jsx 515 → 287: split the main return into ProfileHeader /
  ProfileDetails / ProfileActivity under components/profile/.

Safety contract for the JSX splits (no render tests): explicit NAMED props on
every section so eslint no-undef verifies completeness on both ends; JSX moved
verbatim. Verified: 0 no-undef across all changed files; every original
className preserved (diffed main vs new set); every file <500 lines.

Verified: vite build passes; FULL frontend suite 638/638 pass.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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