feat(ui): team passthrough routes create parity + edit load fix (#28098)

* feat(ui): team allowed_passthrough_routes create parity + edit load fix

Add the Allowed Pass Through Routes selector to the create-team modal
(previously only on the edit form), and fix the edit form silently
dropping the field: it lives under team metadata, so initialValues must
read info.metadata.allowed_passthrough_routes — otherwise the selector
renders empty and saving wipes admin-set routes. Both selectors are
gated to premium proxy admins, mirroring the server-side gate.

Resolves LIT-3019

* fix(ui): persist team allowed_passthrough_routes edits on save

The edit form loaded the selector but the save path never wrote it back:
allowed_passthrough_routes stayed in the raw metadata JSON textarea and
parsedMetadata (from that textarea) always won, so selector edits were
silently discarded. Strip it from the textarea initialValues and overlay
values.allowed_passthrough_routes into updateData.metadata, mirroring how
guardrails is handled.

Resolves LIT-3019

* fix(ui): preserve team passthrough routes for non-proxy-admins on save

Only proxy admins may set allowed_passthrough_routes (server-side gate).
For non-proxy-admins, write the team's stored value back into metadata
instead of the form value, so saving an unrelated setting can't silently
wipe routes; omit the key entirely when the team never had any.

Resolves LIT-3019
This commit is contained in:
ryan-crabbe-berri 2026-05-20 12:35:49 -07:00 committed by GitHub
parent 5a00cb1592
commit fb73995c40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 7 deletions

View file

@ -45,6 +45,7 @@ import OrganizationDropdown from "./common_components/OrganizationDropdown";
import TableIconActionButton from "./common_components/IconActionButton/TableIconActionButtons/TableIconActionButton";
import { teamListCall as v2TeamListCall, type TeamsResponse } from "@/app/(dashboard)/hooks/teams/useTeams";
import AccessGroupSelector from "./common_components/AccessGroupSelector";
import PassThroughRoutesSelector from "./common_components/PassThroughRoutesSelector";
import AgentSelector from "./agent_management/AgentSelector";
import ModelAliasManager from "./common_components/ModelAliasManager";
import PremiumLoggingSettings from "./common_components/PremiumLoggingSettings";
@ -1446,6 +1447,30 @@ const Teams: React.FC<TeamProps> = ({
placeholder="Select vector stores (optional)"
/>
</Form.Item>
<Form.Item
label="Allowed Pass Through Routes"
name="allowed_passthrough_routes"
className="mt-8"
>
<Tooltip
title={
!premiumUser
? "Premium feature - Upgrade to set allowed pass through routes"
: !isProxyAdminRole(userRole || "")
? "Only proxy admins can set allowed pass through routes"
: ""
}
placement="top"
>
<PassThroughRoutesSelector
onChange={(values: string[]) => form.setFieldValue("allowed_passthrough_routes", values)}
value={form.getFieldValue("allowed_passthrough_routes")}
accessToken={accessToken || ""}
placeholder="Select pass through routes (optional)"
disabled={!premiumUser || !isProxyAdminRole(userRole || "")}
/>
</Tooltip>
</Form.Item>
</AccordionBody>
</Accordion>

View file

@ -502,6 +502,14 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
(n) => !(values.guardrails || []).includes(n),
);
// Non-proxy-admins can't set allowed_passthrough_routes; preserve the
// stored value so an unrelated save can't wipe it.
const passthroughRoutesMetadata = is_proxy_admin
? { allowed_passthrough_routes: values.allowed_passthrough_routes || [] }
: info.metadata?.allowed_passthrough_routes
? { allowed_passthrough_routes: info.metadata.allowed_passthrough_routes }
: {};
const updateData: any = {
team_id: teamId,
team_alias: values.team_alias,
@ -515,6 +523,7 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
budget_duration: values.budget_duration,
metadata: {
...parsedMetadata,
...passthroughRoutesMetadata,
guardrails: (values.guardrails || []).filter((n: string) => !globalGuardrailNames.has(n)),
opted_out_global_guardrails: optedOutGlobalGuardrails,
...(values.logging_settings?.length > 0 ? { logging: values.logging_settings } : {}),
@ -961,7 +970,7 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
: "",
metadata: info.metadata
? JSON.stringify(
(({ logging, secret_manager_settings, soft_budget_alerting_emails, model_tpm_limit, model_rpm_limit, ...rest }) => rest)(info.metadata),
(({ logging, secret_manager_settings, soft_budget_alerting_emails, model_tpm_limit, model_rpm_limit, allowed_passthrough_routes, ...rest }) => rest)(info.metadata),
null,
2,
)
@ -986,6 +995,7 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
},
access_group_ids: info.access_group_ids || [],
default_team_member_models: info.default_team_member_models || [],
allowed_passthrough_routes: info.metadata?.allowed_passthrough_routes || [],
}}
layout="vertical"
>
@ -1338,12 +1348,24 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
</Form.Item>
<Form.Item label="Allowed Pass Through Routes" name="allowed_passthrough_routes">
<PassThroughRoutesSelector
onChange={(values: string[]) => form.setFieldValue("allowed_passthrough_routes", values)}
value={form.getFieldValue("allowed_passthrough_routes")}
accessToken={accessToken || ""}
placeholder="Select pass through routes"
/>
<Tooltip
title={
!premiumUser
? "Premium feature - Upgrade to set allowed pass through routes"
: !is_proxy_admin
? "Only proxy admins can set allowed pass through routes"
: ""
}
placement="top"
>
<PassThroughRoutesSelector
onChange={(values: string[]) => form.setFieldValue("allowed_passthrough_routes", values)}
value={form.getFieldValue("allowed_passthrough_routes")}
accessToken={accessToken || ""}
placeholder="Select pass through routes"
disabled={!premiumUser || !is_proxy_admin}
/>
</Tooltip>
</Form.Item>
<Form.Item label="MCP Servers / Access Groups" name="mcp_servers_and_groups">