fix: resolve WireGuard server tab crash and enforce client creation server prerequisite

This commit is contained in:
xtcnet 2026-03-08 09:47:20 +07:00
parent 54d1623551
commit 36acc3ea65
3 changed files with 34 additions and 23 deletions

View file

@ -357,20 +357,27 @@ const internalWireguard = {
}, },
/** /**
* Get the WireGuard interface info * Get the WireGuard interfaces info
*/ */
async getInterfaceInfo(knex) { async getInterfacesInfo(knex) {
const iface = await this.getOrCreateInterface(knex); const ifaces = await knex("wg_interface").select("*");
return { const allLinks = await knex("wg_server_link").select("*");
id: iface.id,
name: iface.name, return ifaces.map((i) => {
public_key: iface.public_key, const links = allLinks.filter(l => l.interface_id_1 === i.id || l.interface_id_2 === i.id);
ipv4_cidr: iface.ipv4_cidr, return {
listen_port: iface.listen_port, id: i.id,
mtu: iface.mtu, name: i.name,
dns: iface.dns, public_key: i.public_key,
host: iface.host, ipv4_cidr: i.ipv4_cidr,
}; listen_port: i.listen_port,
mtu: i.mtu,
dns: i.dns,
host: i.host,
isolate_clients: i.isolate_clients,
linked_servers: links.map(l => l.interface_id_1 === i.id ? l.interface_id_2 : l.interface_id_1),
};
});
}, },
/** /**

View file

@ -10,13 +10,13 @@ const router = express.Router({
/** /**
* GET /api/wireguard * GET /api/wireguard
* Get WireGuard interface info * Get WireGuard interfaces info
*/ */
router.get("/", async (_req, res, next) => { router.get("/", async (_req, res, next) => {
try { try {
const knex = db(); const knex = db();
const iface = await internalWireguard.getInterfaceInfo(knex); const ifaces = await internalWireguard.getInterfacesInfo(knex);
res.status(200).json(iface); res.status(200).json(ifaces);
} catch (err) { } catch (err) {
next(err); next(err);
} }

View file

@ -48,7 +48,7 @@ function timeAgo(date: string | null): string {
} }
function WireGuard() { function WireGuard() {
const [activeTab, setActiveTab] = useState<"servers" | "clients">("clients"); const [activeTab, setActiveTab] = useState<"servers" | "clients">("servers");
const { data: clients, isLoading: clientsLoading } = useWgClients(); const { data: clients, isLoading: clientsLoading } = useWgClients();
const { data: interfaces, isLoading: ifacesLoading } = useWgInterfaces(); const { data: interfaces, isLoading: ifacesLoading } = useWgInterfaces();
@ -107,6 +107,10 @@ function WireGuard() {
// Client Handlers // Client Handlers
const handleNewClient = async () => { const handleNewClient = async () => {
if (!interfaces || interfaces.length === 0) {
alert("Bạn phải tạo một WireGuard Server trước khi tạo Client.");
return;
}
const result = (await EasyModal.show(WireGuardClientModal, { interfaces: interfaces || [] })) as any; const result = (await EasyModal.show(WireGuardClientModal, { interfaces: interfaces || [] })) as any;
if (result && result.name && result.interface_id) { if (result && result.name && result.interface_id) {
createClient.mutate({ name: result.name, interface_id: result.interface_id }); createClient.mutate({ name: result.name, interface_id: result.interface_id });
@ -174,18 +178,18 @@ function WireGuard() {
<div className="card"> <div className="card">
<div className="card-header"> <div className="card-header">
<ul className="nav nav-tabs card-header-tabs" data-bs-toggle="tabs"> <ul className="nav nav-tabs card-header-tabs" data-bs-toggle="tabs">
<li className="nav-item cursor-pointer">
<a className={`nav-link ${activeTab === "clients" ? "active" : ""}`} onClick={() => setActiveTab("clients")}>
<IconNetwork className="me-1" size={16}/> Clients
<span className="badge bg-green ms-2">{clients?.length || 0}</span>
</a>
</li>
<li className="nav-item cursor-pointer"> <li className="nav-item cursor-pointer">
<a className={`nav-link ${activeTab === "servers" ? "active" : ""}`} onClick={() => setActiveTab("servers")}> <a className={`nav-link ${activeTab === "servers" ? "active" : ""}`} onClick={() => setActiveTab("servers")}>
<IconServer className="me-1" size={16}/> Servers <IconServer className="me-1" size={16}/> Servers
<span className="badge bg-blue ms-2">{interfaces?.length || 0}</span> <span className="badge bg-blue ms-2">{interfaces?.length || 0}</span>
</a> </a>
</li> </li>
<li className="nav-item cursor-pointer">
<a className={`nav-link ${activeTab === "clients" ? "active" : ""}`} onClick={() => setActiveTab("clients")}>
<IconNetwork className="me-1" size={16}/> Clients
<span className="badge bg-green ms-2">{clients?.length || 0}</span>
</a>
</li>
</ul> </ul>
</div> </div>