Files
MikrotikManager/components/wireguard/wg-export-sheet.tsx
T
DenozordecandCursor 66509b26bd fix(ui): выровнять экспорт WireGuard под ReUI Frame
Убрать дубль копирования, вынести CodeExportSheet и семантические токены.
Открывать вкладку Peer при экспорте пира. Мигрировать VXLAN/Firewall/Containers/GRE.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-06 00:12:50 +07:00

144 lines
3.9 KiB
TypeScript

"use client"
import { useMemo } from "react"
import type { WgIfaceWithServer } from "@/components/data-grids/wireguard-data-grid"
import {
CodeExportSheet,
type CodeExportFormat,
} from "@/components/reui-kit/code-export-sheet"
import {
generateMikrotikRsc,
generateNativeConf,
generatePeerClientConf,
} from "@/lib/wg-config"
function WgExportSheet({
open,
iface,
onClose,
liveContent,
liveBusy,
onRequestLiveExport,
initialTab = "rsc",
peerId,
}: {
open: boolean
iface: WgIfaceWithServer | null
onClose: () => void
liveContent?: { rsc?: string; conf?: string; peerConf?: string } | null
liveBusy?: boolean
onRequestLiveExport?: (format: "rsc" | "conf" | "peer-conf") => void
initialTab?: "rsc" | "conf" | "peer"
/** Selected peer for Peer .conf (defaults to first peer) */
peerId?: string | null
}) {
const formats = useMemo((): CodeExportFormat[] => {
if (!iface) {
return [
{ id: "rsc", label: "MikroTik .rsc", filename: "wg.rsc", code: "" },
{ id: "conf", label: "Native .conf", filename: "wg.conf", code: "" },
{
id: "peer",
label: "Peer .conf",
filename: "wg-peer.conf",
code: "",
emptyMessage: "Интерфейс не выбран",
},
]
}
const base = {
name: iface.name,
listenPort: iface.listenPort,
mtu: iface.mtu,
comment: iface.comment,
enabled: iface.enabled,
privateKey: iface.privateKey,
publicKey: iface.publicKey,
address: iface.address,
serverName: iface.serverName,
peers: iface.peers.map((p) => ({
publicKey: p.publicKey,
allowedIps: p.allowedIps,
endpoint: p.endpoint,
persistentKeepalive: p.persistentKeepalive,
persistent: p.persistent,
comment: p.comment,
name: p.name,
clientAddress: p.clientAddress,
clientDns: p.clientDns,
clientEndpoint: p.clientEndpoint,
})),
}
const peer =
(peerId
? iface.peers.find((p) => p.id === peerId || p.rosId === peerId)
: undefined) ?? iface.peers[0]
const localRsc = generateMikrotikRsc(base)
const localConf = generateNativeConf(base)
let peerConf = ""
let peerEmpty: string | undefined
if (!iface.publicKey) {
peerEmpty = "Нет public-key интерфейса для клиентского .conf"
} else if (!peer) {
peerEmpty = "Нет пиров для экспорта Peer .conf"
} else {
peerConf = generatePeerClientConf({
peerAddress: peer.clientAddress,
peerDns: peer.clientDns,
serverPublicKey: iface.publicKey,
allowedIps: peer.allowedIps,
endpoint: peer.clientEndpoint || peer.endpoint || undefined,
persistentKeepalive: peer.persistentKeepalive ?? 25,
})
}
return [
{
id: "rsc",
label: "MikroTik .rsc",
filename: `${iface.name}.rsc`,
code: liveContent?.rsc ?? localRsc,
},
{
id: "conf",
label: "Native .conf",
filename: `${iface.name}.conf`,
code: liveContent?.conf ?? localConf,
},
{
id: "peer",
label: "Peer .conf",
filename: `${iface.name}-peer.conf`,
code: liveContent?.peerConf ?? peerConf,
emptyMessage: liveContent?.peerConf ? undefined : peerEmpty,
},
]
}, [iface, liveContent, peerId])
return (
<CodeExportSheet
open={open}
onClose={onClose}
title="Экспорт WireGuard"
description={iface ? `${iface.name} · ${iface.serverName}` : "—"}
formats={formats}
initialFormatId={initialTab}
liveBusy={liveBusy}
onLiveFetch={
onRequestLiveExport
? (formatId) =>
onRequestLiveExport(
formatId === "peer" ? "peer-conf" : formatId === "conf" ? "conf" : "rsc",
)
: undefined
}
/>
)
}
export { WgExportSheet }