Skip to content

feat: comprehensive settings screen#27

Merged
saucam merged 3 commits into
mainfrom
feat/settings-screen
Jul 16, 2026
Merged

feat: comprehensive settings screen#27
saucam merged 3 commits into
mainfrom
feat/settings-screen

Conversation

@saucam

@saucam saucam commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

What

PR 3 of 3 — the codeoid-ui (TUI) counterpart to the config-file-driven settings surface. A tabbed settings screen that is a pure renderer of whatever manifest the daemon serves over settings.schema (daemon-wide — no session needed). Companion to the daemon (highflame-ai/codeoid#186) + web (highflame-ai/codeoid#187).

How

codeoid-protocol

  • ClientMessage: settings.schema / settings.get / settings.set (+ SettingPatch).
  • DaemonMessage: settings.{schema,get,set}.result + the manifest/snapshot types (SettingsManifest / Tab / Group / Field / Option / Snapshot / State / SecretStatus / Error). kind / backing / source are strings so a new value the daemon introduces never breaks deserialization.
  • connection.rs: client_kind / daemon_kind arms for the new messages.

codeoid-tui

  • SettingsModal state — tabs, field cursor, staged edits (dirty), an inline text-edit buffer, secret status, save + restart tracking.
  • keymap: ModalKind::Settings (nav) + ModalKind::SettingsEdit (text buffer), each with a resolve block + tests — mirrors the existing UiDialog choice/text split.
  • reducer (app.rs): open_settings (fetch manifest + values), field/tab nav, activate (toggle boolean · cycle enum · open the buffer for text/number/secret), clear, save (one settings.set batch), refresh, and the three result arms in apply_daemon (staleness-guarded like Capabilities).
  • renderer (ui/modal.rs): tab pills + grouped fields, per-kind control display, provenance / secret-source / ⟳restart badges, the edit buffer, and a footer showing the on-disk config.json + .env paths.
  • /settings (aliases /config, /prefs) slash command + catalog entry.

Interactions

↑↓/jk field · ←→/hl tab · Enter/Space toggle-cycle-or-edit · s save · a advanced · x clear · r refresh · Esc/q close. In edit mode: type, Enter commits, Esc cancels. Secret values are never fetched or shown — only presence + source, with a write-only buffer.

Wire-additive: against an older daemon without the settings RPC, the fetch simply errors and the modal surfaces it.

Checks

  • cargo fmt --all -- --check ✅ · cargo build --all-targets ✅ · cargo test ✅ (314+ pass) · cargo clippy — only the repo's pre-existing pedantic warnings.

🤖 Generated with Claude Code

Add the codeoid-ui (TUI) counterpart to the config-file-driven settings
surface — a tabbed screen that renders whatever manifest the daemon serves
over `settings.schema`, so a new knob appears with no client changes.

Protocol crate:
- ClientMessage: settings.schema / settings.get / settings.set (+ SettingPatch).
- DaemonMessage: settings.{schema,get,set}.result + the manifest/snapshot
  types (SettingsManifest / Tab / Group / Field / Option / Snapshot / State /
  SecretStatus / Error). kind/backing/source kept as strings so a new value
  never breaks deserialization.
- connection.rs: client_kind / daemon_kind arms for the new messages.

TUI:
- SettingsModal state — tabs, field cursor, staged edits (dirty map), an
  inline text-edit buffer, secret status, and save/restart tracking.
- keymap: ModalKind::Settings (nav) + ModalKind::SettingsEdit (text buffer),
  with resolve blocks + tests.
- app reducer: open_settings (fetch manifest + values), field nav, activate
  (toggle bool / cycle enum / open buffer for text/number/secret), clear,
  save (settings.set batch), refresh, and the three result arms in
  apply_daemon (staleness-guarded like Capabilities).
- renderer: tab pills + grouped fields with per-kind control display,
  provenance / secret-source / restart badges, edit buffer, and a footer with
  the on-disk config.json + .env paths.
- `/settings` (aliases `/config`, `/prefs`) slash command + catalog entry.

Renders against a daemon carrying the settings RPC; on an older daemon the
fetch simply errors and the modal shows it. fmt + build + clippy + test clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread crates/codeoid-tui/src/app.rs Outdated
Comment thread crates/codeoid-tui/src/ui/modal.rs
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

🤖 Gemini code review

This PR implements a comprehensive, interactive terminal settings UI for Codeoid, allowing users to view and modify daemon-wide configuration fields, environment variables, and secrets. It correctly handles various input types (booleans, enums, numbers, arrays, and masked secrets), leverages asynchronous state updates with request/response correlation, and includes robust keymaps and unit tests. No bugs or security issues were found.

Findings: 🔴 0 · 🟠 0 · 🟡 0 · 🟢 0


Tokens spent · ⬆️ Input: 15,888 · ⬇️ Output: 95 · Σ Total: 22,266
Total may be higher due to thinking token counts.

- SettingsEdit no longer feeds Ctrl/Alt-modified chars into the field buffer,
  so a shortcut chord (Ctrl+A, Alt+F, …) can't insert its base letter.
- render_settings now scrolls: a fixed tab-rail header + a fixed footer, with
  the field body in its own viewport that follows the selected field. Tabs
  with more fields than fit no longer clip the selection off-screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@saucam

saucam commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini-review

Comment thread crates/codeoid-tui/src/app.rs
Address the second Gemini pass on #27: edit_string_to_value returned Null on a
parse failure, and Null clears the setting — so a typo like "12a" would silently
delete the value on save. Return the raw string instead; the daemon's schema
validation then rejects it with a visible error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@saucam

saucam commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini-review

@saucam
saucam merged commit af0596e into main Jul 16, 2026
1 check passed
This was referenced Jul 16, 2026
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