You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 25da27a
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/webui.md
+64-11Lines changed: 64 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1238,7 +1238,7 @@ clients:
1238
1238
| Archived tasks page | the tab renders its empty state; the list, its restore and its delete need the archived-session contract |
1239
1239
| Usage & models three-source switching | the segmented tabs now match the desktop form (ticket 53), but they are a **view switcher** — they do not switch the model source in use; real Token Plan / MiniMax API / custom-model routing plus source badges still need a model-routing contract |
1240
1240
| MiniMax API key panel | input + connectivity test + save-and-use |
1241
-
| Custom model drag-reorder, per-model toggles, preset picker | provider contract work; adding is dialog-based (ticket 54), editing stays on the rail + editor surfaces |
1241
+
| Custom model drag-reorder, per-model toggles, preset picker | provider contract work; add, edit and delete all converge on one dialog (this batch), leaving the list to display and delete |
1242
1242
| Search keyword highlighting | the reference itself never wired it (component + keyframes defined, no call site) |
1243
1243
| General-page dataDir footer | see the section table above |
1244
1244
@@ -1263,10 +1263,10 @@ The Token Plan view is the desktop's five blocks (the tabs plus four cards):
1263
1263
| Invoice row | The one fully live affordance: 申请 ↗ opens the MiniMax open platform in a new tab |
1264
1264
1265
1265
The custom-models view is the existing provider panel (API keys, protocols,
1266
-
model lists, connection tests, preset one-click enable) with every
1267
-
`data-testid`unchanged; ticket 54 rebuilt the **add** flow into the
1268
-
desktop's dialog form (next section) while the rail + editor surfaces stay
1269
-
as the editing path.
1266
+
model lists, connection tests, preset one-click enable); ticket 54 rebuilt
1267
+
the **add** flow into the desktop's dialog form (next section) and this batch
1268
+
folded **editing** into that same dialog (see "One dialog also edits" below) —
1269
+
the panel is now a list plus a delete affordance, with no second editor.
1270
1270
1271
1271
**Add-model dialog (ticket 54, 53b)**
1272
1272
@@ -1276,7 +1276,7 @@ deep-link — opens the desktop's modal instead of appending a rail draft:
1276
1276
1277
1277
| Dialog region | Contract |
1278
1278
| --- | --- |
1279
-
| Provider select (「请选择提供商」) | Options are `GET /api/providers/presets` plus a 「+ 其他(自定义)」 sentinel; choosing a preset fills id / label / auth-type / baseURL and seeds 「API 格式」, choosing the sentinel expands the custom fields (id, display name, auth type, baseURL). DeepSeek / Zhipu AI(智谱)/ Moonshot AI (China) carry the reference's spellings; other local presets keep their catalogue labels. A 404 catalogue degrades to the custom-only dropdown |
1279
+
| Provider select (「请选择提供商」) | Options are `GET /api/providers/presets` plus a 「+ 其他(自定义)」 sentinel; choosing a preset fills id / label / auth-type / baseURL and seeds 「API 格式」, choosing the sentinel expands the custom fields (id, display name, auth type); 接口地址 is a top-level field for both branches — see "One dialog also edits" below. DeepSeek / Zhipu AI(智谱)/ Moonshot AI (China) carry the reference's spellings; other local presets keep their catalogue labels. A 404 catalogue degrades to the custom-only dropdown |
1280
1280
| API 格式 | The desktop's **second** field, rendered for every provider rather than only for 「其他(自定义)」. It is the existing wire `protocol` under the desktop's labels — `OpenAI Completions` / `Anthropic Messages` / `Gemini` — so no new format reaches the backend. Choosing a preset seeds it from that preset's own protocol and it stays editable afterwards. The protocol select that used to sit inside the custom branch was removed rather than kept alongside: two controls bound to one value is how the preset and custom branches end up disagreeing about what gets saved |
1281
1281
| 自定义 Headers | Rows of (name, value) with 「+ 添加 Header」 and a per-row remove, held as a **list** rather than an object so a half-typed row survives editing. A blank name is dropped, a name is trimmed but a value is not, and a later duplicate wins — all three decided in one place (`headerPairsToRecord`), so the dialog, the PUT body and the server cannot disagree. Zero rows render an explicit placeholder rather than collapsing. The collapse result lands in `auth.headers` on the PUT body and comes back in `auth.headers` on `GET /api/providers` |
1282
1282
| API key (`AntInput.Password`) | The eye toggle is safe here and only here: the field's value is what the user just typed, not a masked placeholder — the editor's no-reveal rule (keep-existing-key convention) is untouched |
@@ -1288,8 +1288,11 @@ deep-link — opens the desktop's modal instead of appending a rail draft:
1288
1288
Ticket 54 invariants — no server-contract change (the `/api/providers` PUT
1289
1289
body, `/api/set-model`, and every endpoint are untouched; the whole delta is
1290
1290
client-side plus tests and docs); every pre-existing `data-testid` on the
1291
-
panel/editor surfaces survives in source (`webapp/test/add-model-dialog.test.ts`
1292
-
pins the list); the preset catalogue, thinkingLevels editing semantics,
1291
+
panel/editor surfaces survived in source at the time
1292
+
(`webapp/test/add-model-dialog.test.ts` pinned 36 + 2) — **that assertion is
1293
+
now void**: after the flat editor's retirement its testids are pinned as
1294
+
must-not-return instead, while the list chrome's testids are still pinned
1295
+
one by one; the preset catalogue, thinkingLevels editing semantics,
1293
1296
provider grouping and the thinking-display exceptions are unchanged; the
1294
1297
auto-add deep-link still lands on the custom-models view, now opening the
1295
1298
dialog. The legacy rail-draft `addProvider` path and the editor's dead
local key-format check, then a real fetch against the configured
1340
1343
baseURL — with no new route. The dialog shell assembles the probe
1341
-
from the current form values (preset branch takes the preset's
1342
-
protocol/baseURL, custom branch takes the custom fields) with a 4s
1343
-
timeout, and renders 「可达 · Nms」 (success token) / 「不可达:
1344
+
from the current form values (the protocol comes from 「API 格式」,
1345
+
the endpoint from the top-level 接口地址 field — which this batch
1346
+
lifted out of the custom branch, so a preset is no longer pinned
1347
+
to its catalogue endpoint) with a 4s timeout, and renders 「可达 · Nms」 (success token) / 「不可达:
1344
1348
error」 (error token). **Granularity, stated honestly**: the probe
1345
1349
is endpoint-level (baseURL + key) and does not exercise the
1346
1350
entry's model id — the tooltip and this paragraph say so rather
@@ -1415,6 +1419,55 @@ reference and there is no second source to check it against. Rebuilding
1415
1419
the model-entry structure is a larger change than this batch and is left
1416
1420
alone.
1417
1421
1422
+
**This batch — one dialog also edits, the flat editor is retired, and
1423
+
「API 格式」 drives the endpoint surface.**
1424
+
1425
+
| Change | Contract |
1426
+
| --- | --- |
1427
+
| Editing runs through the same dialog | A click on a list row opens the **same** modal (`editTarget`), seeded by `editSeedFromDraft`: a preset provider lands on its own catalogue branch, a custom one on 「+ 其他(自定义)」. Id, display name, auth type, 接口地址, the custom headers and the model entries all arrive pre-filled. The title switches from 添加模型 to 编辑模型 (`providers.dialog.editTitle`). Two entry points share one form rather than two forms free to drift |
1428
+
| The commit starts from the stored record | The committed draft begins at the record being edited (`const base = editTarget ?? newDraftProvider()`); only the fields the form can reach are taken from form state. `enabled`, `preset` and `draftId` are properties of the **record**, not the form — rebuilding one would re-enable a provider the operator had disabled, or detach it from its preset. The panel locates and replaces the row by `draftId`, not by wire id: matching on the id would write a second record instead of renaming the first whenever a custom id is retyped |
1429
+
| The key still never lands on disk in edit mode | The edit seed's API Key is always `""`, the server's keep-the-existing-key sentinel; the masked value reaches the placeholder only and is never written back as a value. An untouched field preserves the stored credential; a typed one replaces it |
1430
+
| The flat editor is retired | `ProviderEditor` and its `ApiKeyInput` / `DraftModelList` / `DraftModelRow`, plus the panel-level 「保存供应商」 button, the whole-list validation and the selected-row probe, are deleted. Delete did not disappear with them: it moved onto the list row as 🗑 (`provider-delete-{draftId}`, `Popconfirm` confirmation). Preset rows still carry no delete, the retired editor's own rule — a preset's lifecycle belongs to the preset controls |
1431
+
| The row element changed | The row is now a `<div>` wrapper rather than a `<button>`: it holds a second clickable control, and a button inside a button is invalid HTML with ambiguous keyboard semantics. The row's edit control is `provider-row-edit-{draftId}`, its delete is `provider-delete-{draftId}` |
1432
+
| 接口地址 lifted to a top-level field | The field used to sit inside the 「+ 其他(自定义)」 branch, which meant **11 of the 12 preset providers could neither see nor change their endpoint**. It now renders for every provider: a preset choice seeds it with the catalogue endpoint, the operator may override it, and an empty field falls back to the same protocol default the server uses |
1433
+
1434
+
What the 「API 格式」 selection drives (`API_FORMAT_SPECS`, every value
1435
+
transcribed verbatim from `server/lib/providers-config.js` —
1436
+
`DEFAULT_BASE_URL` and `probe()`):
1437
+
1438
+
| Format | Default endpoint | What 连通检测 actually sends | How the key travels |
0 commit comments