forked from phoenix/litellm-mirror
build(ui): client-side validation if key models are in new team
ensures when keys move teams, the models the key can call, are allowed by the team
This commit is contained in:
parent
5935b5d7e2
commit
666407f198
11 changed files with 65 additions and 47 deletions
|
@ -120,11 +120,9 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
|||
|
||||
const EditKeyModal: React.FC<EditKeyModalProps> = ({ visible, onCancel, token, onSubmit }) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
console.log("in edit key modal:", token);
|
||||
console.log("in edit key modal, team:", selectedTeam);
|
||||
|
||||
|
||||
const [keyTeam, setKeyTeam] = useState(selectedTeam);
|
||||
const [errorModels, setErrorModels] = useState<string[]>([]);
|
||||
const [errorBudget, setErrorBudget] = useState<boolean>(false);
|
||||
|
||||
const handleOk = () => {
|
||||
form
|
||||
|
@ -137,8 +135,8 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
|||
.catch((error) => {
|
||||
console.error("Validation failed:", error);
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Edit Key"
|
||||
|
@ -166,7 +164,23 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
|||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Models" name="models">
|
||||
<Form.Item label="Models" name="models" rules={[
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
const errorModels = value.filter((model: string) => (
|
||||
!keyTeam.models.includes(model) &&
|
||||
model !== "all-team-models" &&
|
||||
model !== "all-proxy-models"
|
||||
));
|
||||
console.log(`errorModels: ${errorModels}`)
|
||||
if (errorModels.length > 0) {
|
||||
return Promise.reject(`Some models are not part of the new team\'s models - ${errorModels}`);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
]}>
|
||||
<Select
|
||||
mode="multiple"
|
||||
placeholder="Select models"
|
||||
|
@ -175,42 +189,40 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
|||
<Option key="all-team-models" value="all-team-models">
|
||||
All Team Models
|
||||
</Option>
|
||||
{selectedTeam && selectedTeam.models ? (
|
||||
selectedTeam.models.includes("all-proxy-models") ? (
|
||||
userModels.filter(model => model !== "all-proxy-models").map((model: string) => (
|
||||
<Option key={model} value={model}>
|
||||
{model}
|
||||
</Option>
|
||||
))
|
||||
) : (
|
||||
selectedTeam.models.map((model: string) => (
|
||||
<Option key={model} value={model}>
|
||||
{model}
|
||||
</Option>
|
||||
))
|
||||
)
|
||||
) : (
|
||||
userModels.map((model: string) => (
|
||||
<Option key={model} value={model}>
|
||||
{model}
|
||||
</Option>
|
||||
))
|
||||
)}
|
||||
|
||||
|
||||
|
||||
{keyTeam && keyTeam.models ? (
|
||||
keyTeam.models.includes("all-proxy-models") ? (
|
||||
userModels.filter(model => model !== "all-proxy-models").map((model: string) => (
|
||||
<Option key={model} value={model}>
|
||||
{model}
|
||||
</Option>
|
||||
))
|
||||
) : (
|
||||
keyTeam.models.map((model: string) => (
|
||||
<Option key={model} value={model}>
|
||||
{model}
|
||||
</Option>
|
||||
))
|
||||
)
|
||||
) : (
|
||||
userModels.map((model: string) => (
|
||||
<Option key={model} value={model}>
|
||||
{model}
|
||||
</Option>
|
||||
))
|
||||
)}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
className="mt-8"
|
||||
label="Max Budget (USD)"
|
||||
name="max_budget"
|
||||
help={`Budget cannot exceed team max budget: $${selectedTeam?.max_budget !== null && selectedTeam?.max_budget !== undefined ? selectedTeam?.max_budget : 'unlimited'}`}
|
||||
help={`Budget cannot exceed team max budget: ${keyTeam?.max_budget !== null && keyTeam?.max_budget !== undefined ? keyTeam?.max_budget : 'unlimited'}`}
|
||||
rules={[
|
||||
{
|
||||
validator: async (_, value) => {
|
||||
if (value && selectedTeam && selectedTeam.max_budget !== null && value > selectedTeam.max_budget) {
|
||||
throw new Error(`Budget cannot exceed team max budget: $${selectedTeam.max_budget}`);
|
||||
if (value && keyTeam && keyTeam.max_budget !== null && value > keyTeam.max_budget) {
|
||||
console.log(`keyTeam.max_budget: ${keyTeam.max_budget}`)
|
||||
throw new Error(`Budget cannot exceed team max budget: $${keyTeam.max_budget}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -228,16 +240,17 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
|||
name="team_id"
|
||||
help="the team this key belongs to"
|
||||
>
|
||||
<Select value={token.team_alias}>
|
||||
<Select3 value={token.team_alias}>
|
||||
{teams?.map((team_obj, index) => (
|
||||
<SelectItem
|
||||
key={index}
|
||||
value={team_obj.team_id}
|
||||
onClick={() => setKeyTeam(team_obj)}
|
||||
>
|
||||
{team_obj.team_alias}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</Select3>
|
||||
</Form.Item>
|
||||
</>
|
||||
<div style={{ textAlign: "right", marginTop: "10px" }}>
|
||||
|
@ -270,10 +283,15 @@ const handleEditCancel = () => {
|
|||
};
|
||||
|
||||
const handleEditSubmit = async (formValues: Record<string, any>) => {
|
||||
// Call API to update team with teamId and values
|
||||
/**
|
||||
* Call API to update team with teamId and values
|
||||
*
|
||||
* Client-side validation: For selected team, ensure models in team + max budget < team max budget
|
||||
*/
|
||||
if (accessToken == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentKey = formValues.token;
|
||||
formValues.key = currentKey;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue