/* * @Author: ZhaoYing * @Date: 2026-02-03 16:29:29 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-03-26 15:31:36 */ import { type FC, useState, useRef, useEffect } from 'react'; import clsx from 'clsx'; import { useTranslation } from 'react-i18next'; import { Button, Space, App, Row, Col, Flex } from 'antd'; import copy from 'copy-to-clipboard' import type { Application } from '@/views/ApplicationManagement/types' import type { ApiKeyModalRef, ApiKeyConfigModalRef } from './types' import type { ApiKey } from '@/views/ApiKeyManagement/types' import ApiKeyModal from './components/ApiKeyModal'; import ApiKeyConfigModal from './components/ApiKeyConfigModal'; import { getApiKeyList, getApiKeyStats, deleteApiKey } from '@/api/apiKey'; import { maskApiKeys } from '@/utils/apiKeyReplacer' import RbCard from '@/components/RbCard/Card'; /** * API configuration page component * Manages API endpoints and API keys for the application * @param application - Current application data */ const Api: FC<{ application: Application | null }> = ({ application }) => { const { t } = useTranslation(); const activeMethods = ['POST']; const { message, modal } = App.useApp() const copyContent = window.location.origin + '/v1/app/chat' const apiKeyModalRef = useRef(null); const apiKeyConfigModalRef = useRef(null); const [apiKeyList, setApiKeyList] = useState([]) /** * Copy content to clipboard * @param content - Content to copy */ const handleCopy = (content: string) => { copy(content) message.success(t('common.copySuccess')) } useEffect(() => { getApiList() }, []) /** * Fetch API key list for the application */ const getApiList = () => { if (!application) { return } setApiKeyList([]) getApiKeyList({ type: application.type, is_active: true, resource_id: application.id, page: 1, pagesize: 10, }).then(res => { const response = res as { items: ApiKey[] } const list = response.items ?? [] getAllStats([...list]) }) } /** * Fetch statistics for all API keys * @param list - List of API keys */ const getAllStats = (list: ApiKey[]) => { const allList: ApiKey[] = [] list.forEach(async item => { await getApiKeyStats(item.id) .then(res => { const response = res as { requests_today: number; total_requests: number; quota_limit: number; quota_used: number; } allList.push({ ...item, ...response, }) setApiKeyList(prev => [...prev, { ...item, ...response, }]) }) }) } /** * Open modal to add new API key */ const handleAdd = () => { apiKeyModalRef.current?.handleOpen() } /** * Open modal to edit API key * @param vo - API key to edit */ const handleEdit = (vo: ApiKey) => { apiKeyConfigModalRef.current?.handleOpen(vo) } /** * Delete API key with confirmation * @param vo - API key to delete */ const handleDelete = (vo: ApiKey) => { modal.confirm({ title: t('common.confirmDeleteDesc', { name: vo.name }), content: t('application.apiKeyDeleteContent'), okText: t('common.delete'), cancelText: t('common.cancel'), okType: 'danger', onOk: () => { deleteApiKey(vo.id) .then(() => { getApiList(); message.success(t('common.deleteSuccess')) }) } }) } // Calculate total requests across all API keys const totalRequests = apiKeyList.reduce((total, item) => total + item.total_requests, 0); return (
( {t('application.endpointConfiguration')} ({t('application.endpointConfigurationSubTitle')}) )} headerType="borderless" headerClassName="rb:min-h-13.5!" > {['GET', 'POST', 'PUT', 'DELETE'].map((method) => (
{method}
))}
{copyContent}
( {t('application.apiKeys')} ({t('application.apiKeySubTitle')}) )} extra={ } headerType="borderless" headerClassName="rb:min-h-13.5!" > {/* Overview Data */}
{apiKeyList.length}
{t('application.apiKeyTotal')}
{totalRequests}
{t('application.apiKeyRequestTotal')}
{/* API Key List */} {apiKeyList.sort((a, b) => b.created_at - a.created_at).map(item => (
{item.name}
ID: {item.id}
handleEdit(item)} >
handleDelete(item)} >
{item.total_requests}
{t('application.apiKeyRequestTotal')}
{item.rate_limit}
{t('application.qpsLimit')}
{maskApiKeys(item.api_key)}
))}
); } export default Api;