From a368af0598929c1c8f14ee9c0854ffeb36b830b2 Mon Sep 17 00:00:00 2001 From: scarqin Date: Thu, 26 Dec 2024 14:20:06 +0800 Subject: [PATCH] feat: add modal --- .../src/components/AIProviderSelect/index.tsx | 2 +- .../keySettings/components/ApiKeyContent.tsx | 92 +++++++++++ .../keySettings/components/ApiKeyModal.tsx | 143 ------------------ .../core/src/pages/keySettings/index.tsx | 120 ++++++++------- .../core/src/pages/keySettings/types.ts | 16 +- 5 files changed, 175 insertions(+), 198 deletions(-) create mode 100644 frontend/packages/core/src/pages/keySettings/components/ApiKeyContent.tsx delete mode 100644 frontend/packages/core/src/pages/keySettings/components/ApiKeyModal.tsx diff --git a/frontend/packages/core/src/components/AIProviderSelect/index.tsx b/frontend/packages/core/src/components/AIProviderSelect/index.tsx index 3433e92c..77d4bf76 100644 --- a/frontend/packages/core/src/components/AIProviderSelect/index.tsx +++ b/frontend/packages/core/src/components/AIProviderSelect/index.tsx @@ -11,7 +11,7 @@ export interface AIProvider { configured: boolean getApikeyUrl: string status: string - config: string + default_config: string } interface AIProviderResponse { diff --git a/frontend/packages/core/src/pages/keySettings/components/ApiKeyContent.tsx b/frontend/packages/core/src/pages/keySettings/components/ApiKeyContent.tsx new file mode 100644 index 00000000..d04e83e2 --- /dev/null +++ b/frontend/packages/core/src/pages/keySettings/components/ApiKeyContent.tsx @@ -0,0 +1,92 @@ +import { Codebox } from '@common/components/postcat/api/Codebox' +import { $t } from '@common/locales' +import { AIProvider } from '@core/components/AIProviderSelect' +import { DatePicker, Form, Input, Switch } from 'antd' +import dayjs from 'dayjs' +import React, { useEffect, useState } from 'react' +import { EditAPIKey } from '../types' + +interface ApiKeyContentProps { + provider?: AIProvider + entity: EditAPIKey +} + +const ApiKeyContent: React.FC = ({ provider, entity }) => { + const [form] = Form.useForm() + const [neverExpire, setNeverExpire] = useState(true) + + useEffect(() => { + try { + form.setFieldsValue({ + name: entity.name, + expire_time: entity.expire_time === '0' ? 0 : dayjs(entity.expire_time), + config: entity.config + }) + } catch (e) { + form.setFieldsValue({ + name: entity.name, + expire_time: undefined, + config: '' + }) + } + // setNeverExpire(entity.expire_time === '0') + }, []) + + const handleOk = async () => { + try { + const values = await form.validateFields() + // onSave({ + // ...values, + // expire_time: neverExpire ? null : values.expire_time.format('YYYY-MM-DD HH:mm:ss') + // }) + } catch (error) { + console.error('Validation failed:', error) + } + } + + const handleNeverExpireChange = (checked: boolean) => { + console.log(checked) + setNeverExpire(checked) + if (!checked) { + form.setFieldsValue({ + expire_time: dayjs().add(7, 'days') + }) + } + } + + return ( +
+ + + + + + + +
+ + {neverExpire ? $t('永不过期') : $t('设置过期时间')} +
+
+ neverExpire:{neverExpire} + {!neverExpire && ( + + + + )} +
+ ) +} + +export default ApiKeyContent diff --git a/frontend/packages/core/src/pages/keySettings/components/ApiKeyModal.tsx b/frontend/packages/core/src/pages/keySettings/components/ApiKeyModal.tsx deleted file mode 100644 index b536e9fa..00000000 --- a/frontend/packages/core/src/pages/keySettings/components/ApiKeyModal.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import Icon from '@ant-design/icons' -import { Codebox } from '@common/components/postcat/api/Codebox' -import { $t } from '@common/locales' -import { AIProvider } from '@core/components/AIProviderSelect' -import { DatePicker, Form, Input, Modal, Switch } from 'antd' -import dayjs from 'dayjs' -import React, { useEffect, useState } from 'react' -import { APIKey } from '../types' - -interface ApiKeyModalProps { - visible: boolean - onCancel: () => void - onSave: (values: any) => void - provider?: AIProvider - mode: 'add' | 'edit' - entity: APIKey | null -} - -const ApiKeyModal: React.FC = ({ visible, onCancel, onSave, provider, mode, entity }) => { - const [form] = Form.useForm() - const [neverExpire, setNeverExpire] = useState(true) - - useEffect(() => { - try { - form.setFieldsValue({ - name: entity?.name, - expire_time: entity?.expire_time ? dayjs(entity.expire_time) : undefined, - config: entity?.config ? JSON.stringify(JSON.parse(entity?.config), null, 2) : JSON.parse(provider?.config) - }) - setNeverExpire(!entity?.expire_time) - } catch (e) { - console.error('Error setting form values:', e) - form.setFieldsValue({ - name: entity?.name, - expire_time: undefined, - config: '' - }) - } - }, []) - - const handleOk = async () => { - try { - const values = await form.validateFields() - onSave({ - ...values, - expire_time: neverExpire ? null : values.expire_time.format('YYYY-MM-DD HH:mm:ss') - }) - } catch (error) { - console.error('Validation failed:', error) - } - } - - const handleNeverExpireChange = (checked: boolean) => { - setNeverExpire(checked) - if (!checked) { - form.setFieldsValue({ - expire_time: dayjs().add(7, 'days') - }) - } - } - - const getProviderKeyUrl = (provider: string): string => { - const urls: Record = { - openai: 'https://platform.openai.com/api-keys', - anthropic: 'https://console.anthropic.com/account/keys', - google: 'https://console.cloud.google.com/apis/credentials', - azure: 'https://portal.azure.com/#blade/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/OpenAI', - stability: 'https://platform.stability.ai/account/keys' - } - return urls[provider.toLowerCase()] || '#' - } - - console.log(provider) - return ( - ( - - )} - > -
- - - - - - - - - -
- - {neverExpire ? $t('永不过期') : $t('设置过期时间')} -
-
- - {!neverExpire && ( - - - - )} - - {mode === 'edit' && ( - - - - )} -
-
- ) -} - -export default ApiKeyModal diff --git a/frontend/packages/core/src/pages/keySettings/index.tsx b/frontend/packages/core/src/pages/keySettings/index.tsx index 3de600e1..6fa9fc46 100644 --- a/frontend/packages/core/src/pages/keySettings/index.tsx +++ b/frontend/packages/core/src/pages/keySettings/index.tsx @@ -1,3 +1,4 @@ +import Icon from '@ant-design/icons' import { ActionType } from '@ant-design/pro-components' import InsidePage from '@common/components/aoplatform/InsidePage' import PageList, { PageProColumns } from '@common/components/aoplatform/PageList' @@ -6,71 +7,92 @@ import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from '@common/const/const' import { useFetch } from '@common/hooks/http' import { $t } from '@common/locales' import AIProviderSelect, { AIProvider } from '@core/components/AIProviderSelect' -import { Divider, message, Space, Typography } from 'antd' +import { App, Divider, Space, Typography } from 'antd' import React, { useEffect, useRef, useState } from 'react' -import ApiKeyModal from './components/ApiKeyModal' -import { APIKey } from './types' +import ApiKeyContent from './components/ApiKeyContent' +import { APIKey, EditAPIKey } from './types' const KeySettings: React.FC = () => { const pageListRef = useRef(null) + const { modal, message } = App.useApp() const [selectedProvider, setSelectedProvider] = useState() const [provider, setProvider] = useState() - const [modalVisible, setModalVisible] = useState(false) - const [modalMode, setModalMode] = useState<'add' | 'edit'>('add') - const [editingKey, setEditingKey] = useState(null) const [apiKeys, setApiKeys] = useState([]) const { fetchData } = useFetch() const [searchWord, setSearchWord] = useState('') - + const [total, setTotal] = useState(0) + const modalRef = useRef() useEffect(() => { pageListRef.current?.reload() }, [selectedProvider]) const handleEdit = (record: APIKey) => { - setEditingKey(record) - setModalMode('edit') - setModalVisible(true) + openModal(record) } const handleAdd = () => { - setModalMode('add') - setModalVisible(true) + openModal() } - const handleModalCancel = () => { - setModalVisible(false) - setEditingKey(null) - } - - const handleSave = (values: any) => { - if (modalMode === 'edit' && editingKey) { - const newKeys: APIKey[] = apiKeys.map((key) => - key.id === editingKey.id - ? { - ...key, - key: values.name, - expire_time: values.expire_time, - status: values.enabled ? 'normal' : 'disabled' - } - : key - ) - setApiKeys(newKeys) - } else { - // Handle add case - const newKey: APIKey = { - id: String(Date.now()), - name: values.name, - status: 'normal', - expire_time: values.expire_time, - priority: apiKeys.length + 1, - can_delete: true, - use_token: 0, - update_time: '' + const openModal = async (entity?: EditAPIKey) => { + if (!provider) return + const mode = entity ? 'edit' : 'add' + if (mode === 'edit') { + message.loading($t(RESPONSE_TIPS.loading)) + const { code, data, msg } = await fetchData>('ai/resource/key', { + method: 'GET', + eoParams: { provider: selectedProvider, id: entity!.id } + }) + message.destroy() + if (code !== STATUS_CODE.SUCCESS) { + message.error(msg || $t(RESPONSE_TIPS.error)) + return } - setApiKeys([...apiKeys, newKey]) + entity = data?.info + } else { + provider.default_config = '{"apikey":"******"}' + entity = { + name: `key${total}`, + config: provider.default_config, + expire_time: '0' + } as EditAPIKey } - setModalVisible(false) - setEditingKey(null) + const newEntity = entity as EditAPIKey + + modal.confirm({ + title: mode === 'add' ? $t(`添加 ${provider?.name} APIKey`) : $t('编辑 APIKey'), + content: , + onOk: () => { + return modalRef.current?.save().then((res) => { + // if (res === true) setAiConfigFlushed(true) + // getAiSettingList() + }) + }, + width: 600, + okText: $t('确认'), + footer: (_, { OkBtn, CancelBtn }) => { + return ( +
+ + {$t('从 (0) 获取 API KEY', [provider.name])} + + +
+ + {/* {checkAccess('system.devops.ai_provider.edit', accessData) ? : null} */} +
+
+ ) + }, + cancelText: $t('取消'), + closable: true, + icon: <> + }) } const handleDelete = async (id: string) => { @@ -166,6 +188,7 @@ const KeySettings: React.FC = () => { }) if (response.code === STATUS_CODE.SUCCESS) { + setTotal(response.data.total) return { data: response.data.keys, success: true, @@ -320,15 +343,6 @@ const KeySettings: React.FC = () => { addNewBtnTitle={$t('添加 APIKey')} onAddNewBtnClick={handleAdd} /> - ) diff --git a/frontend/packages/core/src/pages/keySettings/types.ts b/frontend/packages/core/src/pages/keySettings/types.ts index 92e4d1ff..55f43e18 100644 --- a/frontend/packages/core/src/pages/keySettings/types.ts +++ b/frontend/packages/core/src/pages/keySettings/types.ts @@ -9,4 +9,18 @@ export interface APIKey extends Record { can_delete: boolean priority: number } - \ No newline at end of file + +export interface APIKey extends EditAPIKey { + status: 'normal' | 'exceeded' | 'expired' | 'disabled' | 'error' + use_token: number + update_time: string + can_delete: boolean + priority: number +} + +export interface EditAPIKey { + id?: string + name: string + config: string + expire_time: string +}