Commit 035161e
committed
fix(ui/store): clear missing server fields on merge (#438)
Reported by Jason Landbridge (issue #438): after clicking "Approve all
tools" on a server, navigating to the Servers overview page kept showing
the "5 pending approval" quarantine badge even though everything was
approved. A hard refresh fixed it.
Root cause is a generalisation of the previously-special-cased
last_error bug:
The Pinia stores/servers.ts mergeServers helper updates each existing
server in place via Object.assign(existingServer, incomingServer). The
backend's enrichServersWithQuarantineStats (internal/httpapi/server.go)
only sets `Quarantine` when `pending > 0 || changed > 0`; once all tools
are approved the field disappears from the JSON entirely. Object.assign
adds and overwrites — it never deletes. The stale `quarantine: { pending_count: 5 }`
therefore survived on the in-place reactive object and ServerCard's
`server.quarantine?.pending_count` kept rendering the badge until a full
page reload replaced the array.
The author had already special-cased `last_error` for this exact reason.
The same pattern affects every conditional optional field — `quarantine`,
`oauth_status`, `token_expires_at`, `user_logged_out`, `health`,
`security_scan`, `diagnostic`, `error_code`, etc. — and Jason flagged
that he sees similar staleness "in several areas of the UI."
Fix: replace the one-field special case with a general key-sync. For
each key on the existing server that is absent on the incoming server,
delete it before Object.assign. This treats the API response as
authoritative (which it is) and works for every conditional field
without enumerating them. The existing object reference is still
preserved, so v-memo on ServerCard keeps its stable identity and the
list does not visually rerender.
Tests in frontend/tests/unit/servers-store.spec.ts:
* drops the stale quarantine field when the backend stops emitting it
* drops last_error on recovery (regression coverage for the original
special case the new code subsumes)
* drops oauth_status / token_expires_at / user_logged_out together
* preserves the existing object reference across merges (identity
stability for v-memo)
* sanity: still updates and adds present fields
8 tests, all passing (5 new + 3 existing).
Note: a complementary backend change — emit `servers.changed` SSE on
tool approval — is in a separate PR so a Servers/overview page open in
another tab also reactively updates without depending on the Approve
flow's explicit fetchServers() call. This PR is the primary fix; the
SSE one is the cross-tab improvement.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent f9c8d0e commit 035161e
2 files changed
Lines changed: 147 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
59 | 68 | | |
60 | | - | |
61 | 69 | | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | 70 | | |
68 | 71 | | |
69 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
14 | 143 | | |
15 | 144 | | |
16 | 145 | | |
| |||
0 commit comments