fix(ui): учитывать готовность устройства в действиях IPsec

This commit is contained in:
Denozordec committed 2026-09-30 14:48:21 +07:00
1 parent b8923d075d
commit f0071a495c
7 files changed
+97 -12

No files matched your search

+20 -5
View File
@@ -300,6 +300,13 @@ function IpsecPage() {
const failedServerIds = new Set(failures.map(f => f.serverId))
const scopeUnknown = isLive && (!hasLoaded || !!dataError || (effectiveServerId === ALL_SERVERS_ID ? failures.length > 0 : failedServerIds.has(effectiveServerId)))
const canManage = (serverId: string) => isLive && hasLoaded && !dataError && !inventoryError &&
!loading && !busy && !historyRestoring && !failedServerIds.has(serverId) && liveServers.some(s => s.id === serverId)
const assertDeviceReady = (serverId: string) => {
if (!canManage(serverId)) throw new Error("Сначала подтвердите актуальное состояние устройства: повторите опрос IPsec")
}
const hasReadyDevice = displayServers.some(s => canManage(s.id))
const scopedClients = useMemo(() => {
if (effectiveServerId === ALL_SERVERS_ID) return displayClients
return displayClients.filter((c) => c.serverId === effectiveServerId)
@@ -370,6 +377,7 @@ function IpsecPage() {
}, [displayServers, displayClients])
const handleInit = async (form: IpsecInitFormState) => {
assertDeviceReady(form.serverId)
setBusy(true)
try {
await initIpsecServer(backendUrl, {
@@ -391,6 +399,7 @@ function IpsecPage() {
}
const handleCreateUser = async (form: IpsecUserFormState) => {
assertDeviceReady(form.serverId)
setBusy(true)
try {
const res = await createIpsecUser(backendUrl, {
@@ -424,6 +433,7 @@ function IpsecPage() {
const handleEditUser = async (form: IpsecUserFormState) => {
if (!editing) return
assertDeviceReady(editing.serverId)
setBusy(true)
try {
await patchIpsecUser(backendUrl, editing.serverId, editing.rosId, {
@@ -490,6 +500,8 @@ function IpsecPage() {
const confirmDelete = async (force = false) => {
if (!pendingDelete || deleteLock.current || (force && !forceAllowed)) return
const target = pendingDelete
const serverId = target.kind === "user" ? target.client.serverId : target.kind === "server" ? target.summary.serverId : target.serverId
if (!canManage(serverId)) { setDeleteError("Повторите опрос IPsec перед удалением"); return }
deleteLock.current = true
setBusy(true)
setDeleteError(null)
@@ -523,6 +535,7 @@ function IpsecPage() {
const handleEditPeer = async (form: IpsecPeerFormState) => {
if (!editingPeer) return
assertDeviceReady(editingPeer.serverId)
setBusy(true)
try {
await patchIpsecPeer(backendUrl, editingPeer.serverId, editingPeer.peer.rosId, {
@@ -586,7 +599,7 @@ function IpsecPage() {
<Button
size="sm"
variant="outline"
disabled={loading}
disabled={loading || busy || historyRestoring}
onClick={() => void loadLive()}
>
<RefreshCwIcon className={`size-4 ${loading ? "animate-spin" : ""}`} />
@@ -597,7 +610,7 @@ function IpsecPage() {
<Button
size="sm"
variant="outline"
disabled={loading || !historyServerId}
disabled={loading || busy || historyRestoring || !historyServerId}
title={!historyServerId ? "Выберите сервер, чтобы смотреть историю" : "История версий и откат"}
onClick={() => {
setHistoryOpen(true)
@@ -609,7 +622,7 @@ function IpsecPage() {
</Button>
)}
{isLive ? (
<Button size="sm" onClick={() => setUserOpen(true)}>
<Button size="sm" disabled={!hasReadyDevice} onClick={() => setUserOpen(true)}>
<PlusIcon className="size-4" />
Новый клиент
</Button>
@@ -713,7 +726,7 @@ function IpsecPage() {
searchPlaceholder="Поиск по имени / CN / IP…"
actions={
isLive ? (
<Button size="sm" onClick={() => { setEditing(null); setUserOpen(true) }}>
<Button size="sm" disabled={!hasReadyDevice} onClick={() => { setEditing(null); setUserOpen(true) }}>
<PlusIcon className="size-4" />
Клиент
</Button>
@@ -722,6 +735,7 @@ function IpsecPage() {
/>
{isLive && !hasLoaded ? <p role="status" className="p-5 text-sm text-muted-foreground">{loading ? "Загрузка клиентов IPsec…" : "Клиенты IPsec пока неизвестны"}</p> : <IpsecUsersGrid
clients={filteredClients}
canManage={canManage}
emptyTitle={scopeUnknown ? "Клиенты IPsec пока неизвестны" : undefined}
emptyDescription={scopeUnknown ? "Повторите опрос устройств, чтобы подтвердить состояние" : undefined}
compactServer={compactServer}
@@ -735,6 +749,7 @@ function IpsecPage() {
<TabsContent value="server" className="mt-0 outline-none">
{isLive && !hasLoaded ? <p role="status" className="p-5 text-sm text-muted-foreground">Состояние серверов IPsec пока неизвестно</p> : <IpsecServerGrid
servers={scopedSummaries}
canManage={canManage}
onInit={isLive ? (s) => { setSelectedServerId(s.serverId); setInitOpen(true) } : undefined}
onRemove={isLive ? (s) => setPendingDelete({ kind: "server", summary: s }) : undefined}
onEditPeer={isLive ? openEditPeer : undefined}
@@ -814,7 +829,7 @@ function IpsecPage() {
<IpsecUserSheet
open={userOpen}
onOpenChange={(v) => { setUserOpen(v); if (!v) setEditing(null) }}
servers={serverOptions}
servers={serverOptions.filter(s => canManage(s.id) || busy)}
peers={peerOptions}
busy={busy}
defaultServerId={sheetServerId}