Убрать дубль копирования, вынести CodeExportSheet и семантические токены. Открывать вкладку Peer при экспорте пира. Мигрировать VXLAN/Firewall/Containers/GRE. Co-authored-by: Cursor <cursoragent@cursor.com>
144 lines
3.9 KiB
TypeScript
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 }
|