mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-05-07 06:13:04 +08:00
feat: add WebDAV mapping configuration and UI in System Settings
This commit is contained in:
@@ -286,6 +286,7 @@ export const en = {
|
||||
'App Settings': 'App Settings',
|
||||
'Email Settings': 'Email Settings',
|
||||
'AI Settings': 'AI Settings',
|
||||
'Protocol Mappings': 'Protocol Mappings',
|
||||
'Vision Model': 'Vision Model',
|
||||
'Embedding Model': 'Embedding Model',
|
||||
'Embedding Dimension': 'Embedding Dimension',
|
||||
@@ -332,6 +333,14 @@ export const en = {
|
||||
'Favicon URL': 'Favicon URL',
|
||||
'App Domain': 'App Domain',
|
||||
'File Domain': 'File Domain',
|
||||
'WebDAV Mapping': 'WebDAV Mapping',
|
||||
'WebDAV Endpoint': 'WebDAV Endpoint',
|
||||
'Basic (system account password)': 'Basic (system account password)',
|
||||
'Root Path': 'Root Path',
|
||||
'Client Compatibility': 'Client Compatibility',
|
||||
'Supports Finder, Windows network drive, rclone, and other WebDAV clients.': 'Supports Finder, Windows network drive, rclone, and other WebDAV clients.',
|
||||
'Toggle the switch to expose the virtual file system via WebDAV.': 'Toggle the switch to expose the virtual file system via WebDAV.',
|
||||
'S3 Mapping': 'S3 Mapping',
|
||||
'SMTP Settings': 'SMTP Settings',
|
||||
'SMTP Host': 'SMTP Host',
|
||||
'Please input SMTP host': 'Please input SMTP host',
|
||||
|
||||
@@ -307,6 +307,7 @@ export const zh = {
|
||||
'App Settings': '应用设置',
|
||||
'Email Settings': '邮箱设置',
|
||||
'AI Settings': 'AI设置',
|
||||
'Protocol Mappings': '映射协议',
|
||||
'Choose Template': '选择模板',
|
||||
'Configure Provider': '配置提供商',
|
||||
'Back to Templates': '返回选择',
|
||||
@@ -357,6 +358,14 @@ export const zh = {
|
||||
'Favicon URL': 'Favicon 地址',
|
||||
'App Domain': '应用域名',
|
||||
'File Domain': '文件域名',
|
||||
'WebDAV Mapping': 'WebDAV 映射',
|
||||
'WebDAV Endpoint': 'WebDAV 访问地址',
|
||||
'Basic (system account password)': 'Basic(系统账号密码)',
|
||||
'Root Path': '根路径',
|
||||
'Client Compatibility': '客户端兼容性',
|
||||
'Supports Finder, Windows network drive, rclone, and other WebDAV clients.': '兼容 Finder、Windows 网络驱动器、rclone 等 WebDAV 客户端。',
|
||||
'Toggle the switch to expose the virtual file system via WebDAV.': '通过开关控制是否对外暴露虚拟文件系统的 WebDAV 协议。',
|
||||
'S3 Mapping': 'S3 映射',
|
||||
'SMTP Settings': 'SMTP 配置',
|
||||
'SMTP Host': 'SMTP 服务器',
|
||||
'Please input SMTP host': '请输入 SMTP 服务器',
|
||||
|
||||
@@ -2,7 +2,7 @@ import { message, Tabs, Space } from 'antd';
|
||||
import { useEffect, useState } from 'react';
|
||||
import PageCard from '../../components/PageCard';
|
||||
import { getAllConfig, setConfig } from '../../api/config';
|
||||
import { AppstoreOutlined, RobotOutlined, DatabaseOutlined, SkinOutlined, MailOutlined } from '@ant-design/icons';
|
||||
import { AppstoreOutlined, RobotOutlined, DatabaseOutlined, SkinOutlined, MailOutlined, CloudSyncOutlined } from '@ant-design/icons';
|
||||
import { useTheme } from '../../contexts/ThemeContext';
|
||||
import '../../styles/settings-tabs.css';
|
||||
import { useI18n } from '../../i18n';
|
||||
@@ -11,10 +11,11 @@ import AppSettingsTab from './components/AppSettingsTab';
|
||||
import AiSettingsTab from './components/AiSettingsTab';
|
||||
import VectorDbSettingsTab from './components/VectorDbSettingsTab';
|
||||
import EmailSettingsTab from './components/EmailSettingsTab';
|
||||
import ProtocolMappingsTab from './components/ProtocolMappingsTab';
|
||||
|
||||
type TabKey = 'appearance' | 'app' | 'email' | 'ai' | 'vector-db';
|
||||
type TabKey = 'appearance' | 'app' | 'email' | 'ai' | 'vector-db' | 'mappings';
|
||||
|
||||
const TAB_KEYS: TabKey[] = ['appearance', 'app', 'email', 'ai', 'vector-db'];
|
||||
const TAB_KEYS: TabKey[] = ['appearance', 'app', 'email', 'ai', 'vector-db', 'mappings'];
|
||||
const DEFAULT_TAB: TabKey = 'appearance';
|
||||
|
||||
const isValidTab = (key?: string): key is TabKey => !!key && (TAB_KEYS as string[]).includes(key);
|
||||
@@ -191,6 +192,22 @@ export default function SystemSettingsPage({ tabKey, onTabNavigate }: SystemSett
|
||||
<VectorDbSettingsTab isActive={activeTab === 'vector-db'} />
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'mappings',
|
||||
label: (
|
||||
<span>
|
||||
<CloudSyncOutlined style={{ marginRight: 8 }} />
|
||||
{t('Protocol Mappings')}
|
||||
</span>
|
||||
),
|
||||
children: (
|
||||
<ProtocolMappingsTab
|
||||
config={config}
|
||||
loading={loading}
|
||||
onSave={handleSave}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Space>
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Card, Descriptions, Space, Switch, Typography } from 'antd';
|
||||
import { useI18n } from '../../../i18n';
|
||||
|
||||
interface ProtocolMappingsTabProps {
|
||||
config: Record<string, string>;
|
||||
loading: boolean;
|
||||
onSave: (values: Record<string, unknown>) => Promise<void>;
|
||||
}
|
||||
|
||||
const WEBDAV_KEY = 'WEBDAV_MAPPING_ENABLED';
|
||||
|
||||
const truthy = new Set(['1', 'true', 'yes', 'on']);
|
||||
|
||||
export default function ProtocolMappingsTab({ config, loading, onSave }: ProtocolMappingsTabProps) {
|
||||
const { t } = useI18n();
|
||||
const [webdavEnabled, setWebdavEnabled] = useState(() => truthy.has((config[WEBDAV_KEY] ?? '1').toLowerCase()));
|
||||
const [webdavSaving, setWebdavSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setWebdavEnabled(truthy.has((config[WEBDAV_KEY] ?? '1').toLowerCase()));
|
||||
}, [config]);
|
||||
|
||||
const webdavEndpoint = useMemo(() => {
|
||||
const configured = (config.APP_DOMAIN ?? '').trim();
|
||||
if (configured) {
|
||||
const hasProtocol = configured.startsWith('http://') || configured.startsWith('https://');
|
||||
const base = hasProtocol ? configured : `https://${configured}`;
|
||||
return base.replace(/\/$/, '') + '/webdav';
|
||||
}
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.location.origin.replace(/\/$/, '') + '/webdav';
|
||||
}
|
||||
return '/webdav';
|
||||
}, [config.APP_DOMAIN]);
|
||||
|
||||
const handleToggleWebdav = async (checked: boolean) => {
|
||||
setWebdavSaving(true);
|
||||
try {
|
||||
await onSave({ [WEBDAV_KEY]: checked ? '1' : '0' });
|
||||
setWebdavEnabled(checked);
|
||||
} finally {
|
||||
setWebdavSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Space direction="vertical" size={16} style={{ width: '100%' }}>
|
||||
<Card
|
||||
title={t('WebDAV Mapping')}
|
||||
extra={(
|
||||
<Space size={12} align="center">
|
||||
<Switch
|
||||
checked={webdavEnabled}
|
||||
loading={webdavSaving}
|
||||
disabled={loading}
|
||||
onChange={handleToggleWebdav}
|
||||
/>
|
||||
</Space>
|
||||
)}
|
||||
>
|
||||
<Descriptions
|
||||
column={1}
|
||||
size="small"
|
||||
items={[
|
||||
{
|
||||
key: 'endpoint',
|
||||
label: t('WebDAV Endpoint'),
|
||||
children: (
|
||||
<Typography.Text copyable={{ text: webdavEndpoint }}>
|
||||
<code>{webdavEndpoint}</code>
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'auth',
|
||||
label: t('Authentication'),
|
||||
children: t('Basic (system account password)'),
|
||||
},
|
||||
{
|
||||
key: 'root',
|
||||
label: t('Root Path'),
|
||||
children: '/webdav',
|
||||
},
|
||||
{
|
||||
key: 'compat',
|
||||
label: t('Client Compatibility'),
|
||||
children: t('Supports Finder, Windows network drive, rclone, and other WebDAV clients.'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Typography.Text type="secondary">
|
||||
{t('Toggle the switch to expose the virtual file system via WebDAV.')}
|
||||
</Typography.Text>
|
||||
</Card>
|
||||
|
||||
<Card title={t('S3 Mapping')}>
|
||||
<Typography.Text type="secondary">{t('Coming soon')}</Typography.Text>
|
||||
</Card>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user