mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-10 15:26:38 +08:00
refactor: reuse notify config controls
This commit is contained in:
@@ -0,0 +1,97 @@
|
|||||||
|
import { Field } from './NotifyChannelFormField'
|
||||||
|
|
||||||
|
type ConfigControlProps = {
|
||||||
|
config: Record<string, string>
|
||||||
|
updateConfig: (key: string, value: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigInputProps = ConfigControlProps & {
|
||||||
|
label: string
|
||||||
|
name: string
|
||||||
|
placeholder?: string
|
||||||
|
required?: boolean
|
||||||
|
type?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConfigInput({
|
||||||
|
config,
|
||||||
|
updateConfig,
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
placeholder,
|
||||||
|
required,
|
||||||
|
type,
|
||||||
|
}: ConfigInputProps) {
|
||||||
|
return (
|
||||||
|
<Field label={label}>
|
||||||
|
<input
|
||||||
|
required={required}
|
||||||
|
type={type}
|
||||||
|
className="input-base"
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={config[name] ?? ''}
|
||||||
|
onChange={(event) => updateConfig(name, event.target.value)}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigSelectProps = ConfigControlProps & {
|
||||||
|
label: string
|
||||||
|
name: string
|
||||||
|
options: Array<{ value: string; label: string }>
|
||||||
|
defaultValue?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConfigSelect({
|
||||||
|
config,
|
||||||
|
updateConfig,
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
options,
|
||||||
|
defaultValue = '',
|
||||||
|
}: ConfigSelectProps) {
|
||||||
|
return (
|
||||||
|
<Field label={label}>
|
||||||
|
<select
|
||||||
|
className="input-base"
|
||||||
|
value={config[name] ?? defaultValue}
|
||||||
|
onChange={(event) => updateConfig(name, event.target.value)}
|
||||||
|
>
|
||||||
|
{options.map((option) => (
|
||||||
|
<option key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigTextareaProps = ConfigControlProps & {
|
||||||
|
label: string
|
||||||
|
name: string
|
||||||
|
placeholder?: string
|
||||||
|
rows: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConfigTextarea({
|
||||||
|
config,
|
||||||
|
updateConfig,
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
placeholder,
|
||||||
|
rows,
|
||||||
|
}: ConfigTextareaProps) {
|
||||||
|
return (
|
||||||
|
<Field label={label}>
|
||||||
|
<textarea
|
||||||
|
rows={rows}
|
||||||
|
className="input-base font-mono text-xs"
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={config[name] ?? ''}
|
||||||
|
onChange={(event) => updateConfig(name, event.target.value)}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,63 +1,67 @@
|
|||||||
import { Field } from './NotifyChannelFormField'
|
import {
|
||||||
|
ConfigInput,
|
||||||
|
ConfigSelect,
|
||||||
|
ConfigTextarea,
|
||||||
|
} from './NotifyChannelConfigControls'
|
||||||
|
|
||||||
type ProviderFieldsProps = {
|
type ProviderFieldsProps = {
|
||||||
config: Record<string, string>
|
config: Record<string, string>
|
||||||
updateConfig: (key: string, value: string) => void
|
updateConfig: (key: string, value: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const METHOD_OPTIONS = [
|
||||||
|
{ value: 'POST', label: 'POST' },
|
||||||
|
{ value: 'GET', label: 'GET' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const TLS_OPTIONS = [
|
||||||
|
{ value: 'true', label: '启用' },
|
||||||
|
{ value: 'false', label: '关闭' },
|
||||||
|
]
|
||||||
|
|
||||||
export function TelegramFields({ config, updateConfig }: ProviderFieldsProps) {
|
export function TelegramFields({ config, updateConfig }: ProviderFieldsProps) {
|
||||||
|
const control = { config, updateConfig }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field label="Bot Token">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="Bot Token"
|
||||||
placeholder="123456:ABC-DEF…"
|
name="bot_token"
|
||||||
value={config.bot_token ?? ''}
|
placeholder="123456:ABC-DEF…"
|
||||||
onChange={(e) => updateConfig('bot_token', e.target.value)}
|
/>
|
||||||
/>
|
<ConfigInput
|
||||||
</Field>
|
{...control}
|
||||||
<Field label="管理员 Telegram ID">
|
required
|
||||||
<input
|
label="管理员 Telegram ID"
|
||||||
required
|
name="admin_user_ids"
|
||||||
className="input-base"
|
placeholder="多个用逗号分隔,如 123456789,987654321"
|
||||||
placeholder="多个用逗号分隔,如 123456789,987654321"
|
/>
|
||||||
value={config.admin_user_ids ?? ''}
|
<ConfigInput
|
||||||
onChange={(e) => updateConfig('admin_user_ids', e.target.value)}
|
{...control}
|
||||||
/>
|
label="绑定群组 ID"
|
||||||
</Field>
|
name="group_chat_id"
|
||||||
<Field label="绑定群组 ID">
|
placeholder="选填,如 -1001234567890;填写后群组成员可唤醒/绑定"
|
||||||
<input
|
/>
|
||||||
className="input-base"
|
<ConfigInput
|
||||||
placeholder="选填,如 -1001234567890;填写后群组成员可唤醒/绑定"
|
{...control}
|
||||||
value={config.group_chat_id ?? ''}
|
label="绑定频道 ID"
|
||||||
onChange={(e) => updateConfig('group_chat_id', e.target.value)}
|
name="channel_chat_id"
|
||||||
/>
|
placeholder="选填,如 -1009876543210;填写后频道成员可唤醒/绑定"
|
||||||
</Field>
|
/>
|
||||||
<Field label="绑定频道 ID">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
className="input-base"
|
label="Telegram API 地址 (可选)"
|
||||||
placeholder="选填,如 -1009876543210;填写后频道成员可唤醒/绑定"
|
name="api_base_url"
|
||||||
value={config.channel_chat_id ?? ''}
|
placeholder="默认 https://api.telegram.org;反代可填 https://tg.example.com"
|
||||||
onChange={(e) => updateConfig('channel_chat_id', e.target.value)}
|
/>
|
||||||
/>
|
<ConfigInput
|
||||||
</Field>
|
{...control}
|
||||||
<Field label="Telegram API 地址 (可选)">
|
label="Telegram 代理 (可选)"
|
||||||
<input
|
name="proxy_url"
|
||||||
className="input-base"
|
placeholder="如 http://172.17.0.1:7890 或 socks5://172.17.0.1:1080"
|
||||||
placeholder="默认 https://api.telegram.org;反代可填 https://tg.example.com"
|
/>
|
||||||
value={config.api_base_url ?? ''}
|
|
||||||
onChange={(e) => updateConfig('api_base_url', e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
<Field label="Telegram 代理 (可选)">
|
|
||||||
<input
|
|
||||||
className="input-base"
|
|
||||||
placeholder="如 http://172.17.0.1:7890 或 socks5://172.17.0.1:1080"
|
|
||||||
value={config.proxy_url ?? ''}
|
|
||||||
onChange={(e) => updateConfig('proxy_url', e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
<div className="rounded-2xl border border-primary-400/15 bg-primary-400/5 px-4 py-3 text-xs leading-6 text-ink-50">
|
<div className="rounded-2xl border border-primary-400/15 bg-primary-400/5 px-4 py-3 text-xs leading-6 text-ink-50">
|
||||||
群组 ID、频道 ID 均为选填,可填一个、两个都填,也可以不填。管理功能始终仅管理员 Telegram ID 或已绑定的本地管理员可用;普通用户需要在已配置的群组或频道中,才能使用 <code>/start 用户名 密码</code> 绑定账号、切换隐藏成人媒体库和目录。不配置群组/频道时,普通用户不会被放行。若测试通知超时,可填写反代 API 地址或代理地址。
|
群组 ID、频道 ID 均为选填,可填一个、两个都填,也可以不填。管理功能始终仅管理员 Telegram ID 或已绑定的本地管理员可用;普通用户需要在已配置的群组或频道中,才能使用 <code>/start 用户名 密码</code> 绑定账号、切换隐藏成人媒体库和目录。不配置群组/频道时,普通用户不会被放行。若测试通知超时,可填写反代 API 地址或代理地址。
|
||||||
</div>
|
</div>
|
||||||
@@ -66,156 +70,134 @@ export function TelegramFields({ config, updateConfig }: ProviderFieldsProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function WechatFields({ config, updateConfig }: ProviderFieldsProps) {
|
export function WechatFields({ config, updateConfig }: ProviderFieldsProps) {
|
||||||
|
const control = { config, updateConfig }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Field label="SendKey">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="SendKey"
|
||||||
placeholder="SCT…"
|
name="sendkey"
|
||||||
value={config.sendkey ?? ''}
|
placeholder="SCT…"
|
||||||
onChange={(e) => updateConfig('sendkey', e.target.value)}
|
/>
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BarkFields({ config, updateConfig }: ProviderFieldsProps) {
|
export function BarkFields({ config, updateConfig }: ProviderFieldsProps) {
|
||||||
|
const control = { config, updateConfig }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field label="设备 Key">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="设备 Key"
|
||||||
value={config.device_key ?? ''}
|
name="device_key"
|
||||||
onChange={(e) => updateConfig('device_key', e.target.value)}
|
/>
|
||||||
/>
|
<ConfigInput
|
||||||
</Field>
|
{...control}
|
||||||
<Field label="服务器地址 (可选)">
|
label="服务器地址 (可选)"
|
||||||
<input
|
name="server"
|
||||||
className="input-base"
|
placeholder="https://api.day.app"
|
||||||
placeholder="https://api.day.app"
|
/>
|
||||||
value={config.server ?? ''}
|
|
||||||
onChange={(e) => updateConfig('server', e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function WebhookFields({ config, updateConfig }: ProviderFieldsProps) {
|
export function WebhookFields({ config, updateConfig }: ProviderFieldsProps) {
|
||||||
|
const control = { config, updateConfig }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field label="URL">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="URL"
|
||||||
placeholder="https://example.com/notify"
|
name="url"
|
||||||
value={config.url ?? ''}
|
placeholder="https://example.com/notify"
|
||||||
onChange={(e) => updateConfig('url', e.target.value)}
|
/>
|
||||||
/>
|
<ConfigSelect
|
||||||
</Field>
|
{...control}
|
||||||
<Field label="Method">
|
label="Method"
|
||||||
<select
|
name="method"
|
||||||
className="input-base"
|
options={METHOD_OPTIONS}
|
||||||
value={config.method ?? 'POST'}
|
defaultValue="POST"
|
||||||
onChange={(e) => updateConfig('method', e.target.value)}
|
/>
|
||||||
>
|
<ConfigTextarea
|
||||||
<option value="POST">POST</option>
|
{...control}
|
||||||
<option value="GET">GET</option>
|
label="Headers (JSON)"
|
||||||
</select>
|
name="headers"
|
||||||
</Field>
|
rows={2}
|
||||||
<Field label="Headers (JSON)">
|
placeholder='{"Content-Type":"application/json"}'
|
||||||
<textarea
|
/>
|
||||||
rows={2}
|
<ConfigTextarea
|
||||||
className="input-base font-mono text-xs"
|
{...control}
|
||||||
placeholder='{"Content-Type":"application/json"}'
|
label="Body 模板 (支持 {{title}} {{message}})"
|
||||||
value={config.headers ?? ''}
|
name="body_template"
|
||||||
onChange={(e) => updateConfig('headers', e.target.value)}
|
rows={3}
|
||||||
/>
|
placeholder='{"title":"{{title}}","message":"{{message}}"}'
|
||||||
</Field>
|
/>
|
||||||
<Field label="Body 模板 (支持 {{title}} {{message}})">
|
|
||||||
<textarea
|
|
||||||
rows={3}
|
|
||||||
className="input-base font-mono text-xs"
|
|
||||||
placeholder='{"title":"{{title}}","message":"{{message}}"}'
|
|
||||||
value={config.body_template ?? ''}
|
|
||||||
onChange={(e) => updateConfig('body_template', e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EmailFields({ config, updateConfig }: ProviderFieldsProps) {
|
export function EmailFields({ config, updateConfig }: ProviderFieldsProps) {
|
||||||
|
const control = { config, updateConfig }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field label="SMTP 地址">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="SMTP 地址"
|
||||||
placeholder="smtp.gmail.com"
|
name="smtp_host"
|
||||||
value={config.smtp_host ?? ''}
|
placeholder="smtp.gmail.com"
|
||||||
onChange={(e) => updateConfig('smtp_host', e.target.value)}
|
/>
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<Field label="SMTP 端口">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="SMTP 端口"
|
||||||
placeholder="465"
|
name="smtp_port"
|
||||||
value={config.smtp_port ?? ''}
|
placeholder="465"
|
||||||
onChange={(e) => updateConfig('smtp_port', e.target.value)}
|
/>
|
||||||
/>
|
<ConfigSelect
|
||||||
</Field>
|
{...control}
|
||||||
<Field label="TLS">
|
label="TLS"
|
||||||
<select
|
name="tls"
|
||||||
className="input-base"
|
options={TLS_OPTIONS}
|
||||||
value={config.tls ?? 'true'}
|
defaultValue="true"
|
||||||
onChange={(e) => updateConfig('tls', e.target.value)}
|
/>
|
||||||
>
|
|
||||||
<option value="true">启用</option>
|
|
||||||
<option value="false">关闭</option>
|
|
||||||
</select>
|
|
||||||
</Field>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<Field label="用户名">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="用户名"
|
||||||
value={config.username ?? ''}
|
name="username"
|
||||||
onChange={(e) => updateConfig('username', e.target.value)}
|
/>
|
||||||
/>
|
<ConfigInput
|
||||||
</Field>
|
{...control}
|
||||||
<Field label="密码">
|
required
|
||||||
<input
|
label="密码"
|
||||||
type="password"
|
name="password"
|
||||||
required
|
type="password"
|
||||||
className="input-base"
|
/>
|
||||||
value={config.password ?? ''}
|
|
||||||
onChange={(e) => updateConfig('password', e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</div>
|
</div>
|
||||||
<Field label="发件人">
|
<ConfigInput
|
||||||
<input
|
{...control}
|
||||||
required
|
required
|
||||||
className="input-base"
|
label="发件人"
|
||||||
placeholder="noreply@example.com"
|
name="from"
|
||||||
value={config.from ?? ''}
|
placeholder="noreply@example.com"
|
||||||
onChange={(e) => updateConfig('from', e.target.value)}
|
/>
|
||||||
/>
|
<ConfigInput
|
||||||
</Field>
|
{...control}
|
||||||
<Field label="收件人 (多个用逗号分隔)">
|
required
|
||||||
<input
|
label="收件人 (多个用逗号分隔)"
|
||||||
required
|
name="to"
|
||||||
className="input-base"
|
placeholder="user@example.com"
|
||||||
placeholder="user@example.com"
|
/>
|
||||||
value={config.to ?? ''}
|
|
||||||
onChange={(e) => updateConfig('to', e.target.value)}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user