Skip to content

Commit ca4e9a6

Browse files
committed
feat(tui): redesign provider and mcp add/edit forms
1 parent 79dd57a commit ca4e9a6

File tree

10 files changed

+5535
-215
lines changed

10 files changed

+5535
-215
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# TUI Add Forms (Provider + MCP) Implementation Plan
2+
3+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4+
5+
**Goal:** Replace the current JSON-only “Add Provider” / “Add MCP Server” flow with a friendly, scooter-style form UI (templates + grouped fields + live JSON preview) while keeping an escape hatch to advanced JSON editing.
6+
7+
**Architecture:** Introduce a new `App::form` state machine (`ProviderAdd`, `McpAdd`) driven by key events. Render it in `cli/tui/ui.rs` with reusable mini-components (chip bar, field list, input box, JSON preview). On submit, generate JSON and reuse the existing `EditorSubmit::ProviderAdd` / `EditorSubmit::McpAdd` handling for persistence. Advanced JSON editing reuses `EditorState`; saving applies JSON back into the form (round-trip), without creating the entity until the user submits from the form.
8+
9+
**Tech Stack:** Rust, ratatui, crossterm, serde_json, toml
10+
11+
---
12+
13+
### Task 1: Add reusable form primitives
14+
15+
**Files:**
16+
- Create: `src-tauri/src/cli/tui/form.rs`
17+
- Modify: `src-tauri/src/cli/tui/mod.rs`
18+
- Test: `src-tauri/src/cli/tui/app.rs`
19+
20+
**Step 1: Write failing tests for single-line text input editing**
21+
22+
Add unit tests covering: `insert`, `backspace`, `left/right/home/end`, and UTF-8 cursor safety.
23+
24+
Run: `cd src-tauri && cargo test text_input_ -- -q`
25+
Expected: FAIL (types/functions not found).
26+
27+
**Step 2: Implement `TextInput` + helpers**
28+
29+
Implement `TextInput` with:
30+
- `value: String`, `cursor: usize` (char index)
31+
- editing ops: insert char, backspace/delete, move left/right/home/end, set value
32+
- `display_value(mask: bool)` helper for secret-like fields
33+
34+
**Step 3: Run tests**
35+
36+
Run: `cd src-tauri && cargo test text_input_ -- -q`
37+
Expected: PASS.
38+
39+
---
40+
41+
### Task 2: Add form state machine to `App`
42+
43+
**Files:**
44+
- Modify: `src-tauri/src/cli/tui/app.rs`
45+
- Test: `src-tauri/src/cli/tui/app.rs`
46+
47+
**Step 1: Write failing tests for “press `a` opens add-form”**
48+
49+
Add tests:
50+
- Providers page: `a` opens `FormState::ProviderAdd` (not JSON editor)
51+
- MCP page: `a` opens `FormState::McpAdd`
52+
53+
Run: `cd src-tauri && cargo test providers_a_opens_add_form mcp_a_opens_add_form -- -q`
54+
Expected: FAIL.
55+
56+
**Step 2: Implement `App::form` wiring**
57+
58+
- Add `form: Option<FormState>` to `App`
59+
- In `on_key`, handle form before global actions (`Esc`/`q` back)
60+
- Add `on_form_key(...)` to process input + focus + submit/cancel
61+
62+
**Step 3: Run tests**
63+
64+
Run: `cd src-tauri && cargo test providers_a_opens_add_form mcp_a_opens_add_form -- -q`
65+
Expected: PASS.
66+
67+
---
68+
69+
### Task 3: Provider add form (templates + fields + JSON)
70+
71+
**Files:**
72+
- Modify: `src-tauri/src/cli/tui/app.rs`
73+
- Modify: `src-tauri/src/cli/tui/ui.rs`
74+
- Modify: `src-tauri/src/cli/i18n.rs`
75+
- Test: `src-tauri/src/cli/tui/app.rs`
76+
77+
**Step 1: Write failing tests for provider JSON generation**
78+
79+
Add tests:
80+
- `Ctrl+S` on ProviderAdd form returns `Action::EditorSubmit { submit: ProviderAdd, content }`
81+
- JSON includes `id/name/settingsConfig` and uses `settingsConfig.env` keys for the active `AppType`
82+
83+
Run: `cd src-tauri && cargo test provider_add_form_ -- -q`
84+
Expected: FAIL.
85+
86+
**Step 2: Implement ProviderAdd form model**
87+
88+
Model requirements:
89+
- template chips (at least: `Custom`, `Official` per app)
90+
- fields: `id`, `name`, `websiteUrl`, `notes`
91+
- app-specific fields:
92+
- Claude: `ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_BASE_URL`, optional model envs
93+
- Codex: `base_url`, `model`, `wire_api`, `requires_openai_auth`, optional `env_key`, optional `OPENAI_API_KEY`
94+
- Gemini: `auth_type` (oauth/api-key), optional `GEMINI_API_KEY`, `GOOGLE_GEMINI_BASE_URL`, optional `GEMINI_MODEL`
95+
- auto-generate `id` from `name` (unless user edited `id` manually)
96+
- validation: id/name required (toast on missing)
97+
98+
**Step 3: Implement ProviderAdd form rendering**
99+
100+
In `ui.rs` render:
101+
- top key bar (mode-aware)
102+
- template chip bar (wrap-aware)
103+
- left: field list + field editor (scooter-style input box)
104+
- right: live JSON preview (scrollable)
105+
- focused border uses theme accent
106+
107+
**Step 4: Run tests**
108+
109+
Run: `cd src-tauri && cargo test provider_add_form_ -- -q`
110+
Expected: PASS.
111+
112+
---
113+
114+
### Task 4: MCP add form (fields + JSON)
115+
116+
**Files:**
117+
- Modify: `src-tauri/src/cli/tui/app.rs`
118+
- Modify: `src-tauri/src/cli/tui/ui.rs`
119+
- Modify: `src-tauri/src/cli/i18n.rs`
120+
- Test: `src-tauri/src/cli/tui/app.rs`
121+
122+
**Step 1: Write failing tests for MCP JSON generation**
123+
124+
Add tests:
125+
- `Ctrl+S` on McpAdd form returns `EditorSubmit::McpAdd`
126+
- JSON includes `id/name/server/apps` with `server.command` and `server.args`
127+
128+
Run: `cd src-tauri && cargo test mcp_add_form_ -- -q`
129+
Expected: FAIL.
130+
131+
**Step 2: Implement McpAdd form model + rendering**
132+
133+
Fields:
134+
- `id`, `name`
135+
- `command`
136+
- `args` (single-line; split by whitespace into JSON array for `server.args`)
137+
- `apps` checkboxes (Claude/Codex/Gemini)
138+
139+
**Step 3: Run tests**
140+
141+
Run: `cd src-tauri && cargo test mcp_add_form_ -- -q`
142+
Expected: PASS.
143+
144+
---
145+
146+
### Task 5: Advanced JSON round-trip + i18n polish
147+
148+
**Files:**
149+
- Modify: `src-tauri/src/cli/tui/app.rs`
150+
- Modify: `src-tauri/src/cli/i18n.rs`
151+
- Test: `src-tauri/src/cli/tui/app.rs`
152+
153+
**Step 1: Write failing tests**
154+
155+
Add tests:
156+
- From ProviderAdd/McpAdd form press `e` opens editor with `EditorSubmit::FormApplyJson { .. }`
157+
- In that editor, `Ctrl+S` parses JSON and updates form fields, then closes editor
158+
- Invalid JSON keeps editor open and shows error toast
159+
160+
Run: `cd src-tauri && cargo test form_apply_json_ -- -q`
161+
Expected: FAIL.
162+
163+
**Step 2: Implement `FormApplyJson` editor submit and apply logic**
164+
165+
Implementation notes:
166+
- parsing provider JSON can be via `serde_json::Value` → extract known keys (ignore unknown)
167+
- Codex config parsing uses `toml::from_str::<toml::Table>()` to pull `base_url/model/wire_api/env_key/requires_openai_auth`
168+
169+
**Step 3: Add missing i18n strings**
170+
171+
Add texts for: templates title, field labels, focus names, “JSON preview”, “Advanced JSON”, validation toasts.
172+
173+
**Step 4: Run tests**
174+
175+
Run: `cd src-tauri && cargo test form_apply_json_ -- -q`
176+
Expected: PASS.
177+
178+
---
179+
180+
### Task 6: Small correctness fix + verification
181+
182+
**Files:**
183+
- Modify: `src-tauri/src/cli/tui/data.rs`
184+
- Test: `src-tauri/src/cli/tui/data.rs`
185+
186+
**Step 1: Write failing test**
187+
188+
Add a unit test for Gemini `api_url` extraction to prefer `GOOGLE_GEMINI_BASE_URL`.
189+
190+
Run: `cd src-tauri && cargo test gemini_api_url_ -- -q`
191+
Expected: FAIL.
192+
193+
**Step 2: Implement fix**
194+
195+
Update `extract_api_url()` to check:
196+
- `GOOGLE_GEMINI_BASE_URL` (preferred)
197+
- fallback to legacy keys if present
198+
199+
**Step 3: Run verification**
200+
201+
Run:
202+
- `cd src-tauri && cargo fmt`
203+
- `cd src-tauri && cargo test`
204+
- `cd src-tauri && cargo clippy --all-targets -- -D warnings` (ok to document existing failures)
205+

0 commit comments

Comments
 (0)