fix(ui): защитить форму импорта WireGuard во время запроса
This commit is contained in:
1 parent
efc6da1249
commit
ec6ec52965
6 files changed
+89
-16
No files matched your search
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { useMemo, useState } from "react"
|
||||
import { FormField, SectionTitle } from "@/components/form-kit"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
@@ -17,6 +17,7 @@ function WgImportSheet({
|
||||
onOpenChange,
|
||||
servers,
|
||||
busy,
|
||||
error,
|
||||
defaultServerId,
|
||||
onImport,
|
||||
}: {
|
||||
@@ -24,6 +25,7 @@ function WgImportSheet({
|
||||
onOpenChange: (v: boolean) => void
|
||||
servers: ServerOption[]
|
||||
busy?: boolean
|
||||
error?: string | null
|
||||
defaultServerId?: string
|
||||
onImport: (args: {
|
||||
serverId: string
|
||||
@@ -43,10 +45,11 @@ function WgImportSheet({
|
||||
[content],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
setServerId(defaultServerId ?? "")
|
||||
}, [open, defaultServerId])
|
||||
const [context, setContext] = useState({ open: false, defaultServerId })
|
||||
if (context.open !== open || context.defaultServerId !== defaultServerId) {
|
||||
setContext({ open, defaultServerId })
|
||||
if (open) setServerId(defaultServerId ?? "")
|
||||
}
|
||||
|
||||
function runPreview() {
|
||||
setParseError(null)
|
||||
@@ -73,6 +76,7 @@ function WgImportSheet({
|
||||
<Sheet
|
||||
open={open}
|
||||
onOpenChange={(v) => {
|
||||
if (busy) return
|
||||
if (v) {
|
||||
setServerId(defaultServerId ?? "")
|
||||
} else {
|
||||
@@ -84,7 +88,7 @@ function WgImportSheet({
|
||||
onOpenChange(v)
|
||||
}}
|
||||
>
|
||||
<SheetContent side="right" className="w-full sm:max-w-lg flex flex-col gap-0 p-0">
|
||||
<SheetContent showCloseButton={!busy} side="right" className="w-full sm:max-w-lg flex flex-col gap-0 p-0">
|
||||
<SheetHeader className="px-6 pt-6 pb-4 border-b shrink-0">
|
||||
<SheetTitle>Импорт конфига WireGuard</SheetTitle>
|
||||
<SheetDescription>
|
||||
@@ -92,10 +96,11 @@ function WgImportSheet({
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
|
||||
<div className="flex-1 overflow-y-auto px-6 py-5 flex flex-col gap-5">
|
||||
<fieldset disabled={busy} aria-busy={busy} className="min-h-0 min-w-0 flex-1 overflow-y-auto px-6 py-5 flex flex-col gap-5">
|
||||
<FormField label="Сервер" 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 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
|
||||
aria-label="Сервер"
|
||||
value={serverId}
|
||||
onChange={(e) => setServerId(e.target.value)}
|
||||
>
|
||||
@@ -111,6 +116,7 @@ function WgImportSheet({
|
||||
<FormField label="Формат">
|
||||
<select
|
||||
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm"
|
||||
aria-label="Формат"
|
||||
value={format}
|
||||
onChange={(e) => setFormat(e.target.value as "auto" | "rsc" | "conf")}
|
||||
>
|
||||
@@ -135,6 +141,7 @@ function WgImportSheet({
|
||||
<textarea
|
||||
className="min-h-40 w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-xs leading-relaxed outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
|
||||
placeholder={"[Interface]\nPrivateKey = …\n…\n\nили\n\n/interface wireguard add …"}
|
||||
aria-label="Конфигурация WireGuard"
|
||||
value={content}
|
||||
onChange={(e) => {
|
||||
setContent(e.target.value)
|
||||
@@ -148,7 +155,7 @@ function WgImportSheet({
|
||||
Предпросмотр
|
||||
</Button>
|
||||
|
||||
{parseError && <p className="text-sm text-destructive">{parseError}</p>}
|
||||
{parseError && <p role="alert" className="text-sm text-destructive">{parseError}</p>}
|
||||
|
||||
{preview && (
|
||||
<div className="rounded-lg border border-border bg-muted/20 px-4 py-3 text-sm flex flex-col gap-2">
|
||||
@@ -167,14 +174,17 @@ function WgImportSheet({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<SheetFooter className="px-6 py-4 border-t shrink-0 flex-col gap-2 sm:flex-col">
|
||||
{busy && <p role="status" className="text-sm text-muted-foreground">Ожидание результата импорта…</p>}
|
||||
{error && <p role="alert" className="text-sm text-destructive">{error}</p>}
|
||||
<div className="flex w-full gap-2">
|
||||
<SheetClose render={<Button variant="outline" className="flex-1" disabled={busy} />}>
|
||||
Отмена
|
||||
</SheetClose>
|
||||
<Button
|
||||
type="button"
|
||||
className="flex-1"
|
||||
disabled={!serverId || !content.trim() || busy}
|
||||
onClick={() => void onImport({ serverId, content, format, dryRun: false })}
|
||||
|
||||
Reference in new issue
Block a user