fix
This commit is contained in:
3 files changed
+76
-1
No files matched your search
@@ -100,6 +100,41 @@ export function useImportZones() {
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["domains", project?.id] }),
|
||||
})
|
||||
}
|
||||
const CHECK_ALL_CONCURRENCY = 4
|
||||
|
||||
// Ручной check по всем переданным доменам. Бэкенд (handleCheck) сам пишет
|
||||
// статус, поэтому после прогона достаточно перечитать список доменов.
|
||||
// Сбой одной зоны не прерывает остальные — считаем успехи и ошибки.
|
||||
export function useCheckAllDomains() {
|
||||
const { project } = useAuth()
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: async (ids: string[]) => {
|
||||
const pid = requireProjectId(project)
|
||||
let ok = 0
|
||||
let failed = 0
|
||||
const queue = [...ids]
|
||||
const worker = async () => {
|
||||
for (let id = queue.shift(); id !== undefined; id = queue.shift()) {
|
||||
try {
|
||||
await api.checkDomain(pid, id)
|
||||
ok++
|
||||
} catch {
|
||||
failed++
|
||||
}
|
||||
}
|
||||
}
|
||||
await Promise.all(
|
||||
Array.from({ length: Math.min(CHECK_ALL_CONCURRENCY, ids.length) }, worker),
|
||||
)
|
||||
return { ok, failed }
|
||||
},
|
||||
onSettled: () => {
|
||||
qc.invalidateQueries({ queryKey: ["domains", project?.id] })
|
||||
qc.invalidateQueries({ queryKey: ["check", project?.id] })
|
||||
},
|
||||
})
|
||||
}
|
||||
export function useSetDomainTemplate() {
|
||||
const { project } = useAuth()
|
||||
const qc = useQueryClient()
|
||||
|
||||
@@ -234,3 +234,16 @@ test("счётчик показывает, сколько доменов отф
|
||||
|
||||
expect(screen.getByText(/показано 1 из 2/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test("«Проверить все зоны» проверяет только домены с шаблоном и обновляет список", async () => {
|
||||
const check = vi.spyOn(api, "checkDomain").mockResolvedValue({ diffs: [] } as never)
|
||||
const user = userEvent.setup()
|
||||
renderPage()
|
||||
await screen.findByText("example.com.")
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Проверить все зоны" }))
|
||||
|
||||
await waitFor(() => expect(check).toHaveBeenCalledTimes(1))
|
||||
expect(check).toHaveBeenCalledWith(PROJECT_ID, "d2")
|
||||
expect(await screen.findByText("Проверено 1")).toBeInTheDocument()
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
import { Inbox, Loader2, Upload } from "lucide-react"
|
||||
import { GitCompareArrows, Inbox, Loader2, Upload } from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { StatusBadge } from "@/components/StatusBadge"
|
||||
import {
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
} from "@/components/ui/table"
|
||||
import {
|
||||
useAccounts,
|
||||
useCheckAllDomains,
|
||||
useDomains,
|
||||
useImportZones,
|
||||
useSetDomainTemplate,
|
||||
@@ -56,6 +57,7 @@ export function DomainsPage() {
|
||||
const accounts = useAccounts()
|
||||
const templates = useTemplates()
|
||||
const importZones = useImportZones()
|
||||
const checkAll = useCheckAllDomains()
|
||||
const setTemplate = useSetDomainTemplate()
|
||||
|
||||
const accountList = accounts.data ?? []
|
||||
@@ -104,6 +106,13 @@ export function DomainsPage() {
|
||||
importZones.mutate(selectedImportAccount)
|
||||
}
|
||||
|
||||
// Диф есть только у доменов с шаблоном; фильтры списка на набор не влияют.
|
||||
const checkableIds = domainList.filter((d) => d.templateId).map((d) => d.id)
|
||||
|
||||
function onCheckAll() {
|
||||
checkAll.mutate(checkableIds)
|
||||
}
|
||||
|
||||
function onTemplateChange(domainId: string, value: unknown) {
|
||||
const templateId = value === NO_TEMPLATE ? null : (value as string)
|
||||
setTemplate.mutate({ id: domainId, templateId })
|
||||
@@ -146,9 +155,27 @@ export function DomainsPage() {
|
||||
)}
|
||||
Импортировать зоны
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={onCheckAll}
|
||||
disabled={checkableIds.length === 0 || checkAll.isPending}
|
||||
>
|
||||
{checkAll.isPending ? (
|
||||
<Loader2 className="size-4 animate-spin" strokeWidth={1.75} />
|
||||
) : (
|
||||
<GitCompareArrows className="size-4" strokeWidth={1.75} />
|
||||
)}
|
||||
Проверить все зоны
|
||||
</Button>
|
||||
{importZones.isError && (
|
||||
<span className="font-dns text-xs text-destructive">{importZones.error.message}</span>
|
||||
)}
|
||||
{checkAll.isSuccess && (
|
||||
<span className="font-dns text-xs text-muted-foreground">
|
||||
Проверено {checkAll.data.ok}
|
||||
{checkAll.data.failed > 0 && `, ошибок ${checkAll.data.failed}`}
|
||||
</span>
|
||||
)}
|
||||
{importZones.isSuccess && (
|
||||
<span className="font-dns text-xs text-muted-foreground">
|
||||
Создано {importZones.data.created.length}, удалено {importZones.data.removed.length}
|
||||
|
||||
Reference in new issue
Block a user