Skip to content

Commit 89cc891

Browse files
fix(ui): preserve visibility selection when editing entities (#3402)
* fix: append visibility in edit form handlers to retain selection across edits Signed-off-by: Oriol Morros Vilaseca <OM368@student.aru.ac.uk> * fix(ui): add visibility append to A2A edit handler for consistency The handleEditA2AAgentFormSubmit handler was missing the formData.append("visibility", ...) call that all other edit and create handlers have. This ensures visibility is preserved when editing A2A agents, matching the pattern in the other five edit handlers. Closes #3391 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * test(ui): add tests for visibility preservation in edit form handlers Cover all six edit form submit handlers to verify that the visibility field selected by the user is included in the submitted FormData: tool, prompt, gateway, server, resource, and A2A agent. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix(ui): use formData.set() instead of append() to prevent duplicate visibility entries formData.append() creates a second visibility key in the submitted FormData. Since Starlette's ImmutableMultiDict resolves duplicate keys to the last value, this introduces ordering-dependent behavior. Replace all 12 append("visibility", ...) calls (6 create + 6 edit handlers) with set(), which replaces the existing entry instead of duplicating it. Also strengthen tests to assert exactly one visibility entry (toEqual([value]) instead of toContain(value)), so they now fail if duplicates are reintroduced. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * chore: fix trailing whitespace in sandbox.rs tests Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Oriol Morros Vilaseca <OM368@student.aru.ac.uk> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
1 parent 08f1f05 commit 89cc891

File tree

3 files changed

+343
-8
lines changed

3 files changed

+343
-8
lines changed

mcp-servers/rust/filesystem-server/src/sandbox.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ mod tests {
8383
let sandbox = Sandbox::new(vec![path.clone()]).await.unwrap();
8484
let roots = sandbox.get_roots();
8585
assert_eq!(roots.len(), 1);
86-
86+
8787
// On macOS, temp paths may be canonicalized from /var to /private/var
8888
// So we compare the canonicalized version of the temp_dir path
8989
let expected_canon = fs::canonicalize(temp_dir.path()).await.unwrap();
@@ -131,7 +131,7 @@ mod tests {
131131
.resolve_path(file_path.to_str().unwrap())
132132
.await
133133
.unwrap();
134-
134+
135135
// On macOS, temp paths may be canonicalized from /var to /private/var
136136
// So we compare against the canonicalized temp_dir path
137137
let expected_canon = fs::canonicalize(temp_dir.path()).await.unwrap();

mcpgateway/static/admin.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15627,7 +15627,7 @@ async function handleGatewayFormSubmit(e) {
1562715627
formData.set("oauth_grant_type", "");
1562815628
}
1562915629

15630-
formData.append("visibility", formData.get("visibility"));
15630+
formData.set("visibility", formData.get("visibility"));
1563115631

1563215632
const teamId = new URL(window.location.href).searchParams.get(
1563315633
"team_id",
@@ -15714,7 +15714,7 @@ async function handleResourceFormSubmit(e) {
1571415714

1571515715
const isInactiveCheckedBool = isInactiveChecked("resources");
1571615716
formData.append("is_inactive_checked", isInactiveCheckedBool);
15717-
formData.append("visibility", formData.get("visibility"));
15717+
formData.set("visibility", formData.get("visibility"));
1571815718
const teamId = new URL(window.location.href).searchParams.get(
1571915719
"team_id",
1572015720
);
@@ -15784,7 +15784,7 @@ async function handlePromptFormSubmit(e) {
1578415784

1578515785
const isInactiveCheckedBool = isInactiveChecked("prompts");
1578615786
formData.append("is_inactive_checked", isInactiveCheckedBool);
15787-
formData.append("visibility", formData.get("visibility"));
15787+
formData.set("visibility", formData.get("visibility"));
1578815788
const teamId = new URL(window.location.href).searchParams.get(
1578915789
"team_id",
1579015790
);
@@ -15854,6 +15854,7 @@ async function handleEditPromptFormSubmit(e) {
1585415854

1585515855
const isInactiveCheckedBool = isInactiveChecked("prompts");
1585615856
formData.append("is_inactive_checked", isInactiveCheckedBool);
15857+
formData.set("visibility", formData.get("visibility"));
1585715858

1585815859
// Submit via fetch
1585915860
const response = await fetch(form.action, {
@@ -15916,7 +15917,7 @@ async function handleServerFormSubmit(e) {
1591615917
const isInactiveCheckedBool = isInactiveChecked("servers");
1591715918
formData.append("is_inactive_checked", isInactiveCheckedBool);
1591815919

15919-
formData.append("visibility", formData.get("visibility"));
15920+
formData.set("visibility", formData.get("visibility"));
1592015921
const teamId = new URL(window.location.href).searchParams.get(
1592115922
"team_id",
1592215923
);
@@ -16093,7 +16094,7 @@ async function handleA2AFormSubmit(e) {
1609316094

1609416095
// ✅ Ensure visibility is captured from checked radio button
1609516096
// formData.set("visibility", visibility);
16096-
formData.append("visibility", formData.get("visibility"));
16097+
formData.set("visibility", formData.get("visibility"));
1609716098
const teamId = new URL(window.location.href).searchParams.get(
1609816099
"team_id",
1609916100
);
@@ -16195,7 +16196,7 @@ async function handleToolFormSubmit(event) {
1619516196
const isInactiveCheckedBool = isInactiveChecked("tools");
1619616197
formData.append("is_inactive_checked", isInactiveCheckedBool);
1619716198

16198-
formData.append("visibility", formData.get("visibility"));
16199+
formData.set("visibility", formData.get("visibility"));
1619916200
const teamId = new URL(window.location.href).searchParams.get(
1620016201
"team_id",
1620116202
);
@@ -16265,6 +16266,7 @@ async function handleEditToolFormSubmit(event) {
1626516266

1626616267
const isInactiveCheckedBool = isInactiveChecked("tools");
1626716268
formData.append("is_inactive_checked", isInactiveCheckedBool);
16269+
formData.set("visibility", formData.get("visibility"));
1626816270

1626916271
// Submit via fetch
1627016272
const response = await fetch(form.action, {
@@ -16360,6 +16362,7 @@ async function handleEditGatewayFormSubmit(e) {
1636016362

1636116363
const isInactiveCheckedBool = isInactiveChecked("gateways");
1636216364
formData.append("is_inactive_checked", isInactiveCheckedBool);
16365+
formData.set("visibility", formData.get("visibility"));
1636316366
// Submit via fetch
1636416367
const response = await fetch(form.action, {
1636516368
method: "POST",
@@ -16459,6 +16462,7 @@ async function handleEditA2AAgentFormSubmit(e) {
1645916462

1646016463
const isInactiveCheckedBool = isInactiveChecked("a2a-agents");
1646116464
formData.append("is_inactive_checked", isInactiveCheckedBool);
16465+
formData.set("visibility", formData.get("visibility"));
1646216466
// Submit via fetch
1646316467
const response = await fetch(form.action, {
1646416468
method: "POST",
@@ -16513,6 +16517,7 @@ async function handleEditServerFormSubmit(e) {
1651316517

1651416518
const isInactiveCheckedBool = isInactiveChecked("servers");
1651516519
formData.append("is_inactive_checked", isInactiveCheckedBool);
16520+
formData.set("visibility", formData.get("visibility"));
1651616521

1651716522
// Merge persistent selection store into FormData so off-screen selections are included
1651816523
[
@@ -16622,6 +16627,7 @@ async function handleEditResFormSubmit(e) {
1662216627

1662316628
const isInactiveCheckedBool = isInactiveChecked("resources");
1662416629
formData.append("is_inactive_checked", isInactiveCheckedBool);
16630+
formData.set("visibility", formData.get("visibility"));
1662516631
// Submit via fetch
1662616632
const response = await fetch(form.action, {
1662716633
method: "POST",

0 commit comments

Comments
 (0)