From 1d497d01c25aa794eead0e73d92e751ac3f6b0bd Mon Sep 17 00:00:00 2001 From: Denozordec Date: Mon, 20 Jul 2026 17:28:02 +0700 Subject: [PATCH] feat(health-check): add TLS verification option to health check configuration Introduced a new `verify_tls` boolean option in health check configurations across various services, allowing users to specify whether to validate TLS certificates during health checks. Updated related components and services to accommodate this new option, ensuring proper handling in both the backend and frontend. Enhanced tests to validate the new functionality and ensure correct behavior with different configurations. --- .cursor/rules/backend-api-ui.mdc | 9 +- .cursor/rules/frontend-ui-patterns.mdc | 2 +- apps/api/src/routes/health.ts | 5 - apps/api/src/services/health-check-service.ts | 9 +- .../src/services/service-config-service.ts | 10 +- apps/api/test/health-check.test.ts | 27 + .../app-shell-12/components/app-shell.tsx | 46 - .../app-shell-12/components/app-sidebar.tsx | 92 -- .../app-shell-12/components/apps-menu.tsx | 54 - .../blocks/app-shell-12/components/brand.tsx | 72 -- .../blocks/app-shell-12/components/data.tsx | 604 --------- .../components/item-action-menu.tsx | 51 - .../app-shell-12/components/nav-main.tsx | 140 -- .../app-shell-12/components/nav-projects.tsx | 113 -- .../app-shell-12/components/nav-secondary.tsx | 36 - .../components/notifications-menu.tsx | 460 ------- .../app-shell-12/components/page-toolbar.tsx | 27 - .../app-shell-12/components/search-menu.tsx | 64 - .../app-shell-12/components/site-footer.tsx | 26 - .../app-shell-12/components/site-header.tsx | 44 - .../app-shell-12/components/user-menu.tsx | 340 ----- .../components/blocks/app-shell-12/page.tsx | 5 - .../blocks/auth-13/components/auth-logo.tsx | 34 - .../blocks/auth-13/components/auth.tsx | 58 - .../blocks/auth-13/components/data.tsx | 60 - .../blocks/auth-13/components/login-form.tsx | 86 -- .../auth-13/components/noise-texture.tsx | 57 - .../src/components/blocks/auth-13/page.tsx | 25 - .../blocks/card-18/components/card-grid.tsx | 15 - .../blocks/card-18/components/card-item.tsx | 34 - .../blocks/card-18/components/data.tsx | 39 - .../src/components/blocks/card-18/page.tsx | 9 - .../blocks/card-35/components/card-grid.tsx | 17 - .../blocks/card-35/components/card-item.tsx | 233 ---- .../blocks/card-35/components/data.tsx | 23 - .../src/components/blocks/card-35/page.tsx | 9 - .../dashboard-1/components/capacity-chart.tsx | 416 ------ .../dashboard-1/components/chart-cards.tsx | 64 - .../dashboard-1/components/commander-card.tsx | 155 --- .../dashboard-1/components/dashboard.tsx | 35 - .../blocks/dashboard-1/components/data.tsx | 676 ---------- .../components/exception-columns.tsx | 520 -------- .../dashboard-1/components/exception-grid.tsx | 369 ------ .../dashboard-1/components/navbar-actions.tsx | 246 ---- .../components/navbar-breadcrumb.tsx | 34 - .../components/navbar-presence.tsx | 80 -- .../blocks/dashboard-1/components/navbar.tsx | 17 - .../components/blocks/dashboard-1/page.tsx | 9 - .../components/columns.tsx | 406 ------ .../components/data-grid-view.tsx | 662 ---------- .../data-grid-filtering-2/components/data.tsx | 384 ------ .../blocks/data-grid-filtering-2/page.tsx | 15 - .../components/columns.tsx | 550 -------- .../components/data-grid-view.tsx | 620 --------- .../data-grid-grouping-2/components/data.tsx | 459 ------- .../blocks/data-grid-grouping-2/page.tsx | 15 - .../blocks/empty-state-12/components/data.ts | 48 - .../empty-state-12/components/empty-state.tsx | 247 ---- .../components/blocks/empty-state-12/page.tsx | 15 - .../blocks/form-7/components/data.ts | 152 --- .../form-7/components/editable-detail-row.tsx | 222 ---- .../form-7/components/ticket-details-form.tsx | 1151 ----------------- .../web/src/components/blocks/form-7/page.tsx | 10 - .../blocks/kanban-board-8/components/data.tsx | 392 ------ .../components/kanban-board.tsx | 472 ------- .../components/blocks/kanban-board-8/page.tsx | 15 - .../components/access-review-alert.tsx | 49 - .../billing-seat-selection-cards.tsx | 69 - .../profile-1/components/billing-tab.tsx | 166 --- .../components/brand-accent-picker.tsx | 32 - .../blocks/profile-1/components/data.ts | 409 ------ .../components/image-upload-field.tsx | 134 -- .../components/profile-form-fields.tsx | 266 ---- .../components/profile-summary-frames.tsx | 145 --- .../profile-1/components/profile-tab.tsx | 244 ---- .../blocks/profile-1/components/profile.tsx | 148 --- .../profile-1/components/setting-row.tsx | 3 - .../profile-1/components/team-columns.tsx | 294 ----- .../profile-1/components/team-data-grid.tsx | 335 ----- .../blocks/profile-1/components/team-tab.tsx | 5 - .../profile-1/components/workspace-tab.tsx | 156 --- .../src/components/blocks/profile-1/page.tsx | 9 - .../blocks/settings-16/components/data.tsx | 147 --- .../components/integration-settings.tsx | 109 -- .../components/blocks/settings-16/page.tsx | 15 - .../blocks/settings-8/components/data.tsx | 243 ---- .../components/endpoint-actions-menu.tsx | 72 -- .../components/endpoint-alert-indicator.tsx | 49 - .../settings-8/components/endpoint-row.tsx | 83 -- .../settings-8/components/endpoint-toast.tsx | 46 - .../components/endpoint-url-copy.tsx | 54 - .../components/status-indicator.tsx | 11 - .../components/webhook-endpoints.tsx | 128 -- .../src/components/blocks/settings-8/page.tsx | 9 - .../blocks/stats-12/components/data.tsx | 47 - .../blocks/stats-12/components/stats.tsx | 43 - .../src/components/blocks/stats-12/page.tsx | 9 - apps/web/src/components/form-field.tsx | 58 - .../components/health-check-config-fields.tsx | 68 +- .../integrations/app-switcher-editor.tsx | 120 -- apps/web/src/components/mode-toggle.tsx | 29 - .../components/reui-kit/settings-shell.tsx | 8 +- apps/web/src/components/reui/color-picker.tsx | 220 ---- apps/web/src/components/reui/phone-input.tsx | 220 ---- apps/web/src/components/reui/rating.tsx | 164 --- .../web/src/components/service-edit-sheet.tsx | 9 +- .../components/service-group-edit-sheet.tsx | 5 +- apps/web/src/components/setting-row.tsx | 5 +- apps/web/src/lib/schemas.ts | 4 + apps/web/src/lib/ui-surface.ts | 15 - .../src/routes/_auth/settings/appearance.tsx | 86 +- docs/ui-design-contract.md | 9 +- packages/db/dist/index.d.ts | 77 +- packages/db/dist/index.js | 78 +- .../016_health_check_verify_tls.sql | 2 + packages/db/src/repos.ts | 30 +- packages/db/src/schema.ts | 8 +- packages/db/src/settings-repo.ts | 52 +- packages/shared/dist/index.d.ts | 53 +- packages/shared/dist/index.js | 12 +- .../shared/src/integration-vps-tracker.ts | 2 - packages/shared/src/schemas.ts | 4 + packages/shared/src/types.ts | 5 + 123 files changed, 351 insertions(+), 15912 deletions(-) delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/app-shell.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/app-sidebar.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/apps-menu.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/brand.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/data.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/item-action-menu.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/nav-main.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/nav-projects.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/nav-secondary.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/notifications-menu.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/page-toolbar.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/search-menu.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/site-footer.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/site-header.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/components/user-menu.tsx delete mode 100644 apps/web/src/components/blocks/app-shell-12/page.tsx delete mode 100644 apps/web/src/components/blocks/auth-13/components/auth-logo.tsx delete mode 100644 apps/web/src/components/blocks/auth-13/components/auth.tsx delete mode 100644 apps/web/src/components/blocks/auth-13/components/data.tsx delete mode 100644 apps/web/src/components/blocks/auth-13/components/login-form.tsx delete mode 100644 apps/web/src/components/blocks/auth-13/components/noise-texture.tsx delete mode 100644 apps/web/src/components/blocks/auth-13/page.tsx delete mode 100644 apps/web/src/components/blocks/card-18/components/card-grid.tsx delete mode 100644 apps/web/src/components/blocks/card-18/components/card-item.tsx delete mode 100644 apps/web/src/components/blocks/card-18/components/data.tsx delete mode 100644 apps/web/src/components/blocks/card-18/page.tsx delete mode 100644 apps/web/src/components/blocks/card-35/components/card-grid.tsx delete mode 100644 apps/web/src/components/blocks/card-35/components/card-item.tsx delete mode 100644 apps/web/src/components/blocks/card-35/components/data.tsx delete mode 100644 apps/web/src/components/blocks/card-35/page.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/capacity-chart.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/chart-cards.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/commander-card.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/dashboard.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/data.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/exception-columns.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/exception-grid.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/navbar-actions.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/navbar-breadcrumb.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/navbar-presence.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/components/navbar.tsx delete mode 100644 apps/web/src/components/blocks/dashboard-1/page.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/components/columns.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/components/data-grid-view.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/components/data.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-filtering-2/page.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-grouping-2/components/columns.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-grouping-2/components/data-grid-view.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-grouping-2/components/data.tsx delete mode 100644 apps/web/src/components/blocks/data-grid-grouping-2/page.tsx delete mode 100644 apps/web/src/components/blocks/empty-state-12/components/data.ts delete mode 100644 apps/web/src/components/blocks/empty-state-12/components/empty-state.tsx delete mode 100644 apps/web/src/components/blocks/empty-state-12/page.tsx delete mode 100644 apps/web/src/components/blocks/form-7/components/data.ts delete mode 100644 apps/web/src/components/blocks/form-7/components/editable-detail-row.tsx delete mode 100644 apps/web/src/components/blocks/form-7/components/ticket-details-form.tsx delete mode 100644 apps/web/src/components/blocks/form-7/page.tsx delete mode 100644 apps/web/src/components/blocks/kanban-board-8/components/data.tsx delete mode 100644 apps/web/src/components/blocks/kanban-board-8/components/kanban-board.tsx delete mode 100644 apps/web/src/components/blocks/kanban-board-8/page.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/access-review-alert.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/billing-seat-selection-cards.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/billing-tab.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/brand-accent-picker.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/data.ts delete mode 100644 apps/web/src/components/blocks/profile-1/components/image-upload-field.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/profile-form-fields.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/profile-summary-frames.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/profile-tab.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/profile.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/setting-row.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/team-columns.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/team-data-grid.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/team-tab.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/components/workspace-tab.tsx delete mode 100644 apps/web/src/components/blocks/profile-1/page.tsx delete mode 100644 apps/web/src/components/blocks/settings-16/components/data.tsx delete mode 100644 apps/web/src/components/blocks/settings-16/components/integration-settings.tsx delete mode 100644 apps/web/src/components/blocks/settings-16/page.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/data.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/endpoint-actions-menu.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/endpoint-alert-indicator.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/endpoint-row.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/endpoint-toast.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/endpoint-url-copy.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/status-indicator.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/components/webhook-endpoints.tsx delete mode 100644 apps/web/src/components/blocks/settings-8/page.tsx delete mode 100644 apps/web/src/components/blocks/stats-12/components/data.tsx delete mode 100644 apps/web/src/components/blocks/stats-12/components/stats.tsx delete mode 100644 apps/web/src/components/blocks/stats-12/page.tsx delete mode 100644 apps/web/src/components/integrations/app-switcher-editor.tsx delete mode 100644 apps/web/src/components/mode-toggle.tsx delete mode 100644 apps/web/src/components/reui/color-picker.tsx delete mode 100644 apps/web/src/components/reui/phone-input.tsx delete mode 100644 apps/web/src/components/reui/rating.tsx delete mode 100644 apps/web/src/lib/ui-surface.ts create mode 100644 packages/db/migrations/016_health_check_verify_tls.sql diff --git a/.cursor/rules/backend-api-ui.mdc b/.cursor/rules/backend-api-ui.mdc index 0f91e77..b9bd34f 100644 --- a/.cursor/rules/backend-api-ui.mdc +++ b/.cursor/rules/backend-api-ui.mdc @@ -20,13 +20,14 @@ Fastify backend: `apps/api/`. Контракты — `@cfdm/shared` (Zod). Front - Дублирование Zod schemas в `apps/web` — только re-export из `@cfdm/shared` - Самописные формы без `Field` + RHF + Zod -## shadcn-паттерны +## UI-паттерны (ReUI Frame) | API-данные | UI | |------------|-----| -| Список | `Table` / `DataTableCard` | -| Создание | `Card` + `FieldGroup` + RHF | -| Статус | `Badge` variants | +| Список | `ResourcePage` (Frame + DataGrid + Filters) | +| Создание / редактирование | `FormSheet` + `FieldGroup` + RHF | +| Settings | `SettingsShell` + Frame + `SettingRow` | +| Статус | ReUI `Badge` / `StatusBadge` | | Ошибка | `sonner` `toast.error` | ## Согласованность diff --git a/.cursor/rules/frontend-ui-patterns.mdc b/.cursor/rules/frontend-ui-patterns.mdc index 0db863d..038f679 100644 --- a/.cursor/rules/frontend-ui-patterns.mdc +++ b/.cursor/rules/frontend-ui-patterns.mdc @@ -36,7 +36,7 @@ alwaysApply: false | Forms | [form-7](https://reui.io/preview/base/form-7) | | Shell | [app-shell-12](https://reui.io/preview/base/app-shell-12) | -**SettingRow:** `FieldSeparator` только между соседними rows; не между toggle-row и nested fields (Health-check). +**SettingRow:** `FieldSeparator` opt-in (`separated`); не между toggle-row и nested fields (Health-check). Settings-секции — отдельные Frame + `gap`, без hairline под PageHeader. ## Иерархия компонентов diff --git a/apps/api/src/routes/health.ts b/apps/api/src/routes/health.ts index a16d287..43df357 100644 --- a/apps/api/src/routes/health.ts +++ b/apps/api/src/routes/health.ts @@ -1,7 +1,6 @@ import type { FastifyInstance } from "fastify"; import { z } from "zod"; import { healthCheck } from "../plugins/db.js"; -import { getAppSwitcher } from "@cfdm/db"; import * as authService from "../services/auth.js"; export async function healthRoutes(app: FastifyInstance) { @@ -40,10 +39,6 @@ export async function authRoutes(app: FastifyInstance) { }; }); - app.get("/settings/app-switcher", async (request) => { - return getAppSwitcher(request.server.db); - }); - const loginSchema = z.object({ username: z.string(), password: z.string(), diff --git a/apps/api/src/services/health-check-service.ts b/apps/api/src/services/health-check-service.ts index 527e7da..b8a876a 100644 --- a/apps/api/src/services/health-check-service.ts +++ b/apps/api/src/services/health-check-service.ts @@ -85,9 +85,10 @@ function createIpPinnedAgent( sniHost: string, useTls: boolean, timeoutMs: number, + verifyTls: boolean, ): Agent { const connector = buildConnector({ - rejectUnauthorized: false, + rejectUnauthorized: verifyTls, timeout: timeoutMs, }); return new Agent({ @@ -126,14 +127,15 @@ async function httpProbe( const connectAddr = String(ip || "").trim(); const headerHost = (target.hostname || "").trim() || connectAddr; const url = buildHttpProbeUrl(headerHost, port, pathWithSlash, useTls); + const verifyTls = target.verify_tls === true; const family = isIP(connectAddr); const pinToIp = family === 4 || family === 6; const dispatcher = pinToIp - ? createIpPinnedAgent(connectAddr, headerHost, useTls, timeoutMs) + ? createIpPinnedAgent(connectAddr, headerHost, useTls, timeoutMs, verifyTls) : useTls - ? createIpPinnedAgent(connectAddr, headerHost, useTls, timeoutMs) + ? createIpPinnedAgent(connectAddr, headerHost, useTls, timeoutMs, verifyTls) : undefined; try { @@ -373,6 +375,7 @@ export async function runDomainMonitors( path: monitor.path, expected_status: monitor.expected_status, timeout_ms: monitor.timeout_ms, + verify_tls: false, }; let result: ProbeResult; if (monitor.type === "http") { diff --git a/apps/api/src/services/service-config-service.ts b/apps/api/src/services/service-config-service.ts index 9e55111..d1c8179 100644 --- a/apps/api/src/services/service-config-service.ts +++ b/apps/api/src/services/service-config-service.ts @@ -40,6 +40,7 @@ export interface ServiceDomainInput { health_check_expected_status?: number | null; health_check_interval_sec?: number; health_check_timeout_ms?: number; + health_check_verify_tls?: boolean; } export interface ToggleRequest { @@ -59,6 +60,7 @@ export interface ServiceGroupBody { health_check_expected_status?: number | null; health_check_interval_sec?: number; health_check_timeout_ms?: number; + health_check_verify_tls?: boolean; } export interface UpdateServiceGroupBody { @@ -74,6 +76,7 @@ export interface UpdateServiceGroupBody { health_check_expected_status?: number | null; health_check_interval_sec?: number; health_check_timeout_ms?: number; + health_check_verify_tls?: boolean; } export interface UpdateServiceConfigRequest { @@ -322,6 +325,7 @@ async function buildView(db: Db, serviceId: number): Promise { health_check_expected_status: binding.health_check_expected_status, health_check_interval_sec: binding.health_check_interval_sec, health_check_timeout_ms: binding.health_check_timeout_ms, + health_check_verify_tls: binding.health_check_verify_tls, sync_status: aggregateSyncStatus(statuses), }; }); @@ -1209,7 +1213,8 @@ export async function updateConfig( input.health_check_path !== undefined || input.health_check_expected_status !== undefined || input.health_check_interval_sec !== undefined || - input.health_check_timeout_ms !== undefined + input.health_check_timeout_ms !== undefined || + input.health_check_verify_tls !== undefined ) { repos.updateBindingLbConfig(db, binding.id, { lb_mode: input.lb_mode, @@ -1220,6 +1225,7 @@ export async function updateConfig( health_check_expected_status: input.health_check_expected_status, health_check_interval_sec: input.health_check_interval_sec, health_check_timeout_ms: input.health_check_timeout_ms, + health_check_verify_tls: input.health_check_verify_tls, }); } @@ -1314,6 +1320,7 @@ export async function createGroup( health_check_expected_status: body.health_check_expected_status, health_check_interval_sec: body.health_check_interval_sec, health_check_timeout_ms: body.health_check_timeout_ms, + health_check_verify_tls: body.health_check_verify_tls, }, ); } @@ -1349,6 +1356,7 @@ export async function updateGroup( health_check_expected_status: body.health_check_expected_status, health_check_interval_sec: body.health_check_interval_sec, health_check_timeout_ms: body.health_check_timeout_ms, + health_check_verify_tls: body.health_check_verify_tls, }, ); if (!domain && group.enabled) { diff --git a/apps/api/test/health-check.test.ts b/apps/api/test/health-check.test.ts index 891760e..ec5763e 100644 --- a/apps/api/test/health-check.test.ts +++ b/apps/api/test/health-check.test.ts @@ -55,6 +55,7 @@ describe("health-check probeTarget", () => { path: null, expected_status: null, timeout_ms: 1000, + verify_tls: false, }; const result = await healthCheckService.probeTarget(target); expect(result.ok).toBe(true); @@ -73,6 +74,7 @@ describe("health-check probeTarget", () => { path: null, expected_status: null, timeout_ms: 500, + verify_tls: false, }; const result = await healthCheckService.probeTarget(target); expect(result.ok).toBe(false); @@ -104,6 +106,7 @@ describe("health-check probeTarget", () => { path: "/", expected_status: 200, timeout_ms: 1000, + verify_tls: false, }; const bindingTarget: HealthCheckTarget = { ...groupTarget, @@ -138,6 +141,7 @@ describe("health-check probeTarget", () => { path: null, expected_status: null, timeout_ms: 3000, + verify_tls: false, }; const binding: HealthCheckTarget = { ...group, @@ -204,4 +208,27 @@ describe("health-check state derivation via runAllChecks", () => { ); expect(status?.status).toBe("down"); }); + + it("listHealthCheckTargets includes verify_tls from binding config", async () => { + const { createMemoryDb, repos, runMigrations } = await import("@cfdm/db"); + const { db, sqlite } = createMemoryDb(); + runMigrations(sqlite); + + const domain = repos.createDomain(db, null, "example.com", "zone-id"); + const service = repos.createService(db, "Svc", "svc"); + const binding = repos.insertBinding(db, domain.id, service.id, "@", null); + repos.updateBindingLbConfig(db, binding.id, { + health_check_enabled: true, + health_check_type: "http", + health_check_port: 443, + health_check_verify_tls: true, + }); + repos.replaceBindingIpsWithMeta(db, binding.id, [ + { ip: "10.0.0.1", weight: 1, priority: 1 }, + ]); + + const targets = repos.listHealthCheckTargets(db); + expect(targets).toHaveLength(1); + expect(targets[0]?.verify_tls).toBe(true); + }); }); diff --git a/apps/web/src/components/blocks/app-shell-12/components/app-shell.tsx b/apps/web/src/components/blocks/app-shell-12/components/app-shell.tsx deleted file mode 100644 index 67a2151..0000000 --- a/apps/web/src/components/blocks/app-shell-12/components/app-shell.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { type CSSProperties } from "react" - -import { cn } from "@cfdm/ui/lib/utils" -import { SidebarInset, SidebarProvider } from "@cfdm/ui/components/sidebar" - -import { AppSidebar } from "./app-sidebar" -import { PageToolbar } from "./page-toolbar" -import { SiteFooter } from "./site-footer" -import { SiteHeader } from "./site-header" - -export function AppShell() { - return ( - - {/* Sidebar */} - - - {/* Header */} - - {/* Content */} -
- -
-
-
-
-
-
-
- {/* Footer */} - -
-
- ) -} \ No newline at end of file diff --git a/apps/web/src/components/blocks/app-shell-12/components/app-sidebar.tsx b/apps/web/src/components/blocks/app-shell-12/components/app-sidebar.tsx deleted file mode 100644 index a9a5f97..0000000 --- a/apps/web/src/components/blocks/app-shell-12/components/app-sidebar.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { cn } from "@cfdm/ui/lib/utils" -import { Separator } from "@cfdm/ui/components/separator" -import { - SidebarContent, - SidebarFooter, - SidebarHeader, - Sidebar as SidebarRoot, - useSidebar, -} from "@cfdm/ui/components/sidebar" - -import { Brand } from "./brand" -import { NavMain } from "./nav-main" -import { NavProjects } from "./nav-projects" -import { NavSecondary } from "./nav-secondary" - -function SidebarRailToggle() { - const { state, toggleSidebar } = useSidebar() - const isExpanded = state === "expanded" - - return ( - - ) -} - -export function AppSidebar() { - return ( - - - - - - - - - - - -
- -
- -
- - -
- ) -} \ No newline at end of file diff --git a/apps/web/src/components/blocks/app-shell-12/components/apps-menu.tsx b/apps/web/src/components/blocks/app-shell-12/components/apps-menu.tsx deleted file mode 100644 index c9b3211..0000000 --- a/apps/web/src/components/blocks/app-shell-12/components/apps-menu.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Button } from "@cfdm/ui/components/button" -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@cfdm/ui/components/dropdown-menu" -import { APPS } from "./data" -import { LayoutGridIcon } from "lucide-react" - -export function AppsMenu() { - return ( - - } - > - - - - - Apps -
- {APPS.map((app) => ( - } - className="h-auto flex-col gap-1.5 py-3 text-center [&_svg]:size-5" - > - {app.icon} - {app.label} - - ))} -
- - } - className="justify-center text-sm font-medium" - > - Browse All Apps - -
-
-
- ) -} \ No newline at end of file diff --git a/apps/web/src/components/blocks/app-shell-12/components/brand.tsx b/apps/web/src/components/blocks/app-shell-12/components/brand.tsx deleted file mode 100644 index ef03007..0000000 --- a/apps/web/src/components/blocks/app-shell-12/components/brand.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { cn } from "@cfdm/ui/lib/utils" -import { Item, ItemMedia } from "@cfdm/ui/components/item" -import { - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, -} from "@cfdm/ui/components/sidebar" - -import { BRAND } from "./data" - -function AuthLogo({ className }: { className?: string }) { - return ( - - ) -} - -function BrandLogo() { - return ( - - - - ) -} - -export function Brand() { - return ( - - {/* Sidebar */} - - } - className="gap-2.5" - > - -
- {BRAND.name} - - {BRAND.tier} plan - -
-
-
-
- ) -} \ No newline at end of file diff --git a/apps/web/src/components/blocks/app-shell-12/components/data.tsx b/apps/web/src/components/blocks/app-shell-12/components/data.tsx deleted file mode 100644 index 5d1f521..0000000 --- a/apps/web/src/components/blocks/app-shell-12/components/data.tsx +++ /dev/null @@ -1,604 +0,0 @@ -import { type ReactNode } from "react" -import { SettingsIcon, UsersIcon, BookOpenIcon, HouseIcon, BarChart3Icon, GlobeIcon, ExternalLinkIcon, UserPlusIcon, FlagIcon, CopyIcon, ArchiveIcon, InboxIcon, CalendarIcon, FileTextIcon, ListChecksIcon } from "lucide-react" - -// ── Types ── - -export type NavChild = { - id: string - label: string - isActive?: boolean - disabled?: boolean -} - -export type NavItem = { - id: string - label: string - icon: ReactNode - badge?: string | number - isActive?: boolean - disabled?: boolean - children?: NavChild[] -} - -export type NavGroup = { - id: string - label?: string - items: NavItem[] -} - -export type SecondaryItem = { - id: string - label: string - icon: ReactNode -} - -export type Workspace = { - id: string - name: string - tier: string - description: string -} - -export type Project = { - id: string - name: string - progress: number - color: string -} - -export type ItemAction = { - id: string - label: string - icon: ReactNode - destructive: boolean -} - -export type AppShortcut = { - id: string - label: string - icon: ReactNode -} - -export type NotificationType = - | "mention" - | "comment" - | "share" - | "invite" - | "billing" - | "security" - | "feature" - | "deployment" - | "usage" - | "system" - | "task" - | "approval" - | "integration" - | "achievement" - | "feedback" - | "team_join" - | "reaction" - | "review" - | "event" - -export type NotificationVariant = "info" | "success" | "warning" | "destructive" - -export type NotificationAction = { - label: string - variant?: "default" | "outline" | "destructive" -} - -export type NotificationAttachment = { - name: string - size: string -} - -export type NotificationAvatar = { - src: string - fallback: string -} - -export type NotificationGroupMember = { - src: string - fallback: string - online?: boolean -} - -export type NotificationMeta = { - label: string - value: string - color?: string -} - -export type Notification = { - id: string - type: NotificationType - variant?: NotificationVariant - title: string - body?: string - time: string - unread?: boolean - avatar?: NotificationAvatar - username?: string - link?: string - badge?: string - actions?: NotificationAction[] - attachment?: NotificationAttachment - meta?: NotificationMeta - progress?: number - progressVariant?: "default" | "success" - avatarGroup?: NotificationGroupMember[] - avatarGroupCount?: number - rating?: number - eventDate?: string - eventTime?: string -} - -export type FooterLink = { id: string; label: string } - -// ── Brand + account ── - -export const BRAND = { - name: "ReUI", - tier: "Pro", -} as const - -export const USER = { - name: "Theo Park", - email: "theo@reui.io", - image: - "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=96&h=96&dpr=2&q=80", - initials: "TP", -} as const - -export const WORKSPACES: Workspace[] = [ - { - id: "reui", - name: "ReUI Labs", - tier: "Enterprise", - description: "Design systems and block releases", - }, - { - id: "studio", - name: "ReUI Studio", - tier: "Pro", - description: "Customer workspace builds", - }, - { - id: "ops", - name: "ReUI Ops", - tier: "Team", - description: "Billing, support, and reliability", - }, -] - -// ── Nav secondary ── - -export const NAV_SECONDARY: SecondaryItem[] = [ - { - id: "settings", - label: "Settings", - icon: ( -