open-notebook/api/routers
Luis Novo 85336f49fa
fix: actually clear credential fields end to end (frontend payload + API null handling) (#1046)
* fix(frontend): actually clear credential fields when emptied in the edit dialog

Clearing base_url (or the Vertex project/location/credentials_path)
in the credential edit dialog silently did nothing: the submit handler
mapped an emptied field to `undefined`, JSON.stringify dropped the key
from the PUT body, and the backend's partial-update semantics kept the
old value — while the UI reported success.

Emptied fields are now sent as an explicit `null`, which the API
already accepts and persists as a cleared value (verified live).
UpdateCredentialRequest's nullable fields are typed accordingly.

Found in v1.11 release testing (pre-existing, not a release regression):
an Ollama credential with a stale IP in base_url could not be cleared
from the UI.

* fix(api): clear credential fields on explicit null, not just empty string

The update handler guarded every field with 'is not None', so a JSON
null sent to clear base_url (or endpoint/api_version/endpoint_*/
project/location/credentials_path/num_ctx) was silently skipped — the
old value survived while the client saw a 200. Combined with the
frontend bug fixed in the previous commit (emptied fields dropped from
the payload entirely), clearing a credential field was impossible from
the UI: during release testing an Ollama credential kept pointing at a
stale IP after being 'cleared', and only an empty-string PUT crafted by
hand actually cleared it.

Field updates are now keyed on presence in model_fields_set: absent
keeps the old value, explicit null or "" clears. name/modalities/
api_key keep their non-null guards (clearing those is not meaningful).

Regression tests cover null-clears, empty-string-clears, absent-keeps
and the Vertex credentials_path case.

* test(frontend): extract credential update payload builder and cover clear-on-empty

Addresses the cubic review: the frontend half of the fix had no
reproducing test. The edit dialog's payload construction now lives in
a pure buildCredentialUpdatePayload() (frontend/src/lib/
credential-update-payload.ts) used by the component, with tests that
fail on the original bug: an emptied base_url (and Vertex project/
location/credentials_path) must survive JSON.stringify as an explicit
null, unchanged fields must be omitted, and emptied num_ctx clears
via 0.
2026-07-11 09:00:06 -03:00
..
__init__.py Api podcast migration (#93) 2025-07-17 08:36:11 -03:00
auth.py feat: credential-based API key management (#477) (#540) 2026-02-10 08:30:22 -03:00
chat.py fix: batch source-insight lookups when building notebook/chat context (#1008) 2026-07-10 10:36:13 -03:00
commands.py Feat/localization tests docker (#371) 2026-01-15 13:51:05 -03:00
config.py Feat/localization tests docker (#371) 2026-01-15 13:51:05 -03:00
context.py fix: batch source-insight lookups when building notebook/chat context (#1008) 2026-07-10 10:36:13 -03:00
credentials.py fix: actually clear credential fields end to end (frontend payload + API null handling) (#1046) 2026-07-11 09:00:06 -03:00
embedding.py fix: surface silent command-submission failures where they matter (#1019) 2026-07-10 13:53:57 -03:00
embedding_rebuild.py Fix re-embedding issues and improve retry strategy (#515) 2026-01-31 18:55:01 -03:00
episode_profiles.py fix: pass max_tokens through to podcast_creator for outline/transcript generation (#982) 2026-07-03 12:23:19 -03:00
insights.py fix: prevent SurrealQL injection in repo_relate/repo_upsert/repo_update (#1002) 2026-07-10 10:26:31 -03:00
languages.py feat(podcasts): model registry integration, credential passthrough & new features (#632) 2026-02-27 11:06:47 -03:00
models.py fix: remove deprecated gemini models (#1027) 2026-07-10 15:59:56 -03:00
notebooks.py feat: Recently Viewed section for notebooks and sources (#979) 2026-07-03 12:39:14 -03:00
notes.py fix(api): return 404 instead of 500 for missing resources in CRUD endpoints (#862) (#924) 2026-06-18 08:23:28 -03:00
podcasts.py fix: contain podcast audio paths and batch job-status lookups (#1018) 2026-07-10 13:48:24 -03:00
search.py fix: stream SSE responses end-to-end through Next.js proxy (#770) 2026-06-21 14:49:15 -03:00
settings.py Feat/localization tests docker (#371) 2026-01-15 13:51:05 -03:00
source_chat.py fix: run chat graph invoke off the event loop (#971) 2026-06-25 07:26:46 -03:00
sources.py fix: sort sources by title without tripping the SEARCH index, return 422 for invalid form data (#1042) 2026-07-10 21:10:24 -03:00
speaker_profiles.py fix: use model_dump(exclude_unset=True) in PUT profile handlers (#860) 2026-06-13 08:56:33 -03:00
transformations.py feat: per-transformation custom model selection (#978) 2026-07-03 12:30:50 -03:00