refactor(traffic): update traffic flow host file generation and configuration scripts
Docker images / prepare-release (push) Successful in 6s
Docker images / backend-image (push) Successful in 1m39s
Docker images / frontend-image (push) Successful in 3m2s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 43s
Docker images / publish-release (push) Successful in 9s
Docker images / prepare-release (push) Successful in 6s
Docker images / backend-image (push) Successful in 1m39s
Docker images / frontend-image (push) Successful in 3m2s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 43s
Docker images / publish-release (push) Successful in 9s
- Renamed and refactored functions for better clarity, including `buildHostComposeSnippet` to `buildHostComposeOverride` and `buildHostNftSnippet` to `buildHostLinuxInstallSh`. - Introduced a new script for Linux installation of WireGuard, enhancing the setup process for Docker hosts. - Updated the `generateNativeConf` function to conditionally include the listen port in the configuration. - Adjusted the `FlowOverlaySheet` component to default to the new Linux tab and improved the user interface for selecting jump-hosts. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -60,10 +60,10 @@ function highlightLine(line: string): string {
|
||||
return "text-foreground/90"
|
||||
}
|
||||
|
||||
function CodeBlock({ code }: { code: string }) {
|
||||
function CodeBlock({ code, className }: { code: string; className?: string }) {
|
||||
const lines = code.length ? code.split("\n") : [""]
|
||||
return (
|
||||
<pre className="px-4 py-3.5 text-[12px] font-mono leading-[1.65] whitespace-pre-wrap break-all select-all">
|
||||
<pre className={cn("px-4 py-3.5 text-[12px] font-mono leading-[1.65] whitespace-pre-wrap break-all select-all", className)}>
|
||||
{lines.map((line, i) => (
|
||||
<span key={i} className={cn("block", highlightLine(line))}>
|
||||
{line || " "}
|
||||
@@ -281,4 +281,4 @@ function CodeExportSheet({
|
||||
)
|
||||
}
|
||||
|
||||
export { CodeExportSheet, downloadText }
|
||||
export { CodeExportSheet, CodeBlock, downloadText }
|
||||
|
||||
@@ -5,9 +5,17 @@ import { toast } from "sonner"
|
||||
import { FormField } from "@/components/form-kit"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/reui/alert"
|
||||
import { Frame, FramePanel } from "@/components/reui/frame"
|
||||
import { downloadText } from "@/components/reui-kit/code-export-sheet"
|
||||
import { CodeBlock, downloadText } from "@/components/reui-kit/code-export-sheet"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { ScrollArea } from "@/components/ui/scroll-area"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import {
|
||||
Sheet, SheetContent, SheetHeader, SheetTitle,
|
||||
@@ -15,7 +23,7 @@ import {
|
||||
} from "@/components/ui/sheet"
|
||||
import { applyTrafficFlowOverlay } from "@/shared/api/traffic-flow"
|
||||
import type { ServerRead } from "@mmapp/contracts/servers"
|
||||
import type { TrafficFlowHostFile, TrafficFlowOverlayResult } from "@mmapp/contracts/traffic-flow"
|
||||
import type { TrafficFlowOverlayResult } from "@mmapp/contracts/traffic-flow"
|
||||
import {
|
||||
CheckIcon,
|
||||
CopyIcon,
|
||||
@@ -45,13 +53,13 @@ function FlowOverlaySheet({
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [result, setResult] = useState<TrafficFlowOverlayResult | null>(null)
|
||||
const [copied, setCopied] = useState(false)
|
||||
const [tab, setTab] = useState("wg-quick")
|
||||
const [tab, setTab] = useState("linux")
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
setResult(null)
|
||||
setCopied(false)
|
||||
setTab("wg-quick")
|
||||
setTab("linux")
|
||||
const first = jumpHosts[0]
|
||||
const nextId = first ? String(first.id) : ""
|
||||
setServerId(nextId)
|
||||
@@ -64,20 +72,12 @@ function FlowOverlaySheet({
|
||||
if (selected) setEndpoint(selected.host)
|
||||
}
|
||||
|
||||
const formats = useMemo((): TrafficFlowHostFile[] => {
|
||||
if (!result) return []
|
||||
return [
|
||||
...result.hostFiles,
|
||||
{
|
||||
id: "peer",
|
||||
label: "[Peer]",
|
||||
filename: "wg-flow-peer.conf",
|
||||
code: result.linuxPeerBlock,
|
||||
},
|
||||
]
|
||||
}, [result])
|
||||
|
||||
const formats = result?.hostFiles ?? []
|
||||
const active = formats.find((f) => f.id === tab) ?? formats[0]
|
||||
const selectedHost = jumpHosts.find((s) => String(s.id) === serverId)
|
||||
const selectedLabel = selectedHost
|
||||
? `${selectedHost.name || selectedHost.host} (${selectedHost.host})`
|
||||
: "Выберите сервер…"
|
||||
const canSubmit = Boolean(serverId && endpoint.trim()) && !busy
|
||||
|
||||
async function handleSubmit() {
|
||||
@@ -86,7 +86,7 @@ function FlowOverlaySheet({
|
||||
try {
|
||||
const res = await applyTrafficFlowOverlay(backendUrl, serverId, endpoint.trim())
|
||||
setResult(res)
|
||||
setTab(res.hostFiles[0]?.id ?? "peer")
|
||||
setTab(res.hostFiles[0]?.id ?? "linux")
|
||||
toast.success(`wg-flow на ${res.address}`)
|
||||
onDone?.(res)
|
||||
} catch (e) {
|
||||
@@ -108,27 +108,35 @@ function FlowOverlaySheet({
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||
<SheetContent side="right" className="w-full sm:max-w-xl flex flex-col gap-0 p-0">
|
||||
<SheetHeader className="px-6 pt-6 pb-4 border-b shrink-0">
|
||||
<SheetTitle>Подключить jump-host</SheetTitle>
|
||||
<SheetContent
|
||||
side="right"
|
||||
className="flex w-full flex-col gap-0 overflow-hidden p-0 sm:max-w-2xl"
|
||||
>
|
||||
<SheetHeader className="shrink-0 gap-1 border-b px-5 pt-5 pb-4 pr-12">
|
||||
<SheetTitle className="text-base font-semibold tracking-tight">
|
||||
Подключить jump-host
|
||||
</SheetTitle>
|
||||
<SheetDescription>
|
||||
Создаст wg-flow на выбранном MikroTik (сервер, listen 13232) и сразу выдаст wg-quick / compose для Linux-хоста Docker MM (клиент).
|
||||
Создаст wg-flow на MikroTik (сервер, listen 13232) и выдаст готовый bash для Linux-хоста Docker MM (клиент).
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="flex-1 min-h-0 overflow-y-auto px-6 py-5 flex flex-col gap-5">
|
||||
<div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-5 py-4">
|
||||
<FormField label="Jump-host" required>
|
||||
<select
|
||||
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs outline-none"
|
||||
value={serverId}
|
||||
onChange={(e) => handleServerChange(e.target.value)}
|
||||
<Select
|
||||
value={serverId || undefined}
|
||||
onValueChange={(v) => handleServerChange(String(v ?? ""))}
|
||||
>
|
||||
<option value="">Выберите сервер…</option>
|
||||
{jumpHosts.map((s) => (
|
||||
<option key={s.id} value={s.id}>
|
||||
{s.name || s.host} ({s.host})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<SelectTrigger className="h-9 w-full min-w-0">
|
||||
<SelectValue>{selectedLabel}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent align="start" className="min-w-(--anchor-width)">
|
||||
{jumpHosts.map((s) => (
|
||||
<SelectItem key={s.id} value={String(s.id)}>
|
||||
{s.name || s.host} ({s.host})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Публичный IP или DNS jump-host"
|
||||
@@ -144,21 +152,24 @@ function FlowOverlaySheet({
|
||||
/>
|
||||
</FormField>
|
||||
{result ? (
|
||||
<div className="flex flex-col gap-4 min-h-0">
|
||||
<Alert>
|
||||
<div className="flex min-h-0 flex-col gap-4">
|
||||
<Alert variant="success">
|
||||
<InfoIcon />
|
||||
<AlertTitle>Ключи и UDP 4739</AlertTitle>
|
||||
<AlertTitle>Linux-хост /opt/cdn-mm</AlertTitle>
|
||||
<AlertDescription>
|
||||
Приватный ключ хоста в SQLite панели — не кладите в git. UDP 4739 публикуйте только на WG-IP хоста, не на 0.0.0.0 контейнера.
|
||||
Скопируйте вкладку Linux и выполните от root. WG — клиент к JH:13232; контейнер слушает только WG-IP:4739, не 0.0.0.0. Ключ не кладите в git.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<ul className="text-xs text-muted-foreground flex flex-col gap-1">
|
||||
<ul className="flex flex-col gap-1.5">
|
||||
{result.steps.map((s) => (
|
||||
<li key={s}>{s}</li>
|
||||
<li key={s} className="flex items-start gap-2 text-sm">
|
||||
<CheckIcon className="mt-0.5 size-3.5 shrink-0 text-success" />
|
||||
<span>{s}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{formats.length > 0 && active ? (
|
||||
<div className="flex flex-col gap-3 min-h-0">
|
||||
<div className="flex min-h-0 flex-col gap-3">
|
||||
<Tabs
|
||||
value={tab}
|
||||
onValueChange={(v) => {
|
||||
@@ -169,17 +180,17 @@ function FlowOverlaySheet({
|
||||
>
|
||||
<TabsList className="h-9 w-full">
|
||||
{formats.map((f) => (
|
||||
<TabsTrigger key={f.id} value={f.id} className="flex-1 px-1.5 text-xs sm:text-sm">
|
||||
<TabsTrigger key={f.id} value={f.id} className="flex-1 px-2 text-xs sm:text-sm">
|
||||
{f.label}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
<Frame dense className="flex min-h-0 flex-col">
|
||||
<Frame dense className="flex min-h-0 flex-col overflow-hidden">
|
||||
<FramePanel className="relative flex min-h-0 flex-col overflow-hidden p-0">
|
||||
<pre className="px-4 py-3.5 text-[12px] font-mono leading-[1.65] whitespace-pre-wrap break-all select-all min-h-[12rem]">
|
||||
{active.code}
|
||||
</pre>
|
||||
<ScrollArea className="h-full min-h-0 max-h-[min(52vh,22rem)]">
|
||||
<CodeBlock code={active.code} className="whitespace-pre break-normal" />
|
||||
</ScrollArea>
|
||||
</FramePanel>
|
||||
</Frame>
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
@@ -202,8 +213,10 @@ function FlowOverlaySheet({
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<SheetFooter className="px-6 py-4 border-t shrink-0 flex-row gap-2">
|
||||
<SheetClose render={<Button variant="outline" />}>Закрыть</SheetClose>
|
||||
<SheetFooter className="shrink-0 flex-row items-center justify-between gap-3 border-t px-5 py-3.5 sm:flex-row">
|
||||
<SheetClose render={<Button type="button" variant="outline" className="shrink-0" />}>
|
||||
Закрыть
|
||||
</SheetClose>
|
||||
<Button disabled={!canSubmit} onClick={() => { void handleSubmit() }}>
|
||||
{busy ? "Подключение…" : "Подключить"}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user