feat(web): view zone without template, snapshot button, no-template status, drop delete

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
This commit is contained in:
2026-07-05 12:19:50 +07:00
parent 5662334799
commit c2832348f8
8 changed files with 217 additions and 45 deletions
+48 -1
View File
@@ -5,10 +5,20 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { DomainDiffPage } from "./DomainDiffPage"
import { AuthProvider } from "@/auth/AuthContext"
import { api } from "@/api/client"
import { vi, beforeEach } from "vitest"
import { vi, beforeEach, test, expect } from "vitest"
import type { Domain } from "@/api/types"
const PROJECT_ID = "p1"
const domainWithTemplate: Domain = {
id: "d1",
providerAccountId: "acc1",
zoneName: "example.com.",
zoneId: "z1",
templateId: "t1",
lastCheckStatus: "drift",
}
function renderPage() {
const qc = new QueryClient()
return render(
@@ -29,6 +39,7 @@ beforeEach(() => {
project: { id: PROJECT_ID, name: "Default" },
})
vi.spyOn(api, "domainHistory").mockResolvedValue([])
vi.spyOn(api, "listDomains").mockResolvedValue([domainWithTemplate])
})
test("apply sends applyPrunes=false by default, true only after opting in", async () => {
@@ -53,3 +64,39 @@ test("apply sends applyPrunes=false by default, true only after opting in", asyn
await waitFor(() => expect(applySpy).toHaveBeenCalledTimes(2))
expect(applySpy.mock.calls[1]).toEqual([PROJECT_ID, "d1", { applyUpdates: true, applyPrunes: true }])
})
test("домен без шаблона показывает записи зоны и не вызывает check", async () => {
vi.spyOn(api, "listDomains").mockResolvedValue([
{ id: "d1", providerAccountId: "acc1", zoneName: "example.com.", zoneId: "z1", templateId: null },
])
const checkSpy = vi.spyOn(api, "checkDomain")
vi.spyOn(api, "zoneRecords").mockResolvedValue([
{ type: "A", name: "example.com.", ttl: 3600, values: ["1.2.3.4"] },
])
renderPage()
expect(await screen.findByText(/шаблон не привязан/i)).toBeInTheDocument()
expect(screen.getByRole("button", { name: /создать шаблон из этой зоны/i })).toBeInTheDocument()
expect(await screen.findByText("example.com.")).toBeInTheDocument()
expect(screen.getByText("1.2.3.4")).toBeInTheDocument()
expect(screen.queryByText(/вычисляю дифф/i)).not.toBeInTheDocument()
expect(checkSpy).not.toHaveBeenCalled()
})
test("создание шаблона из зоны вызывает templateFromZone", async () => {
vi.spyOn(api, "listDomains").mockResolvedValue([
{ id: "d1", providerAccountId: "acc1", zoneName: "example.com.", zoneId: "z1", templateId: null },
])
vi.spyOn(api, "zoneRecords").mockResolvedValue([])
const templateFromZoneSpy = vi.spyOn(api, "templateFromZone").mockResolvedValue({
id: "t9", name: "example.com. snapshot", records: [], version: 1,
})
const user = userEvent.setup()
renderPage()
const createBtn = await screen.findByRole("button", { name: /создать шаблон из этой зоны/i })
await user.click(createBtn)
await waitFor(() => expect(templateFromZoneSpy).toHaveBeenCalledWith(PROJECT_ID, "d1"))
})