mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-13 00:10:27 +00:00
* refactor: 将默认密码相关逻辑重构为后端处理 * refactor: 日志路由进行脱敏,生成随机密码使用node:crypto.randomBytes * feat: 更新密码功能增强,添加新密码强度验证和旧密码检查 * feat: 给文件管理添加WebUI配置文件的脱敏处理和验证逻辑 * refactor: 优化网络显示卡片按钮样式和行为,调整按钮属性以提升用户体验 * feat: 增强路径处理逻辑,添加安全验证以防止路径遍历攻击 * feat: 增强文件路径处理逻辑,添加安全验证以防止路径遍历攻击,并优化查询参数提取 * feat: CodeQL不认可 受不了
136 lines
3.4 KiB
TypeScript
136 lines
3.4 KiB
TypeScript
import { Button, ButtonGroup } from '@heroui/button'
|
|
import { Switch } from '@heroui/switch'
|
|
import { useState } from 'react'
|
|
import { CgDebug } from 'react-icons/cg'
|
|
import { FiEdit3 } from 'react-icons/fi'
|
|
import { MdDeleteForever } from 'react-icons/md'
|
|
|
|
import DisplayCardContainer from './container'
|
|
|
|
type NetworkType = OneBotConfig['network']
|
|
|
|
export type NetworkDisplayCardFields<T extends keyof NetworkType> = Array<{
|
|
label: string
|
|
value: NetworkType[T][0][keyof NetworkType[T][0]]
|
|
render?: (
|
|
value: NetworkType[T][0][keyof NetworkType[T][0]]
|
|
) => React.ReactNode
|
|
}>
|
|
|
|
export interface NetworkDisplayCardProps<T extends keyof NetworkType> {
|
|
data: NetworkType[T][0]
|
|
showType?: boolean
|
|
typeLabel: string
|
|
fields: NetworkDisplayCardFields<T>
|
|
onEdit: () => void
|
|
onEnable: () => Promise<void>
|
|
onDelete: () => Promise<void>
|
|
onEnableDebug: () => Promise<void>
|
|
}
|
|
|
|
const NetworkDisplayCard = <T extends keyof NetworkType>({
|
|
data,
|
|
showType,
|
|
typeLabel,
|
|
fields,
|
|
onEdit,
|
|
onEnable,
|
|
onDelete,
|
|
onEnableDebug
|
|
}: NetworkDisplayCardProps<T>) => {
|
|
const { name, enable, debug } = data
|
|
const [editing, setEditing] = useState(false)
|
|
|
|
const handleEnable = () => {
|
|
setEditing(true)
|
|
onEnable().finally(() => setEditing(false))
|
|
}
|
|
|
|
const handleDelete = () => {
|
|
setEditing(true)
|
|
onDelete().finally(() => setEditing(false))
|
|
}
|
|
|
|
const handleEnableDebug = () => {
|
|
setEditing(true)
|
|
onEnableDebug().finally(() => setEditing(false))
|
|
}
|
|
|
|
return (
|
|
<DisplayCardContainer
|
|
action={
|
|
<ButtonGroup
|
|
fullWidth
|
|
isDisabled={editing}
|
|
radius="sm"
|
|
size="sm"
|
|
variant="flat"
|
|
>
|
|
<Button
|
|
color="warning"
|
|
startContent={<FiEdit3 size={16} />}
|
|
onPress={onEdit}
|
|
>
|
|
编辑
|
|
</Button>
|
|
|
|
<Button
|
|
color={debug ? 'secondary' : 'success'}
|
|
variant="flat"
|
|
startContent={
|
|
<CgDebug
|
|
style={{
|
|
width: '16px',
|
|
height: '16px',
|
|
minWidth: '16px',
|
|
minHeight: '16px'
|
|
}}
|
|
/>
|
|
}
|
|
onPress={handleEnableDebug}
|
|
>
|
|
{debug ? '关闭调试' : '开启调试'}
|
|
</Button>
|
|
<Button
|
|
className="bg-danger/20 text-danger hover:bg-danger/30 transition-colors"
|
|
variant="flat"
|
|
startContent={<MdDeleteForever size={16} />}
|
|
onPress={handleDelete}
|
|
>
|
|
删除
|
|
</Button>
|
|
</ButtonGroup>
|
|
}
|
|
enableSwitch={
|
|
<Switch
|
|
isDisabled={editing}
|
|
isSelected={enable}
|
|
onChange={handleEnable}
|
|
/>
|
|
}
|
|
tag={showType && typeLabel}
|
|
title={name}
|
|
>
|
|
<div className="grid grid-cols-2 gap-1">
|
|
{fields.map((field, index) => (
|
|
<div
|
|
key={index}
|
|
className={`flex items-center gap-2 ${
|
|
field.label === 'URL' ? 'col-span-2' : ''
|
|
}`}
|
|
>
|
|
<span className="text-default-400">{field.label}</span>
|
|
{field.render ? (
|
|
field.render(field.value)
|
|
) : (
|
|
<span>{field.value}</span>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</DisplayCardContainer>
|
|
)
|
|
}
|
|
|
|
export default NetworkDisplayCard
|