mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
feat: template modal
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
import { $t } from '@common/locales'
|
||||
import { DatePicker, Form, Input, Modal, Switch, theme, Typography } from 'antd'
|
||||
import dayjs from 'dayjs'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
interface ApiKeyModalProps {
|
||||
visible: boolean
|
||||
onCancel: () => void
|
||||
onSave: (values: any) => void
|
||||
vendorName: string
|
||||
mode: 'add' | 'edit'
|
||||
initialValues?: {
|
||||
keyName?: string
|
||||
apiKey?: any
|
||||
expirationDate?: string
|
||||
enabled?: boolean
|
||||
}
|
||||
defaultKeyNumber?: number
|
||||
}
|
||||
|
||||
const { TextArea } = Input
|
||||
const { Text } = Typography
|
||||
|
||||
const ApiKeyModal: React.FC<ApiKeyModalProps> = ({
|
||||
visible,
|
||||
onCancel,
|
||||
onSave,
|
||||
vendorName,
|
||||
mode,
|
||||
initialValues,
|
||||
defaultKeyNumber = 1
|
||||
}) => {
|
||||
const [form] = Form.useForm()
|
||||
const { token } = theme.useToken()
|
||||
const [neverExpire, setNeverExpire] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
if (mode === 'add') {
|
||||
form.setFieldsValue({
|
||||
keyName: `KEY${defaultKeyNumber}`,
|
||||
neverExpire: true,
|
||||
expirationDate: dayjs().add(7, 'days'),
|
||||
apiKey: {
|
||||
openai_api_base: 'API Base',
|
||||
openai_api_key: 'API Key'
|
||||
}
|
||||
})
|
||||
} else if (initialValues) {
|
||||
form.setFieldsValue({
|
||||
keyName: initialValues.keyName,
|
||||
apiKey: initialValues.apiKey,
|
||||
expirationDate: initialValues.expirationDate ? dayjs(initialValues.expirationDate) : undefined,
|
||||
enabled: initialValues.enabled,
|
||||
neverExpire: !initialValues.expirationDate
|
||||
})
|
||||
setNeverExpire(!initialValues.expirationDate)
|
||||
}
|
||||
}
|
||||
}, [visible, mode, initialValues, defaultKeyNumber, form])
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
const values = await form.validateFields()
|
||||
onSave({
|
||||
...values,
|
||||
expirationDate: neverExpire ? null : values.expirationDate.format('YYYY-MM-DD HH:mm:ss')
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Validation failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleNeverExpireChange = (checked: boolean) => {
|
||||
setNeverExpire(checked)
|
||||
if (!checked) {
|
||||
form.setFieldsValue({
|
||||
expirationDate: dayjs().add(7, 'days')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={mode === 'add' ? $t('Add {{vendorName}} APIKEY', { vendorName }) : $t('Edit API Key')}
|
||||
open={visible}
|
||||
onCancel={onCancel}
|
||||
onOk={handleOk}
|
||||
destroyOnClose
|
||||
width={600}
|
||||
>
|
||||
<Form form={form} layout="vertical">
|
||||
<Form.Item
|
||||
name="keyName"
|
||||
label={$t('* KEY Name')}
|
||||
rules={[{ required: true, message: $t('Please input the KEY name') }]}
|
||||
>
|
||||
<Input disabled={mode === 'edit'} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="apiKey"
|
||||
label={
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
|
||||
<span>{$t('* API KEY')}</span>
|
||||
{mode === 'add' && (
|
||||
<a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer">
|
||||
{$t('Get API KEY from OpenAI')}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
rules={[{ required: true, message: $t('Please input the API key') }]}
|
||||
>
|
||||
{mode === 'add' ? (
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder={JSON.stringify(
|
||||
{
|
||||
openai_api_base: 'API Base',
|
||||
openai_api_key: 'API Key'
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<Input.Password />
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="neverExpire" valuePropName="checked">
|
||||
<Switch
|
||||
checkedChildren={$t('Never Expire')}
|
||||
unCheckedChildren={$t('Set Expiration')}
|
||||
onChange={handleNeverExpireChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{!neverExpire && (
|
||||
<Form.Item
|
||||
name="expirationDate"
|
||||
label={$t('Expiration Date')}
|
||||
rules={[{ required: true, message: $t('Please select expiration date') }]}
|
||||
>
|
||||
<DatePicker style={{ width: '100%' }} showTime />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
{mode === 'edit' && (
|
||||
<Form.Item name="enabled" label={$t('Enabled')} valuePropName="checked">
|
||||
<Switch checkedChildren={$t('Yes')} unCheckedChildren={$t('No')} />
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ApiKeyModal
|
||||
@@ -1,67 +0,0 @@
|
||||
import { $t } from '@common/locales'
|
||||
import { DatePicker, Form, Input, Modal, Switch, theme } from 'antd'
|
||||
import dayjs from 'dayjs'
|
||||
import React from 'react'
|
||||
|
||||
interface EditKeyModalProps {
|
||||
visible: boolean
|
||||
onCancel: () => void
|
||||
onSave: (values: any) => void
|
||||
initialValues?: {
|
||||
key: string
|
||||
expirationDate: string
|
||||
enabled: boolean
|
||||
}
|
||||
}
|
||||
|
||||
const EditKeyModal: React.FC<EditKeyModalProps> = ({ visible, onCancel, onSave, initialValues }) => {
|
||||
const [form] = Form.useForm()
|
||||
const { token } = theme.useToken()
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
const values = await form.validateFields()
|
||||
onSave({
|
||||
...values,
|
||||
expirationDate: values.expirationDate.format('YYYY-MM-DD')
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Validation failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal title={$t('Edit API Key')} open={visible} onCancel={onCancel} onOk={handleOk} destroyOnClose>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{
|
||||
...initialValues,
|
||||
expirationDate: initialValues?.expirationDate ? dayjs(initialValues.expirationDate) : undefined
|
||||
}}
|
||||
>
|
||||
<Form.Item
|
||||
name="key"
|
||||
label={$t('API Key')}
|
||||
rules={[{ required: true, message: $t('Please input the API key') }]}
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="expirationDate"
|
||||
label={$t('Expiration Date')}
|
||||
rules={[{ required: true, message: $t('Please select expiration date') }]}
|
||||
>
|
||||
<DatePicker style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="enabled" label={$t('Enabled')} valuePropName="checked">
|
||||
<Switch checkedChildren={$t('Yes')} unCheckedChildren={$t('No')} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditKeyModal
|
||||
@@ -7,7 +7,7 @@ import { useFetch } from '@common/hooks/http'
|
||||
import { $t } from '@common/locales'
|
||||
import { Badge, Button, message, Select, Space, Tooltip } from 'antd'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import EditKeyModal from './components/EditKeyModal'
|
||||
import ApiKeyModal from './components/ApiKeyModal'
|
||||
import StatusFilter from './components/StatusFilter'
|
||||
|
||||
interface APIKey {
|
||||
@@ -23,7 +23,8 @@ const KeySettings: React.FC = () => {
|
||||
const actionRef = useRef<ActionType>()
|
||||
const [selectedProvider, setSelectedProvider] = useState<string>('openai')
|
||||
const [statusFilter, setStatusFilter] = useState<string[]>([])
|
||||
const [editModalVisible, setEditModalVisible] = useState(false)
|
||||
const [modalVisible, setModalVisible] = useState(false)
|
||||
const [modalMode, setModalMode] = useState<'add' | 'edit'>('add')
|
||||
const [editingKey, setEditingKey] = useState<APIKey | null>(null)
|
||||
const [apiKeys, setApiKeys] = useState<APIKey[]>([])
|
||||
const { fetchData } = useFetch()
|
||||
@@ -52,24 +53,46 @@ const KeySettings: React.FC = () => {
|
||||
|
||||
const handleEdit = (record: APIKey) => {
|
||||
setEditingKey(record)
|
||||
setEditModalVisible(true)
|
||||
setModalMode('edit')
|
||||
setModalVisible(true)
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
setModalMode('add')
|
||||
setModalVisible(true)
|
||||
}
|
||||
|
||||
const handleModalCancel = () => {
|
||||
setModalVisible(false)
|
||||
setEditingKey(null)
|
||||
}
|
||||
|
||||
const handleSave = (values: any) => {
|
||||
if (editingKey) {
|
||||
if (modalMode === 'edit' && editingKey) {
|
||||
const newKeys = apiKeys.map((key) =>
|
||||
key.id === editingKey.id
|
||||
? {
|
||||
...key,
|
||||
key: values.key,
|
||||
key: values.apiKey,
|
||||
expirationDate: values.expirationDate,
|
||||
status: values.enabled ? 'normal' : 'disabled'
|
||||
}
|
||||
: key
|
||||
)
|
||||
setApiKeys(newKeys)
|
||||
} else {
|
||||
// Handle add case
|
||||
const newKey = {
|
||||
id: String(Date.now()),
|
||||
key: values.apiKey,
|
||||
status: 'normal',
|
||||
expirationDate: values.expirationDate,
|
||||
priority: apiKeys.length + 1,
|
||||
isDefault: apiKeys.length === 0
|
||||
}
|
||||
setApiKeys([...apiKeys, newKey])
|
||||
}
|
||||
setEditModalVisible(false)
|
||||
setModalVisible(false)
|
||||
setEditingKey(null)
|
||||
}
|
||||
|
||||
@@ -145,7 +168,6 @@ const KeySettings: React.FC = () => {
|
||||
}
|
||||
]
|
||||
|
||||
// const filteredKeys = statusFilter.length > 0 ? apiKeys.filter((key) => statusFilter.includes(key.status)) : apiKeys
|
||||
const filteredKeys = apiKeys
|
||||
|
||||
const beforeSearchNode = [
|
||||
@@ -178,29 +200,27 @@ const KeySettings: React.FC = () => {
|
||||
onDragSortEnd={handleDragSortEnd}
|
||||
beforeSearchNode={beforeSearchNode}
|
||||
addNewBtnTitle={$t('添加 API Key')}
|
||||
onAddNewBtnClick={() => {
|
||||
setEditingKey(null)
|
||||
setEditModalVisible(true)
|
||||
}}
|
||||
onAddNewBtnClick={handleAdd}
|
||||
rowKey="id"
|
||||
/>
|
||||
|
||||
<EditKeyModal
|
||||
visible={editModalVisible}
|
||||
onCancel={() => {
|
||||
setEditModalVisible(false)
|
||||
setEditingKey(null)
|
||||
}}
|
||||
<ApiKeyModal
|
||||
visible={modalVisible}
|
||||
mode={modalMode}
|
||||
onCancel={handleModalCancel}
|
||||
onSave={handleSave}
|
||||
vendorName={selectedProvider}
|
||||
initialValues={
|
||||
editingKey
|
||||
? {
|
||||
key: editingKey.key,
|
||||
keyName: editingKey.key,
|
||||
apiKey: editingKey.key,
|
||||
expirationDate: editingKey.expirationDate,
|
||||
enabled: editingKey.status !== 'disabled'
|
||||
enabled: editingKey.status === 'normal'
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
defaultKeyNumber={apiKeys.length + 1}
|
||||
/>
|
||||
</InsidePage>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user