优化更新表单逻辑
This commit is contained in:
parent
098259177b
commit
1edb3474c5
@ -13,9 +13,6 @@ export default function CustomNode({
|
|||||||
<span className="node-label">{data.label}</span>
|
<span className="node-label">{data.label}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="node-info">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{[Position.Top, Position.Bottom, Position.Right, Position.Left].map((position) => (
|
{[Position.Top, Position.Bottom, Position.Right, Position.Left].map((position) => (
|
||||||
(["target", "source"] as const).map((type) => (
|
(["target", "source"] as const).map((type) => (
|
||||||
<Handle type={type} position={position} id={position} key={`${type}-${position}`} className="node-handle"/>
|
<Handle type={type} position={position} id={position} key={`${type}-${position}`} className="node-handle"/>
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { useState, ReactNode } from 'react';
|
import { useState, ReactNode } from 'react';
|
||||||
import { AppNode, AppEdge, EdgeData } from '../types/graph';
|
import { AppNode, AppEdge, EdgeData, EdgeDataUpdate } from '../types/graph';
|
||||||
import { useReactFlow } from '@xyflow/react';
|
import { useReactFlow } from '@xyflow/react';
|
||||||
|
import './FormEditor.css';
|
||||||
|
|
||||||
interface EdgeEditorProps {
|
interface EdgeEditorProps {
|
||||||
edge: EdgeData;
|
edge: EdgeData;
|
||||||
onUpdate: (data: EdgeData) => void;
|
onUpdate: (data: EdgeDataUpdate) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,18 +14,12 @@ export default function NodeEditor({
|
|||||||
onUpdate,
|
onUpdate,
|
||||||
onClose
|
onClose
|
||||||
}: EdgeEditorProps): ReactNode {
|
}: EdgeEditorProps): ReactNode {
|
||||||
const [formData, setFormData] = useState<EdgeData>(edge);
|
|
||||||
|
const [keepalive, setKeepalive] = useState(edge.persistentKeepalive);
|
||||||
const { getNode, getEdge } = useReactFlow<AppNode, AppEdge>();
|
const { getNode, getEdge } = useReactFlow<AppNode, AppEdge>();
|
||||||
|
|
||||||
const handleInputChange = (field: keyof EdgeData, value: string): void => {
|
|
||||||
setFormData(prev => ({
|
|
||||||
...prev,
|
|
||||||
[field]: value
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = (): void => {
|
const handleSave = (): void => {
|
||||||
onUpdate(formData);
|
onUpdate({persistentKeepalive : keepalive});
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,8 +47,13 @@ export default function NodeEditor({
|
|||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
step="1"
|
step="1"
|
||||||
value={formData.persistentKeepalive || ''}
|
value={keepalive || ''}
|
||||||
onChange={(e) => handleInputChange('persistentKeepalive', e.target.value)}
|
onChange={
|
||||||
|
(e) => {
|
||||||
|
const value = e.target.valueAsNumber;
|
||||||
|
setKeepalive(isNaN(value) ? undefined : value);
|
||||||
|
}
|
||||||
|
}
|
||||||
placeholder={`留空或0代表不保活`}
|
placeholder={`留空或0代表不保活`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useState, ReactNode } from 'react';
|
import { useState, ReactNode } from 'react';
|
||||||
import { NodeData, Settings } from '../types/graph';
|
import { NodeData, Settings, NodeDataUpdate } from '../types/graph';
|
||||||
import { generateWireGuardPrivateKey } from '../utils/wireguardConfig'
|
import { generateWireGuardPrivateKey } from '../utils/wireguardConfig'
|
||||||
import './NodeEditor.css';
|
import './FormEditor.css';
|
||||||
import Folder from './Folder'
|
import Folder from './Folder'
|
||||||
|
|
||||||
|
|
||||||
@ -10,15 +10,10 @@ interface Validation {
|
|||||||
errors: string[]
|
errors: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateNodeConfig(formData : NodeData) : Validation {
|
|
||||||
// todo
|
|
||||||
return {isValid : true, errors: []}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NodeEditorProps {
|
interface NodeEditorProps {
|
||||||
node: NodeData;
|
node: NodeData;
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
onUpdate: (data: NodeData) => void;
|
onUpdate: (data: NodeDataUpdate) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,36 +24,48 @@ export default function NodeEditor({
|
|||||||
onClose
|
onClose
|
||||||
}: NodeEditorProps): ReactNode {
|
}: NodeEditorProps): ReactNode {
|
||||||
|
|
||||||
const [formData, setFormData] = useState<NodeData>(node);
|
|
||||||
const [errors, setErrors] = useState<string[]>([]);
|
const [errors, setErrors] = useState<string[]>([]);
|
||||||
|
|
||||||
const handleInputChange = (field: keyof NodeData, value: string): void => {
|
const [label, setLabel] = useState<string>(node.label);
|
||||||
setFormData(prev => ({
|
const [privateKey, setPrivateKey] = useState<string>(node.privateKey);
|
||||||
...prev,
|
const [ipv4Address, setIpv4Address] = useState(node.ipv4Address);
|
||||||
[field]: value
|
const [ipv6Address, setIpv6Address] = useState(node.ipv6Address);
|
||||||
}));
|
const [disallowIPs, setDisallowIPs] = useState(node.disallowIPs);
|
||||||
};
|
const [listenPort, setListenPort] = useState(node.listenPort);
|
||||||
|
const [mtu, setmtu] = useState(node.mtu);
|
||||||
|
const [dnsServers, setdnsServers] = useState(node.dnsServers)
|
||||||
|
const [postUp, setPostUp] = useState(node.postUp)
|
||||||
|
const [postDown, setPostDown] = useState(node.postDown)
|
||||||
|
const [notes, setNotes] = useState(node.notes)
|
||||||
|
|
||||||
const handleSave = (): void => {
|
const handleSave = (): void => {
|
||||||
const validation = validateNodeConfig(formData);
|
// const validation = validateNodeConfig(formData);
|
||||||
if (!validation.isValid) {
|
// if (!validation.isValid) {
|
||||||
setErrors(validation.errors);
|
// setErrors(validation.errors);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
setErrors([]);
|
setErrors([]);
|
||||||
onUpdate(formData);
|
onUpdate({
|
||||||
|
label: label,
|
||||||
|
privateKey: privateKey,
|
||||||
|
ipv4Address: ipv4Address,
|
||||||
|
ipv6Address: ipv6Address,
|
||||||
|
disallowIPs: disallowIPs,
|
||||||
|
postUp: postUp,
|
||||||
|
postDown: postDown,
|
||||||
|
mtu: mtu,
|
||||||
|
listenPort: listenPort,
|
||||||
|
dnsServers: dnsServers,
|
||||||
|
notes: notes
|
||||||
|
});
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGenerateKey = (): void => {
|
|
||||||
handleInputChange('privateKey', generateWireGuardPrivateKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="node-editor-overlay">
|
<div className="node-editor-overlay">
|
||||||
<div className="node-editor">
|
<div className="node-editor">
|
||||||
<div className="editor-header">
|
<div className="editor-header">
|
||||||
<h2>编辑节点: {formData.label || '新节点'}</h2>
|
<h2>编辑节点: {label}</h2>
|
||||||
<button className="close-btn" onClick={onClose}>×</button>
|
<button className="close-btn" onClick={onClose}>×</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -80,8 +87,8 @@ export default function NodeEditor({
|
|||||||
<label>节点名称</label>
|
<label>节点名称</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.label || ''}
|
value={label}
|
||||||
onChange={(e) => handleInputChange('label', e.target.value)}
|
onChange={e => setLabel(e.target.value)}
|
||||||
placeholder="例如: Node-A"
|
placeholder="例如: Node-A"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -90,10 +97,11 @@ export default function NodeEditor({
|
|||||||
<label>私钥</label>
|
<label>私钥</label>
|
||||||
<div className="item-group">
|
<div className="item-group">
|
||||||
<input
|
<input
|
||||||
value={formData.privateKey || ''}
|
value={privateKey}
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
<button className="btn-interect" onClick={handleGenerateKey}>重新生成</button>
|
<button className="btn-interect"
|
||||||
|
onClick={_ => setPrivateKey(generateWireGuardPrivateKey())}>重新生成</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -102,8 +110,8 @@ export default function NodeEditor({
|
|||||||
<label>IPv4地址</label>
|
<label>IPv4地址</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.ipv4Address || ''}
|
value={ipv4Address || ''}
|
||||||
onChange={(e) => handleInputChange('ipv4Address', e.target.value)}
|
onChange={e => setIpv4Address(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -113,8 +121,8 @@ export default function NodeEditor({
|
|||||||
<label>IPv6地址</label>
|
<label>IPv6地址</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.ipv6Address || ''}
|
value={ipv6Address || ''}
|
||||||
onChange={(e) => handleInputChange('ipv6Address', e.target.value)}
|
onChange={e => setIpv6Address(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -124,8 +132,8 @@ export default function NodeEditor({
|
|||||||
<label>子网黑名单</label>
|
<label>子网黑名单</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.disallowIPs || ''}
|
value={disallowIPs || ''}
|
||||||
onChange={(e) => handleInputChange('disallowIPs', e.target.value)}
|
onChange={e => setDisallowIPs(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -136,8 +144,11 @@ export default function NodeEditor({
|
|||||||
min="1024"
|
min="1024"
|
||||||
max="49151"
|
max="49151"
|
||||||
step="1"
|
step="1"
|
||||||
value={formData.listenPort || ''}
|
value={listenPort || ''}
|
||||||
onChange={(e) => handleInputChange('listenPort', e.target.value)}
|
onChange={e => {
|
||||||
|
const value = e.target.valueAsNumber;
|
||||||
|
setListenPort(isNaN(value) ? undefined : value);
|
||||||
|
}}
|
||||||
placeholder={`默认值:${settings.listenPort}`}
|
placeholder={`默认值:${settings.listenPort}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -148,8 +159,11 @@ export default function NodeEditor({
|
|||||||
type="number"
|
type="number"
|
||||||
min="1"
|
min="1"
|
||||||
step="1"
|
step="1"
|
||||||
value={formData.mtu || ''}
|
value={mtu || ''}
|
||||||
onChange={(e) => handleInputChange('mtu', e.target.value)}
|
onChange={e => {
|
||||||
|
const value = e.target.valueAsNumber;
|
||||||
|
setmtu(isNaN(value) ? undefined : value);
|
||||||
|
}}
|
||||||
placeholder={settings.mtu ? `默认值:${settings.mtu}` : ''}
|
placeholder={settings.mtu ? `默认值:${settings.mtu}` : ''}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -158,8 +172,8 @@ export default function NodeEditor({
|
|||||||
<label>DNS服务器</label>
|
<label>DNS服务器</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={formData.dnsServers || ''}
|
value={dnsServers || ''}
|
||||||
onChange={(e) => handleInputChange('dnsServers', e.target.value)}
|
onChange={(e) => setdnsServers(e.target.value)}
|
||||||
placeholder="例如: 8.8.8.8,1.1.1.1"
|
placeholder="例如: 8.8.8.8,1.1.1.1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -168,8 +182,8 @@ export default function NodeEditor({
|
|||||||
<label>PostUp</label>
|
<label>PostUp</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={2}
|
rows={2}
|
||||||
value={formData.postUp || ''}
|
value={postUp || ''}
|
||||||
onChange={(e) => handleInputChange('postUp', e.target.value)}
|
onChange={(e) => setPostUp(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -177,8 +191,8 @@ export default function NodeEditor({
|
|||||||
<label>PostDown</label>
|
<label>PostDown</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={2}
|
rows={2}
|
||||||
value={formData.postDown || ''}
|
value={postDown || ''}
|
||||||
onChange={(e) => handleInputChange('postDown', e.target.value)}
|
onChange={(e) => setPostDown(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -186,8 +200,8 @@ export default function NodeEditor({
|
|||||||
<label>备注</label>
|
<label>备注</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={4}
|
rows={4}
|
||||||
value={formData.notes || ''}
|
value={notes || ''}
|
||||||
onChange={(e) => handleInputChange('notes', e.target.value)}
|
onChange={(e) => setNotes(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Folder>
|
</Folder>
|
||||||
|
|||||||
@ -11,7 +11,20 @@ export type NodeData = {
|
|||||||
ipv4Address?: string;
|
ipv4Address?: string;
|
||||||
ipv6Address?: string;
|
ipv6Address?: string;
|
||||||
disallowIPs?: string;
|
disallowIPs?: string;
|
||||||
|
postUp?: string;
|
||||||
|
postDown?: string;
|
||||||
|
mtu?: number;
|
||||||
|
listenPort?: number;
|
||||||
|
dnsServers?: string;
|
||||||
|
notes?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeDataUpdate {
|
||||||
|
label: string;
|
||||||
|
privateKey: string;
|
||||||
|
ipv4Address?: string;
|
||||||
|
ipv6Address?: string;
|
||||||
|
disallowIPs?: string;
|
||||||
postUp?: string;
|
postUp?: string;
|
||||||
postDown?: string;
|
postDown?: string;
|
||||||
mtu?: number;
|
mtu?: number;
|
||||||
@ -23,7 +36,11 @@ export type NodeData = {
|
|||||||
export type EdgeData = {
|
export type EdgeData = {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
isTwoWayEdge: boolean;
|
isTwoWayEdge: boolean;
|
||||||
persistentKeepalive?: string;
|
persistentKeepalive?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EdgeDataUpdate {
|
||||||
|
persistentKeepalive?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SubNetRouter {
|
export class SubNetRouter {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user