mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-26 11:14:04 +00:00
working regenerate key flow
This commit is contained in:
parent
2615edc468
commit
40c018272c
2 changed files with 112 additions and 2 deletions
|
@ -770,6 +770,37 @@ export const claimOnboardingToken = async (
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const regenerateKeyCall = async (accessToken: string, keyToRegenerate: string) => {
|
||||||
|
try {
|
||||||
|
const url = proxyBaseUrl
|
||||||
|
? `${proxyBaseUrl}/key/${keyToRegenerate}/regenerate`
|
||||||
|
: `/key/${keyToRegenerate}/regenerate`;
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.text();
|
||||||
|
handleError(errorData);
|
||||||
|
throw new Error("Network response was not ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("Regenerate key Response:", data);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to regenerate key:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let ModelListerrorShown = false;
|
let ModelListerrorShown = false;
|
||||||
let errorTimer: NodeJS.Timeout | null = null;
|
let errorTimer: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
"use client";
|
"use client";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { keyDeleteCall, modelAvailableCall } from "./networking";
|
import { keyDeleteCall, modelAvailableCall } from "./networking";
|
||||||
import { InformationCircleIcon, StatusOnlineIcon, TrashIcon, PencilAltIcon } from "@heroicons/react/outline";
|
import { InformationCircleIcon, StatusOnlineIcon, TrashIcon, PencilAltIcon, RefreshIcon } from "@heroicons/react/outline";
|
||||||
import { keySpendLogsCall, PredictedSpendLogsCall, keyUpdateCall, modelInfoCall } from "./networking";
|
import { keySpendLogsCall, PredictedSpendLogsCall, keyUpdateCall, modelInfoCall, regenerateKeyCall } from "./networking";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Card,
|
Card,
|
||||||
Table,
|
Table,
|
||||||
|
Grid,
|
||||||
|
Col,
|
||||||
Button,
|
Button,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
|
@ -33,6 +35,8 @@ import {
|
||||||
Select,
|
Select,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
|
|
||||||
|
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
const isLocal = process.env.NODE_ENV === "development";
|
const isLocal = process.env.NODE_ENV === "development";
|
||||||
const proxyBaseUrl = isLocal ? "http://localhost:4000" : null;
|
const proxyBaseUrl = isLocal ? "http://localhost:4000" : null;
|
||||||
|
@ -109,6 +113,8 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
||||||
const [userModels, setUserModels] = useState([]);
|
const [userModels, setUserModels] = useState([]);
|
||||||
const initialKnownTeamIDs: Set<string> = new Set();
|
const initialKnownTeamIDs: Set<string> = new Set();
|
||||||
const [modelLimitModalVisible, setModelLimitModalVisible] = useState(false);
|
const [modelLimitModalVisible, setModelLimitModalVisible] = useState(false);
|
||||||
|
const [regenerateDialogVisible, setRegenerateDialogVisible] = useState(false);
|
||||||
|
const [regeneratedKey, setRegeneratedKey] = useState<string | null>(null);
|
||||||
|
|
||||||
const [knownTeamIDs, setKnownTeamIDs] = useState(initialKnownTeamIDs);
|
const [knownTeamIDs, setKnownTeamIDs] = useState(initialKnownTeamIDs);
|
||||||
|
|
||||||
|
@ -612,6 +618,18 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
||||||
setKeyToDelete(null);
|
setKeyToDelete(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRegenerateKey = async () => {
|
||||||
|
try {
|
||||||
|
const response = await regenerateKeyCall(accessToken, selectedToken.token);
|
||||||
|
setRegeneratedKey(response.key);
|
||||||
|
setRegenerateDialogVisible(false);
|
||||||
|
message.success("API Key regenerated successfully");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error regenerating key:", error);
|
||||||
|
message.error("Failed to regenerate API Key");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -768,6 +786,7 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
open={infoDialogVisible}
|
open={infoDialogVisible}
|
||||||
|
@ -867,6 +886,14 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => handleEditClick(item)}
|
onClick={() => handleEditClick(item)}
|
||||||
/>
|
/>
|
||||||
|
<Icon
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedToken(item);
|
||||||
|
setRegenerateDialogVisible(true);
|
||||||
|
}}
|
||||||
|
icon={RefreshIcon}
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
<Icon
|
<Icon
|
||||||
onClick={() => handleDelete(item)}
|
onClick={() => handleDelete(item)}
|
||||||
icon={TrashIcon}
|
icon={TrashIcon}
|
||||||
|
@ -942,6 +969,58 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
||||||
accessToken={accessToken}
|
accessToken={accessToken}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Regenerate Key Confirmation Dialog */}
|
||||||
|
<Modal
|
||||||
|
title="Regenerate API Key"
|
||||||
|
visible={regenerateDialogVisible}
|
||||||
|
onOk={handleRegenerateKey}
|
||||||
|
onCancel={() => setRegenerateDialogVisible(false)}
|
||||||
|
>
|
||||||
|
<p>Are you sure you want to regenerate this key?</p>
|
||||||
|
<p>Key Alias:</p>
|
||||||
|
<pre>{selectedToken?.key_alias || 'No alias set'}</pre>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
{/* Regenerated Key Display Modal */}
|
||||||
|
{regeneratedKey && (
|
||||||
|
<Modal
|
||||||
|
visible={!!regeneratedKey}
|
||||||
|
onOk={() => setRegeneratedKey(null)}
|
||||||
|
onCancel={() => setRegeneratedKey(null)}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<Grid numItems={1} className="gap-2 w-full">
|
||||||
|
<Title>Save your New Key</Title>
|
||||||
|
<Col numColSpan={1}>
|
||||||
|
<p>
|
||||||
|
Please save this new secret key somewhere safe and accessible. For
|
||||||
|
security reasons, <b>you will not be able to view it again</b> through
|
||||||
|
your LiteLLM account. If you lose this secret key, you will need to
|
||||||
|
generate a new one.
|
||||||
|
</p>
|
||||||
|
</Col>
|
||||||
|
<Col numColSpan={1}>
|
||||||
|
<Text className="mt-3">New API Key:</Text>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#f8f8f8",
|
||||||
|
padding: "10px",
|
||||||
|
borderRadius: "5px",
|
||||||
|
marginBottom: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<pre style={{ wordWrap: "break-word", whiteSpace: "normal" }}>
|
||||||
|
{regeneratedKey}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<CopyToClipboard text={regeneratedKey} onCopy={() => message.success("API Key copied to clipboard")}>
|
||||||
|
<Button className="mt-3">Copy API Key</Button>
|
||||||
|
</CopyToClipboard>
|
||||||
|
</Col>
|
||||||
|
</Grid>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue