mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-27 11:43:54 +00:00
UI Fixes and Improvements (02/14/2025) p1 (#8546)
* fix(user_dashboard.tsx): add bounding height to keys table ui prevents table from exceeding page height * fix(create_key_button.tsx): do not require team to be selected when user creating keys - allow personal key creation * fix(team_info.tsx): allow proxy admin to edit/delete team members even when not specifically team admins
This commit is contained in:
parent
08aa201e15
commit
3deefc8e2f
5 changed files with 16 additions and 183 deletions
|
@ -277,7 +277,7 @@ export function AllKeysTable({
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full h-full overflow-hidden">
|
||||||
{selectedKeyId ? (
|
{selectedKeyId ? (
|
||||||
<KeyInfoView
|
<KeyInfoView
|
||||||
keyId={selectedKeyId}
|
keyId={selectedKeyId}
|
||||||
|
@ -289,7 +289,7 @@ export function AllKeysTable({
|
||||||
teams={teams}
|
teams={teams}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="border-b py-4">
|
<div className="border-b py-4 flex-1 overflow-hidden">
|
||||||
<div className="flex items-center justify-between w-full">
|
<div className="flex items-center justify-between w-full">
|
||||||
<TeamFilter
|
<TeamFilter
|
||||||
teams={teams}
|
teams={teams}
|
||||||
|
@ -324,15 +324,16 @@ export function AllKeysTable({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DataTable
|
<div className="h-[32rem] overflow-auto">
|
||||||
columns={columns.filter(col => col.id !== 'expander')}
|
<DataTable
|
||||||
data={keys}
|
columns={columns.filter(col => col.id !== 'expander')}
|
||||||
isLoading={isLoading}
|
data={keys}
|
||||||
getRowCanExpand={() => false}
|
isLoading={isLoading}
|
||||||
renderSubComponent={() => <></>}
|
getRowCanExpand={() => false}
|
||||||
/>
|
renderSubComponent={() => <></>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -289,7 +289,6 @@ const CreateKey: React.FC<CreateKeyProps> = ({
|
||||||
name="team_id"
|
name="team_id"
|
||||||
initialValue={team ? team.team_id : null}
|
initialValue={team ? team.team_id : null}
|
||||||
className="mt-8"
|
className="mt-8"
|
||||||
rules={[{ required: true, message: 'Please select a team' }]}
|
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
showSearch
|
showSearch
|
||||||
|
|
|
@ -2545,8 +2545,8 @@ export const teamMemberDeleteCall = async (
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
team_id: teamId,
|
team_id: teamId,
|
||||||
...(formValues.user_email && { user_email: formValues.user_email }),
|
...(formValues.user_email !== undefined && { user_email: formValues.user_email }),
|
||||||
...(formValues.user_id && { user_id: formValues.user_id })
|
...(formValues.user_id !== undefined && { user_id: formValues.user_id })
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,6 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
|
||||||
|
|
||||||
console.log("userModels in team info", userModels);
|
console.log("userModels in team info", userModels);
|
||||||
|
|
||||||
const canManageMembers = is_team_admin || is_proxy_admin;
|
|
||||||
const canEditTeam = is_team_admin || is_proxy_admin;
|
const canEditTeam = is_team_admin || is_proxy_admin;
|
||||||
|
|
||||||
const fetchTeamInfo = async () => {
|
const fetchTeamInfo = async () => {
|
||||||
|
@ -202,172 +201,6 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderSettingsPanel = () => {
|
|
||||||
if (!teamData?.team_info) return null;
|
|
||||||
const info = teamData.team_info;
|
|
||||||
|
|
||||||
// Extract existing guardrails from team metadata
|
|
||||||
let existingGuardrails: string[] = [];
|
|
||||||
try {
|
|
||||||
existingGuardrails = info.metadata?.guardrails || [];
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error extracting guardrails:", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEditing) {
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<Title>Team Settings</Title>
|
|
||||||
{canEditTeam && (
|
|
||||||
<Button type="primary" onClick={() => setIsEditing(true)}>
|
|
||||||
Edit Settings
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="mt-4 space-y-4">
|
|
||||||
<div>
|
|
||||||
<Text className="font-medium">Team Name</Text>
|
|
||||||
<Text>{info.team_alias}</Text>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Text className="font-medium">Team ID</Text>
|
|
||||||
<Text className="font-mono">{info.team_id}</Text>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Text className="font-medium">Created At</Text>
|
|
||||||
<Text>{new Date(info.created_at).toLocaleString()}</Text>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Text className="font-medium">Models</Text>
|
|
||||||
<div className="flex flex-wrap gap-2 mt-1">
|
|
||||||
{info.models.map((model, index) => (
|
|
||||||
<Badge key={index} color="red">
|
|
||||||
{model}
|
|
||||||
</Badge>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Text className="font-medium">Rate Limits</Text>
|
|
||||||
<Text>TPM: {info.tpm_limit || 'Unlimited'}</Text>
|
|
||||||
<Text>RPM: {info.rpm_limit || 'Unlimited'}</Text>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Text className="font-medium">Budget</Text>
|
|
||||||
<Text>Max: ${info.max_budget || 'Unlimited'}</Text>
|
|
||||||
<Text>Reset: {info.budget_duration || 'Never'}</Text>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Text className="font-medium">Status</Text>
|
|
||||||
<Badge color={info.blocked ? 'red' : 'green'}>
|
|
||||||
{info.blocked ? 'Blocked' : 'Active'}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<Title>Edit Team Settings</Title>
|
|
||||||
<Form
|
|
||||||
form={form}
|
|
||||||
onFinish={handleTeamUpdate}
|
|
||||||
initialValues={{
|
|
||||||
...info,
|
|
||||||
guardrails: existingGuardrails
|
|
||||||
}}
|
|
||||||
layout="vertical"
|
|
||||||
className="mt-4"
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label="Team Name"
|
|
||||||
name="team_alias"
|
|
||||||
rules={[{ required: true, message: "Please input a team name" }]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item label="Models" name="models">
|
|
||||||
<Select2
|
|
||||||
mode="multiple"
|
|
||||||
placeholder="Select models"
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
<Select2.Option
|
|
||||||
key="all-proxy-models"
|
|
||||||
value="all-proxy-models"
|
|
||||||
>
|
|
||||||
All Proxy Models
|
|
||||||
</Select2.Option>
|
|
||||||
{userModels.map((model) => (
|
|
||||||
<Select2.Option key={model} value={model}>
|
|
||||||
{getModelDisplayName(model)}
|
|
||||||
</Select2.Option>
|
|
||||||
))}
|
|
||||||
</Select2>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item label="Max Budget (USD)" name="max_budget">
|
|
||||||
<InputNumber step={0.01} precision={2} style={{ width: 200 }} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item label="Reset Budget" name="budget_duration">
|
|
||||||
<Select placeholder="n/a">
|
|
||||||
<Select.Option value="24h">daily</Select.Option>
|
|
||||||
<Select.Option value="7d">weekly</Select.Option>
|
|
||||||
<Select.Option value="30d">monthly</Select.Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item label="Tokens per minute Limit (TPM)" name="tpm_limit">
|
|
||||||
<InputNumber step={1} style={{ width: "100%" }} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item label="Requests per minute Limit (RPM)" name="rpm_limit">
|
|
||||||
<InputNumber step={1} style={{ width: "100%" }} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={
|
|
||||||
<span>
|
|
||||||
Guardrails{' '}
|
|
||||||
<Tooltip title="Setup your first guardrail">
|
|
||||||
<a
|
|
||||||
href="https://docs.litellm.ai/docs/proxy/guardrails/quick_start"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<InfoCircleOutlined style={{ marginLeft: '4px' }} />
|
|
||||||
</a>
|
|
||||||
</Tooltip>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
name="guardrails"
|
|
||||||
help="Select existing guardrails or enter new ones"
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
mode="tags"
|
|
||||||
placeholder="Select or enter guardrails"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<div className="flex justify-end gap-2 mt-6">
|
|
||||||
<Button onClick={() => setIsEditing(false)}>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button type="primary" htmlType="submit">
|
|
||||||
Save Changes
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div className="p-4">Loading...</div>;
|
return <div className="p-4">Loading...</div>;
|
||||||
}
|
}
|
||||||
|
@ -461,7 +294,7 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
|
||||||
<Text className="font-mono">{member.role}</Text>
|
<Text className="font-mono">{member.role}</Text>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{is_team_admin && (
|
{canEditTeam && (
|
||||||
<>
|
<>
|
||||||
<Icon
|
<Icon
|
||||||
icon={PencilAltIcon}
|
icon={PencilAltIcon}
|
||||||
|
|
|
@ -335,8 +335,8 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
|
||||||
|
|
||||||
console.log("inside user dashboard, selected team", selectedTeam);
|
console.log("inside user dashboard, selected team", selectedTeam);
|
||||||
return (
|
return (
|
||||||
<div className="w-full mx-4">
|
<div className="w-full mx-4 overflow-hidden h-[75vh]">
|
||||||
<Grid numItems={1} className="gap-2 p-8 h-[75vh] w-full mt-2">
|
<Grid numItems={1} className="gap-2 p-8 w-full mt-2">
|
||||||
<Col numColSpan={1} className="flex flex-col gap-2">
|
<Col numColSpan={1} className="flex flex-col gap-2">
|
||||||
<CreateKey
|
<CreateKey
|
||||||
key={selectedTeam ? selectedTeam.team_id : null}
|
key={selectedTeam ? selectedTeam.team_id : null}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue