完善 API Key 能力范围可视化和维护
This commit is contained in:
+45
-10
@@ -10,6 +10,7 @@ import type {
|
||||
GatewayAccessRule,
|
||||
GatewayAccessRuleUpsertRequest,
|
||||
GatewayApiKey,
|
||||
GatewayApiKeyScopeUpdateRequest,
|
||||
GatewayAuditLog,
|
||||
GatewayNetworkProxyConfig,
|
||||
GatewayRunnerPolicy,
|
||||
@@ -31,7 +32,7 @@ import type {
|
||||
RuntimePolicySet,
|
||||
UserGroupUpsertRequest,
|
||||
UserGroup,
|
||||
WalletBalanceAdjustmentRequest,
|
||||
WalletRechargeRequest,
|
||||
} from '@easyai-ai-gateway/contracts';
|
||||
import {
|
||||
batchAccessRules,
|
||||
@@ -53,6 +54,7 @@ import {
|
||||
GatewayApiError,
|
||||
getHealth,
|
||||
listFileStorageChannels,
|
||||
getCurrentUser,
|
||||
getFileStorageSettings,
|
||||
getNetworkProxyConfig,
|
||||
getRunnerPolicy,
|
||||
@@ -63,6 +65,7 @@ import {
|
||||
listApiKeys,
|
||||
listBaseModels,
|
||||
listCatalogProviders,
|
||||
listCurrentUserGroups,
|
||||
listModelCatalog,
|
||||
listModelRateLimitStatuses,
|
||||
listModels,
|
||||
@@ -83,11 +86,12 @@ import {
|
||||
loginLocalAccount,
|
||||
pollTaskUntilSettled,
|
||||
registerLocalAccount,
|
||||
rechargeUserWalletBalance,
|
||||
replacePlatformModels,
|
||||
restoreModelRuntimeStatus,
|
||||
setUserWalletBalance,
|
||||
type HealthResponse,
|
||||
updateAccessRule,
|
||||
updateApiKeyScopes,
|
||||
updateFileStorageChannel,
|
||||
updateFileStorageSettings,
|
||||
updateGatewayUser,
|
||||
@@ -142,6 +146,8 @@ import type {
|
||||
|
||||
type DataKey =
|
||||
| 'health'
|
||||
| 'currentUser'
|
||||
| 'currentUserGroups'
|
||||
| 'publicCatalog'
|
||||
| 'playgroundApiKeys'
|
||||
| 'playgroundModels'
|
||||
@@ -184,6 +190,8 @@ export function App() {
|
||||
const [loginForm, setLoginForm] = useState<LoginForm>({ account: '', password: '' });
|
||||
const [registerForm, setRegisterForm] = useState<RegisterForm>({ username: '', email: '', password: '', displayName: '', invitationCode: '' });
|
||||
const [health, setHealth] = useState<HealthResponse | null>(null);
|
||||
const [currentUser, setCurrentUser] = useState<ConsoleData['currentUser']>(null);
|
||||
const [currentUserGroups, setCurrentUserGroups] = useState<UserGroup[]>([]);
|
||||
const [platforms, setPlatforms] = useState<IntegrationPlatform[]>([]);
|
||||
const [models, setModels] = useState<PlatformModel[]>([]);
|
||||
const [modelCatalog, setModelCatalog] = useState<ModelCatalogResponse>({
|
||||
@@ -313,6 +321,8 @@ export function App() {
|
||||
auditLogs,
|
||||
apiKeys,
|
||||
baseModels,
|
||||
currentUser,
|
||||
currentUserGroups,
|
||||
fileStorageChannels,
|
||||
fileStorageSettings,
|
||||
modelCatalog,
|
||||
@@ -334,7 +344,7 @@ export function App() {
|
||||
users,
|
||||
walletAccounts,
|
||||
walletTransactions,
|
||||
}), [accessRules, apiKeys, auditLogs, baseModels, fileStorageChannels, fileStorageSettings, modelCatalog, modelRateLimits, modelRateLimitsUpdatedAt, models, networkProxyConfig, platforms, pricingRuleSets, pricingRules, providers, rateLimitWindows, runnerPolicy, runtimePolicySets, taskResult, tasks, tenants, userGroups, users, walletAccounts, walletTransactions]);
|
||||
}), [accessRules, apiKeys, auditLogs, baseModels, currentUser, currentUserGroups, fileStorageChannels, fileStorageSettings, modelCatalog, modelRateLimits, modelRateLimitsUpdatedAt, models, networkProxyConfig, platforms, pricingRuleSets, pricingRules, providers, rateLimitWindows, runnerPolicy, runtimePolicySets, taskResult, tasks, tenants, userGroups, users, walletAccounts, walletTransactions]);
|
||||
|
||||
async function refresh(nextToken = token) {
|
||||
await ensureRouteData(nextToken, true);
|
||||
@@ -387,6 +397,12 @@ export function App() {
|
||||
setHealth(await getHealth());
|
||||
return;
|
||||
}
|
||||
case 'currentUser':
|
||||
setCurrentUser(await getCurrentUser(nextToken));
|
||||
return;
|
||||
case 'currentUserGroups':
|
||||
setCurrentUserGroups((await listCurrentUserGroups(nextToken)).items);
|
||||
return;
|
||||
case 'publicCatalog': {
|
||||
const [providersResult, baseModelsResult] = await Promise.all([
|
||||
listPublicCatalogProviders(),
|
||||
@@ -541,7 +557,7 @@ export function App() {
|
||||
try {
|
||||
const response = await createApiKey(token, {
|
||||
name: apiKeyForm.name,
|
||||
scopes: ['chat', 'embedding', 'rerank', 'image', 'video'],
|
||||
scopes: ['chat', 'embedding', 'rerank', 'image', 'video', 'music', 'audio'],
|
||||
expiresAt: apiKeyForm.expiresAt ? new Date(apiKeyForm.expiresAt).toISOString() : undefined,
|
||||
});
|
||||
setApiKeySecret(response.secret);
|
||||
@@ -743,11 +759,11 @@ export function App() {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveUserWalletBalance(userId: string, input: WalletBalanceAdjustmentRequest) {
|
||||
async function rechargeUserWallet(userId: string, input: WalletRechargeRequest) {
|
||||
setCoreState('loading');
|
||||
setCoreMessage('');
|
||||
try {
|
||||
const response = await setUserWalletBalance(token, userId, input);
|
||||
const response = await rechargeUserWalletBalance(token, userId, input);
|
||||
setUsers((current) => current.map((user) => user.id === userId
|
||||
? {
|
||||
...user,
|
||||
@@ -760,10 +776,10 @@ export function App() {
|
||||
setAuditLogs((current) => [response.auditLog, ...current.filter((item) => item.id !== response.auditLog.id)]);
|
||||
invalidateDataKeys('auditLogs');
|
||||
setCoreState('ready');
|
||||
setCoreMessage('用户余额已更新,审计日志已记录。');
|
||||
setCoreMessage('用户余额已充值,审计日志已记录。');
|
||||
} catch (err) {
|
||||
setCoreState('error');
|
||||
setCoreMessage(err instanceof Error ? err.message : '更新用户余额失败');
|
||||
setCoreMessage(err instanceof Error ? err.message : '充值用户余额失败');
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -840,6 +856,22 @@ export function App() {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveAPIKeyScopes(apiKeyId: string, input: GatewayApiKeyScopeUpdateRequest) {
|
||||
setCoreState('loading');
|
||||
setCoreMessage('');
|
||||
try {
|
||||
const item = await updateApiKeyScopes(token, apiKeyId, input);
|
||||
setApiKeys((current) => current.map((apiKey) => (apiKey.id === item.id ? { ...apiKey, ...item } : apiKey)));
|
||||
invalidateDataKeys('playgroundApiKeys', 'playgroundModels', 'modelCatalog');
|
||||
setCoreState('ready');
|
||||
setCoreMessage('API Key 能力范围已更新。');
|
||||
} catch (err) {
|
||||
setCoreState('error');
|
||||
setCoreMessage(err instanceof Error ? err.message : '更新 API Key 能力范围失败');
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveAccessRule(input: GatewayAccessRuleUpsertRequest, ruleId?: string) {
|
||||
setCoreState('loading');
|
||||
setCoreMessage('');
|
||||
@@ -988,6 +1020,8 @@ export function App() {
|
||||
loadedDataKeysRef.current = new Set(health ? ['health'] : []);
|
||||
loadingDataKeysRef.current.clear();
|
||||
setState('idle');
|
||||
setCurrentUser(null);
|
||||
setCurrentUserGroups([]);
|
||||
setPlatforms([]);
|
||||
setModels([]);
|
||||
setModelCatalog({ items: [], filters: { capabilities: [], providers: [] }, summary: { modelCount: 0, sourceCount: 0 } });
|
||||
@@ -1143,6 +1177,7 @@ export function App() {
|
||||
onDeleteApiKey={removeAPIKey}
|
||||
onApiKeyFormChange={setApiKeyForm}
|
||||
onSectionChange={navigateWorkspaceSection}
|
||||
onSaveApiKeyScopes={saveAPIKeyScopes}
|
||||
onSubmitApiKey={submitAPIKey}
|
||||
onTaskQueryChange={navigateWorkspaceTaskQuery}
|
||||
onTransactionQueryChange={setWorkspaceTransactionQuery}
|
||||
@@ -1200,7 +1235,7 @@ export function App() {
|
||||
onSaveFileStorageSettings={saveFileStorageSettings}
|
||||
onSaveTenant={saveTenant}
|
||||
onSaveUser={saveUser}
|
||||
onSetUserWalletBalance={saveUserWalletBalance}
|
||||
onRechargeUserWalletBalance={rechargeUserWallet}
|
||||
onSaveUserGroup={saveUserGroup}
|
||||
onClearOperationMessage={() => setCoreMessage('')}
|
||||
onSectionChange={navigateAdminSection}
|
||||
@@ -1382,7 +1417,7 @@ function dataKeysForRoute(
|
||||
if (!isAuthenticated) return [];
|
||||
|
||||
if (activePage === 'workspace') {
|
||||
if (workspaceSection === 'overview') return ['users', 'userGroups', 'apiKeys'];
|
||||
if (workspaceSection === 'overview') return ['currentUser', 'currentUserGroups', 'apiKeys'];
|
||||
if (workspaceSection === 'billing') return ['wallet'];
|
||||
if (workspaceSection === 'apiKeys') return ['apiKeys', 'accessRules', 'playgroundModels'];
|
||||
if (workspaceSection === 'tasks') return ['tasks'];
|
||||
|
||||
Reference in New Issue
Block a user