2026-03-07 13:49:44 +00:00
|
|
|
import EasyModal, { useModal } from "ez-modal-react";
|
2026-03-08 02:33:24 +00:00
|
|
|
import { useState, useEffect } from "react";
|
2026-03-07 13:49:44 +00:00
|
|
|
import Modal from "react-bootstrap/Modal";
|
|
|
|
|
import { Button } from "src/components";
|
2026-03-08 02:33:24 +00:00
|
|
|
import type { WgInterface } from "src/api/backend/wireguard";
|
2026-03-07 13:49:44 +00:00
|
|
|
|
2026-03-08 02:33:24 +00:00
|
|
|
interface WireGuardClientModalProps {
|
|
|
|
|
interfaces: WgInterface[];
|
|
|
|
|
defaultInterfaceId?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const WireGuardClientModal = EasyModal.create(({ interfaces, defaultInterfaceId }: WireGuardClientModalProps) => {
|
2026-03-07 13:49:44 +00:00
|
|
|
const modal = useModal<any>();
|
|
|
|
|
const [name, setName] = useState("");
|
2026-03-08 02:33:24 +00:00
|
|
|
const [selectedInterfaceId, setSelectedInterfaceId] = useState<number>(0);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (defaultInterfaceId) {
|
|
|
|
|
setSelectedInterfaceId(defaultInterfaceId);
|
|
|
|
|
} else if (interfaces && interfaces.length > 0) {
|
|
|
|
|
setSelectedInterfaceId(interfaces[0].id);
|
|
|
|
|
}
|
|
|
|
|
}, [interfaces, defaultInterfaceId]);
|
2026-03-07 13:49:44 +00:00
|
|
|
|
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
|
|
|
e.preventDefault();
|
2026-03-08 02:33:24 +00:00
|
|
|
if (name.trim() && selectedInterfaceId) {
|
|
|
|
|
modal.resolve({
|
|
|
|
|
name: name.trim(),
|
|
|
|
|
interface_id: selectedInterfaceId
|
|
|
|
|
});
|
2026-03-07 13:49:44 +00:00
|
|
|
modal.hide();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleClose = () => {
|
|
|
|
|
modal.resolve(null);
|
|
|
|
|
modal.hide();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Modal show={modal.visible} onHide={handleClose} backdrop="static">
|
|
|
|
|
<form onSubmit={(e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
handleSubmit(e);
|
|
|
|
|
}}>
|
|
|
|
|
<Modal.Header closeButton>
|
|
|
|
|
<Modal.Title>New WireGuard Client</Modal.Title>
|
|
|
|
|
</Modal.Header>
|
|
|
|
|
<Modal.Body>
|
|
|
|
|
<div className="mb-3">
|
2026-03-08 02:33:24 +00:00
|
|
|
<label htmlFor="wg-client-name" className="form-label required">
|
2026-03-07 13:49:44 +00:00
|
|
|
Client Name
|
|
|
|
|
</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
className="form-control"
|
|
|
|
|
id="wg-client-name"
|
|
|
|
|
placeholder="e.g. My Phone, Laptop, ..."
|
|
|
|
|
value={name}
|
|
|
|
|
onChange={(e) => setName(e.target.value)}
|
|
|
|
|
autoFocus
|
|
|
|
|
required
|
|
|
|
|
/>
|
|
|
|
|
<div className="form-text">
|
|
|
|
|
A friendly name to identify this client.
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-08 02:33:24 +00:00
|
|
|
|
|
|
|
|
{interfaces && interfaces.length > 0 && (
|
|
|
|
|
<div className="mb-3">
|
|
|
|
|
<label htmlFor="wg-server-select" className="form-label required">
|
|
|
|
|
WireGuard Server
|
|
|
|
|
</label>
|
|
|
|
|
<select
|
|
|
|
|
className="form-select"
|
|
|
|
|
id="wg-server-select"
|
|
|
|
|
value={selectedInterfaceId}
|
|
|
|
|
onChange={(e) => setSelectedInterfaceId(Number(e.target.value))}
|
|
|
|
|
required
|
|
|
|
|
>
|
|
|
|
|
{interfaces.map(iface => (
|
|
|
|
|
<option key={iface.id} value={iface.id}>
|
|
|
|
|
{iface.name} ({iface.ipv4Cidr})
|
|
|
|
|
</option>
|
|
|
|
|
))}
|
|
|
|
|
</select>
|
|
|
|
|
<div className="form-text">
|
|
|
|
|
Select which server this client will connect to.
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-03-07 13:49:44 +00:00
|
|
|
</Modal.Body>
|
|
|
|
|
<Modal.Footer>
|
|
|
|
|
<Button data-bs-dismiss="modal" onClick={handleClose}>
|
|
|
|
|
Cancel
|
|
|
|
|
</Button>
|
2026-03-08 02:33:24 +00:00
|
|
|
<Button type="submit" className="ms-auto btn-primary" disabled={!name.trim() || !selectedInterfaceId}>
|
2026-03-07 13:49:44 +00:00
|
|
|
Create Client
|
|
|
|
|
</Button>
|
|
|
|
|
</Modal.Footer>
|
|
|
|
|
</form>
|
|
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export default WireGuardClientModal;
|