From 7d85fef60218f670716ddb0b23fc17d439cbfaf6 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sun, 5 Apr 2026 21:50:46 +0700 Subject: [PATCH] chore: update package dependencies and enhance AppShell component with new navigation items and tooltip support. Refactor API client for improved error handling and response parsing. Expand type definitions for modules, entries, and communities, and enhance UI components with better structure and accessibility features. --- web/components.json | 16 + web/package-lock.json | 5 +- web/package.json | 4 +- web/src/lib/AppShell.svelte | 140 ++- web/src/lib/api/client.ts | 72 +- web/src/lib/api/types.ts | 206 +++- .../alert-dialog/alert-dialog-action.svelte | 27 + .../alert-dialog/alert-dialog-cancel.svelte | 27 + .../alert-dialog/alert-dialog-content.svelte | 32 + .../alert-dialog-description.svelte | 17 + .../alert-dialog/alert-dialog-footer.svelte | 23 + .../alert-dialog/alert-dialog-header.svelte | 20 + .../ui/alert-dialog/alert-dialog-media.svelte | 20 + .../alert-dialog/alert-dialog-overlay.svelte | 17 + .../alert-dialog/alert-dialog-portal.svelte | 7 + .../ui/alert-dialog/alert-dialog-title.svelte | 17 + .../alert-dialog/alert-dialog-trigger.svelte | 7 + .../ui/alert-dialog/alert-dialog.svelte | 7 + .../lib/components/ui/alert-dialog/index.ts | 40 + .../components/ui/alert/alert-action.svelte | 20 + .../ui/alert/alert-description.svelte | 23 + .../components/ui/alert/alert-title.svelte | 23 + web/src/lib/components/ui/alert/alert.svelte | 43 + web/src/lib/components/ui/alert/index.ts | 17 + web/src/lib/components/ui/badge/badge.svelte | 47 +- web/src/lib/components/ui/badge/index.ts | 4 +- .../lib/components/ui/button/button.svelte | 98 +- web/src/lib/components/ui/button/index.ts | 13 +- .../lib/components/ui/card/card-action.svelte | 23 + .../components/ui/card/card-content.svelte | 18 +- .../ui/card/card-description.svelte | 18 +- .../lib/components/ui/card/card-footer.svelte | 20 + .../lib/components/ui/card/card-header.svelte | 21 +- .../lib/components/ui/card/card-title.svelte | 18 +- web/src/lib/components/ui/card/card.svelte | 17 +- web/src/lib/components/ui/card/index.ts | 25 +- .../components/ui/dialog/dialog-close.svelte | 11 + .../ui/dialog/dialog-content.svelte | 48 + .../ui/dialog/dialog-description.svelte | 17 + .../components/ui/dialog/dialog-footer.svelte | 32 + .../components/ui/dialog/dialog-header.svelte | 20 + .../ui/dialog/dialog-overlay.svelte | 17 + .../components/ui/dialog/dialog-portal.svelte | 7 + .../components/ui/dialog/dialog-title.svelte | 17 + .../ui/dialog/dialog-trigger.svelte | 11 + .../lib/components/ui/dialog/dialog.svelte | 7 + web/src/lib/components/ui/dialog/index.ts | 34 + .../dropdown-menu-checkbox-group.svelte | 16 + .../dropdown-menu-checkbox-item.svelte | 44 + .../dropdown-menu-content.svelte | 31 + .../dropdown-menu-group-heading.svelte | 22 + .../dropdown-menu/dropdown-menu-group.svelte | 7 + .../dropdown-menu/dropdown-menu-item.svelte | 27 + .../dropdown-menu/dropdown-menu-label.svelte | 24 + .../dropdown-menu/dropdown-menu-portal.svelte | 7 + .../dropdown-menu-radio-group.svelte | 16 + .../dropdown-menu-radio-item.svelte | 34 + .../dropdown-menu-separator.svelte | 17 + .../dropdown-menu-shortcut.svelte | 20 + .../dropdown-menu-sub-content.svelte | 17 + .../dropdown-menu-sub-trigger.svelte | 29 + .../ui/dropdown-menu/dropdown-menu-sub.svelte | 7 + .../dropdown-menu-trigger.svelte | 7 + .../ui/dropdown-menu/dropdown-menu.svelte | 7 + .../lib/components/ui/dropdown-menu/index.ts | 54 ++ web/src/lib/components/ui/input/index.ts | 9 +- web/src/lib/components/ui/input/input.svelte | 55 +- web/src/lib/components/ui/label/index.ts | 9 +- web/src/lib/components/ui/label/label.svelte | 23 +- web/src/lib/components/ui/popover/index.ts | 28 + .../ui/popover/popover-close.svelte | 7 + .../ui/popover/popover-content.svelte | 31 + .../ui/popover/popover-description.svelte | 20 + .../ui/popover/popover-header.svelte | 20 + .../ui/popover/popover-portal.svelte | 7 + .../ui/popover/popover-title.svelte | 20 + .../ui/popover/popover-trigger.svelte | 17 + .../lib/components/ui/popover/popover.svelte | 7 + .../lib/components/ui/scroll-area/index.ts | 12 +- .../scroll-area/scroll-area-scrollbar.svelte | 30 + .../ui/scroll-area/scroll-area.svelte | 41 +- web/src/lib/components/ui/select/index.ts | 37 + .../ui/select/select-content.svelte | 45 + .../ui/select/select-group-heading.svelte | 21 + .../components/ui/select/select-group.svelte | 17 + .../components/ui/select/select-item.svelte | 38 + .../components/ui/select/select-label.svelte | 20 + .../components/ui/select/select-portal.svelte | 7 + .../select/select-scroll-down-button.svelte | 20 + .../ui/select/select-scroll-up-button.svelte | 20 + .../ui/select/select-separator.svelte | 18 + .../ui/select/select-trigger.svelte | 29 + .../lib/components/ui/select/select.svelte | 11 + web/src/lib/components/ui/separator/index.ts | 9 +- .../components/ui/separator/separator.svelte | 25 +- web/src/lib/components/ui/switch/index.ts | 7 + .../lib/components/ui/switch/switch.svelte | 31 + web/src/lib/components/ui/table/index.ts | 30 +- .../lib/components/ui/table/table-body.svelte | 13 +- .../components/ui/table/table-caption.svelte | 20 + .../lib/components/ui/table/table-cell.svelte | 24 +- .../components/ui/table/table-footer.svelte | 20 + .../lib/components/ui/table/table-head.svelte | 19 +- .../components/ui/table/table-header.svelte | 18 +- .../lib/components/ui/table/table-row.svelte | 16 +- web/src/lib/components/ui/table/table.svelte | 15 +- web/src/lib/components/ui/tabs/index.ts | 18 + .../components/ui/tabs/tabs-content.svelte | 17 + .../lib/components/ui/tabs/tabs-list.svelte | 40 + .../components/ui/tabs/tabs-trigger.svelte | 23 + web/src/lib/components/ui/tabs/tabs.svelte | 19 + web/src/lib/components/ui/textarea/index.ts | 7 + .../components/ui/textarea/textarea.svelte | 23 + web/src/lib/components/ui/tooltip/index.ts | 19 + .../ui/tooltip/tooltip-content.svelte | 52 + .../ui/tooltip/tooltip-portal.svelte | 7 + .../ui/tooltip/tooltip-provider.svelte | 7 + .../ui/tooltip/tooltip-trigger.svelte | 7 + .../lib/components/ui/tooltip/tooltip.svelte | 10 + web/src/routes/+page.svelte | 176 ++-- web/src/routes/directories/+page.svelte | 372 +++++++ web/src/routes/modules/+page.svelte | 245 +++-- .../routes/modules/[moduleId]/+page.svelte | 909 ++++++++++++++++++ web/src/routes/modules/[moduleId]/+page.ts | 1 + web/src/routes/monitoring/+page.svelte | 158 ++- web/src/routes/network/+page.svelte | 372 +++++++ web/src/routes/operations/+page.svelte | 528 ++++++++++ web/src/routes/peers/+page.svelte | 119 +-- web/src/routes/revisions/+page.svelte | 81 +- web/src/routes/schedule/+page.svelte | 198 ++-- web/src/routes/settings/+page.svelte | 98 +- 131 files changed, 5319 insertions(+), 812 deletions(-) create mode 100644 web/components.json create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-media.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/alert-dialog.svelte create mode 100644 web/src/lib/components/ui/alert-dialog/index.ts create mode 100644 web/src/lib/components/ui/alert/alert-action.svelte create mode 100644 web/src/lib/components/ui/alert/alert-description.svelte create mode 100644 web/src/lib/components/ui/alert/alert-title.svelte create mode 100644 web/src/lib/components/ui/alert/alert.svelte create mode 100644 web/src/lib/components/ui/alert/index.ts create mode 100644 web/src/lib/components/ui/card/card-action.svelte create mode 100644 web/src/lib/components/ui/card/card-footer.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-close.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-content.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-description.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-footer.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-header.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-overlay.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-portal.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-title.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog-trigger.svelte create mode 100644 web/src/lib/components/ui/dialog/dialog.svelte create mode 100644 web/src/lib/components/ui/dialog/index.ts create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte create mode 100644 web/src/lib/components/ui/dropdown-menu/index.ts create mode 100644 web/src/lib/components/ui/popover/index.ts create mode 100644 web/src/lib/components/ui/popover/popover-close.svelte create mode 100644 web/src/lib/components/ui/popover/popover-content.svelte create mode 100644 web/src/lib/components/ui/popover/popover-description.svelte create mode 100644 web/src/lib/components/ui/popover/popover-header.svelte create mode 100644 web/src/lib/components/ui/popover/popover-portal.svelte create mode 100644 web/src/lib/components/ui/popover/popover-title.svelte create mode 100644 web/src/lib/components/ui/popover/popover-trigger.svelte create mode 100644 web/src/lib/components/ui/popover/popover.svelte create mode 100644 web/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte create mode 100644 web/src/lib/components/ui/select/index.ts create mode 100644 web/src/lib/components/ui/select/select-content.svelte create mode 100644 web/src/lib/components/ui/select/select-group-heading.svelte create mode 100644 web/src/lib/components/ui/select/select-group.svelte create mode 100644 web/src/lib/components/ui/select/select-item.svelte create mode 100644 web/src/lib/components/ui/select/select-label.svelte create mode 100644 web/src/lib/components/ui/select/select-portal.svelte create mode 100644 web/src/lib/components/ui/select/select-scroll-down-button.svelte create mode 100644 web/src/lib/components/ui/select/select-scroll-up-button.svelte create mode 100644 web/src/lib/components/ui/select/select-separator.svelte create mode 100644 web/src/lib/components/ui/select/select-trigger.svelte create mode 100644 web/src/lib/components/ui/select/select.svelte create mode 100644 web/src/lib/components/ui/switch/index.ts create mode 100644 web/src/lib/components/ui/switch/switch.svelte create mode 100644 web/src/lib/components/ui/table/table-caption.svelte create mode 100644 web/src/lib/components/ui/table/table-footer.svelte create mode 100644 web/src/lib/components/ui/tabs/index.ts create mode 100644 web/src/lib/components/ui/tabs/tabs-content.svelte create mode 100644 web/src/lib/components/ui/tabs/tabs-list.svelte create mode 100644 web/src/lib/components/ui/tabs/tabs-trigger.svelte create mode 100644 web/src/lib/components/ui/tabs/tabs.svelte create mode 100644 web/src/lib/components/ui/textarea/index.ts create mode 100644 web/src/lib/components/ui/textarea/textarea.svelte create mode 100644 web/src/lib/components/ui/tooltip/index.ts create mode 100644 web/src/lib/components/ui/tooltip/tooltip-content.svelte create mode 100644 web/src/lib/components/ui/tooltip/tooltip-portal.svelte create mode 100644 web/src/lib/components/ui/tooltip/tooltip-provider.svelte create mode 100644 web/src/lib/components/ui/tooltip/tooltip-trigger.svelte create mode 100644 web/src/lib/components/ui/tooltip/tooltip.svelte create mode 100644 web/src/routes/directories/+page.svelte create mode 100644 web/src/routes/modules/[moduleId]/+page.svelte create mode 100644 web/src/routes/modules/[moduleId]/+page.ts create mode 100644 web/src/routes/network/+page.svelte create mode 100644 web/src/routes/operations/+page.svelte diff --git a/web/components.json b/web/components.json new file mode 100644 index 0000000..d5f55d3 --- /dev/null +++ b/web/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://www.shadcn-svelte.com/schema.json", + "tailwind": { + "css": "src/routes/layout.css", + "baseColor": "neutral" + }, + "aliases": { + "components": "$lib/components", + "utils": "$lib/utils", + "ui": "$lib/components/ui", + "hooks": "$lib/hooks", + "lib": "$lib" + }, + "typescript": true, + "iconLibrary": "lucide" +} diff --git a/web/package-lock.json b/web/package-lock.json index 9dc33c8..5df0e35 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,8 +8,6 @@ "name": "web", "version": "0.0.1", "dependencies": { - "@internationalized/date": "^3.8.1", - "@lucide/svelte": "^1.7.0", "bits-ui": "^2.17.2", "clsx": "^2.1.1", "svelte-sonner": "^1.1.0", @@ -18,6 +16,8 @@ "tw-animate-css": "^1.4.0" }, "devDependencies": { + "@internationalized/date": "^3.12.0", + "@lucide/svelte": "^1.7.0", "@sveltejs/adapter-static": "^3.0.10", "@sveltejs/kit": "^2.50.2", "@sveltejs/vite-plugin-svelte": "^6.2.4", @@ -531,6 +531,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.7.0.tgz", "integrity": "sha512-YytBKOUBGox7yWcykZnYxOkn5WpR5G1qYXLYXV/j1B79SOTTEKzB+s5yF5Rq9l9OkweDStNH2b4yTqfvhEhV8g==", + "dev": true, "license": "ISC", "peerDependencies": { "svelte": "^5" diff --git a/web/package.json b/web/package.json index 5be9334..54a1a67 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,8 @@ "format": "prettier --write ." }, "devDependencies": { + "@internationalized/date": "^3.12.0", + "@lucide/svelte": "^1.7.0", "@sveltejs/adapter-static": "^3.0.10", "@sveltejs/kit": "^2.50.2", "@sveltejs/vite-plugin-svelte": "^6.2.4", @@ -28,8 +30,6 @@ "vite": "^7.3.1" }, "dependencies": { - "@internationalized/date": "^3.8.1", - "@lucide/svelte": "^1.7.0", "bits-ui": "^2.17.2", "clsx": "^2.1.1", "svelte-sonner": "^1.1.0", diff --git a/web/src/lib/AppShell.svelte b/web/src/lib/AppShell.svelte index 49f0c39..9115c8f 100644 --- a/web/src/lib/AppShell.svelte +++ b/web/src/lib/AppShell.svelte @@ -1,60 +1,158 @@ +
+
{@render children?.()}
+
diff --git a/web/src/lib/api/client.ts b/web/src/lib/api/client.ts index f53f4b6..961192d 100644 --- a/web/src/lib/api/client.ts +++ b/web/src/lib/api/client.ts @@ -3,44 +3,84 @@ import { browser } from '$app/environment'; export const TOKEN_STORAGE_KEY = 'evobgp_api_token'; export type Problem = { + type?: string; title?: string; status?: number; detail?: string; }; -function mergeHeaders(init?: RequestInit): Headers { +function getToken(): string | null { + if (!browser) return null; + return localStorage.getItem(TOKEN_STORAGE_KEY); +} + +function mergeHeaders(init?: RequestInit, extraHeaders?: Record): Headers { const h = new Headers(init?.headers); - if (!h.has('Accept')) { - h.set('Accept', 'application/json'); - } - if (browser) { - const t = localStorage.getItem(TOKEN_STORAGE_KEY); - if (t && !h.has('Authorization')) { - h.set('Authorization', `Bearer ${t}`); + if (!h.has('Accept')) h.set('Accept', 'application/json'); + const t = getToken(); + if (t && !h.has('Authorization')) h.set('Authorization', `Bearer ${t}`); + if (extraHeaders) { + for (const [k, v] of Object.entries(extraHeaders)) { + if (!h.has(k)) h.set(k, v); } } return h; } -export async function apiFetch(path: string, init?: RequestInit): Promise { - if (!browser) { - throw new Error('API is only available in the browser'); +export class ApiError extends Error { + constructor( + public readonly status: number, + message: string, + public readonly problem?: Problem + ) { + super(message); } +} + +export async function apiFetch(path: string, init?: RequestInit): Promise { + if (!browser) throw new Error('API is only available in the browser'); return fetch(path, { ...init, headers: mergeHeaders(init) }); } +/** GET / DELETE без тела */ export async function apiJSON(path: string, init?: RequestInit): Promise { const res = await apiFetch(path, init); + return parseResponse(res); +} + +/** POST / PATCH / PUT с JSON-телом и автоматическим Idempotency-Key */ +export async function apiMutate( + path: string, + method: 'POST' | 'PATCH' | 'PUT' | 'DELETE', + body?: unknown, + opts?: { idempotent?: boolean } +): Promise { + const headers: Record = {}; + if (body !== undefined) headers['Content-Type'] = 'application/json'; + if (opts?.idempotent !== false) { + headers['Idempotency-Key'] = crypto.randomUUID(); + } + const res = await fetch(path, { + method, + headers: mergeHeaders({ headers }, headers), + body: body !== undefined ? JSON.stringify(body) : undefined + }); + return parseResponse(res); +} + +async function parseResponse(res: Response): Promise { + if (res.status === 204 || res.status === 205) return undefined as T; const text = await res.text(); if (!res.ok) { - let detail = text; + let problem: Problem | undefined; + let detail = `HTTP ${res.status}`; try { - const j = JSON.parse(text) as Problem; - if (j?.detail) detail = j.detail; + problem = JSON.parse(text) as Problem; + detail = problem.detail ?? problem.title ?? detail; } catch { - /* plain text */ + if (text) detail = text; } - throw new Error(detail || `HTTP ${res.status}`); + throw new ApiError(res.status, detail, problem); } if (!text) return undefined as T; return JSON.parse(text) as T; diff --git a/web/src/lib/api/types.ts b/web/src/lib/api/types.ts index 555f829..eb91cf8 100644 --- a/web/src/lib/api/types.ts +++ b/web/src/lib/api/types.ts @@ -1,21 +1,152 @@ -export type ModuleRow = { - id: string; - type: string; - name: string; - enabled: boolean; - priority: number; - refresh_interval_sec: number; - cron_expr: string; - default_community_id: string | null; - doh_profile_id: string | null; -}; - -export type ModulesResponse = { - items: ModuleRow[]; +// ---- Pagination ---- +export type Page = { + items: T[]; next_cursor: string | null; has_more: boolean; }; +// ---- Modules ---- +export type ModuleType = 'AS_PREFIXES' | 'CDN_CIDRS' | 'DOMAINS' | 'IP_RANGES'; + +export type ModuleRow = { + id: string; + type: ModuleType; + name: string; + enabled: boolean; + priority: number; + refresh_interval_sec: number | null; + cron_expr: string | null; + default_community_id: string | null; + doh_profile_id: string | null; +}; +export type ModulesResponse = Page; + +export type ModuleCreate = { + type: ModuleType; + name: string; + enabled?: boolean; + priority?: number; + doh_profile_id?: string | null; + refresh_interval_sec?: number | null; + cron_expr?: string | null; + default_community_id?: string | null; +}; +export type ModulePatch = Partial>; + +// ---- AS Entries ---- +export type AsEntry = { + id: string; + asn: number | null; + prefix: string | null; + community_id: string | null; +}; +export type AsEntryCreate = { + asn?: number; + prefix?: string; + community_id?: string | null; +}; +export type AsEntriesResponse = Page; + +// ---- CDN Sources ---- +export type CdnSource = { + id: string; + url: string; + source_kind: string; + community_id: string | null; + refresh_interval_sec: number | null; +}; +export type CdnSourceCreate = { + url: string; + source_kind: string; + community_id?: string | null; +}; +export type CdnSourcePatch = Partial & { refresh_interval_sec?: number | null }; +export type CdnSourcesResponse = Page; + +// ---- Domain Entries ---- +export type DomainEntry = { + id: string; + fqdn: string; + community_id: string | null; +}; +export type DomainEntryCreate = { + fqdn: string; + community_id?: string | null; +}; +export type DomainEntriesResponse = Page; + +// ---- IP Range Entries ---- +export type IpRangeEntry = { + id: string; + prefix: string; + community_id: string; +}; +export type IpRangeEntryCreate = { + prefix: string; + community_id: string; +}; +export type IpRangeEntriesResponse = Page; + +// ---- DoH Profiles ---- +export type DohProfile = { + id: string; + url: string; + timeout_ms: number | null; + vault_secret_ref: string | null; +}; +export type DohProfileCreate = { + url: string; + timeout_ms?: number | null; + vault_secret_ref?: string | null; +}; +export type DohProfilePatch = Partial; +export type DohProfilesResponse = Page; + +// ---- Communities ---- +export type BgpCommunity = { + id: string; + name: string; + kind: string | null; +}; +export type BgpCommunityCreate = { + name: string; + kind?: string; +}; +export type BgpCommunityPatch = Partial; +export type CommunitiesResponse = Page; + +// ---- Peers ---- +export type PeerRow = { + id: string; + name?: string; + neighbor: string; + remote_asn?: number; + session_state: string; + bgp_speaker_id: string | null; +}; +export type PeersResponse = Page; +export type BgpPeerCreate = { + neighbor: string; + remote_asn: number; + bgp_speaker_id?: string | null; +}; +export type BgpPeerPatch = Partial; + +// ---- Speakers ---- +export type SpeakerRow = { + id: string; + role: string; + endpoint: string; + last_applied_revision_id: string | null; +}; +export type SpeakersResponse = Page; +export type BgpSpeakerCreate = { + endpoint: string; + role?: string; +}; +export type BgpSpeakerPatch = Partial; + +// ---- Revisions ---- export type RevisionRow = { id: string; content_hash: string; @@ -24,40 +155,27 @@ export type RevisionRow = { materialized_prefix_count: number; module_id: string | null; }; +export type RevisionsResponse = Page; -export type RevisionsResponse = { - items: RevisionRow[]; - next_cursor: string | null; - has_more: boolean; +export type RevisionPrefix = { + prefix: string; + community_id?: string | null; }; +export type RevisionPrefixesResponse = Page; -export type PeerRow = { +export type RevisionPreview = { id: string; - name: string; - neighbor: string; - session_state: string; - bgp_speaker_id: string | null; + prefixes?: RevisionPrefix[]; + [key: string]: unknown; }; -export type PeersResponse = { - items: PeerRow[]; - next_cursor: string | null; - has_more: boolean; -}; - -export type SpeakerRow = { - id: string; - role: string; - endpoint: string; - last_applied_revision_id: string | null; -}; - -export type SpeakersResponse = { - items: SpeakerRow[]; - next_cursor: string | null; - has_more: boolean; +export type RevisionDiff = { + added: RevisionPrefix[]; + removed: RevisionPrefix[]; + [key: string]: unknown; }; +// ---- Jobs ---- export type JobRow = { job_id: string; kind: string; @@ -69,9 +187,7 @@ export type JobRow = { error?: string | null; meta?: Record; }; +export type JobsResponse = Page; -export type JobsResponse = { - items: JobRow[]; - next_cursor: string | null; - has_more: boolean; -}; +// ---- Settings ---- +export type AppSettings = Record; diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte new file mode 100644 index 0000000..7e63004 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte @@ -0,0 +1,27 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte new file mode 100644 index 0000000..a4ce03c --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte @@ -0,0 +1,27 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte new file mode 100644 index 0000000..c9b3eb3 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte @@ -0,0 +1,32 @@ + + + + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte new file mode 100644 index 0000000..5024f3f --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte new file mode 100644 index 0000000..f4214db --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte new file mode 100644 index 0000000..d6df4d3 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-media.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-media.svelte new file mode 100644 index 0000000..3f634f3 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-media.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte new file mode 100644 index 0000000..9ffcc85 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte new file mode 100644 index 0000000..f0a19a8 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte new file mode 100644 index 0000000..652da33 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte new file mode 100644 index 0000000..b22d1d5 --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog.svelte b/web/src/lib/components/ui/alert-dialog/alert-dialog.svelte new file mode 100644 index 0000000..7ea78bb --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/alert-dialog.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/alert-dialog/index.ts b/web/src/lib/components/ui/alert-dialog/index.ts new file mode 100644 index 0000000..ca81c2a --- /dev/null +++ b/web/src/lib/components/ui/alert-dialog/index.ts @@ -0,0 +1,40 @@ +import Root from "./alert-dialog.svelte"; +import Portal from "./alert-dialog-portal.svelte"; +import Trigger from "./alert-dialog-trigger.svelte"; +import Title from "./alert-dialog-title.svelte"; +import Action from "./alert-dialog-action.svelte"; +import Cancel from "./alert-dialog-cancel.svelte"; +import Footer from "./alert-dialog-footer.svelte"; +import Header from "./alert-dialog-header.svelte"; +import Overlay from "./alert-dialog-overlay.svelte"; +import Content from "./alert-dialog-content.svelte"; +import Description from "./alert-dialog-description.svelte"; +import Media from "./alert-dialog-media.svelte"; + +export { + Root, + Title, + Action, + Cancel, + Portal, + Footer, + Header, + Trigger, + Overlay, + Content, + Description, + Media, + // + Root as AlertDialog, + Title as AlertDialogTitle, + Action as AlertDialogAction, + Cancel as AlertDialogCancel, + Portal as AlertDialogPortal, + Footer as AlertDialogFooter, + Header as AlertDialogHeader, + Trigger as AlertDialogTrigger, + Overlay as AlertDialogOverlay, + Content as AlertDialogContent, + Description as AlertDialogDescription, + Media as AlertDialogMedia, +}; diff --git a/web/src/lib/components/ui/alert/alert-action.svelte b/web/src/lib/components/ui/alert/alert-action.svelte new file mode 100644 index 0000000..1877d38 --- /dev/null +++ b/web/src/lib/components/ui/alert/alert-action.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/alert/alert-description.svelte b/web/src/lib/components/ui/alert/alert-description.svelte new file mode 100644 index 0000000..7ee6039 --- /dev/null +++ b/web/src/lib/components/ui/alert/alert-description.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/alert/alert-title.svelte b/web/src/lib/components/ui/alert/alert-title.svelte new file mode 100644 index 0000000..3e339a3 --- /dev/null +++ b/web/src/lib/components/ui/alert/alert-title.svelte @@ -0,0 +1,23 @@ + + +
svg]/alert:col-start-2 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3", + className + )} + {...restProps} +> + {@render children?.()} +
diff --git a/web/src/lib/components/ui/alert/alert.svelte b/web/src/lib/components/ui/alert/alert.svelte new file mode 100644 index 0000000..abf7487 --- /dev/null +++ b/web/src/lib/components/ui/alert/alert.svelte @@ -0,0 +1,43 @@ + + + + + diff --git a/web/src/lib/components/ui/alert/index.ts b/web/src/lib/components/ui/alert/index.ts new file mode 100644 index 0000000..071b113 --- /dev/null +++ b/web/src/lib/components/ui/alert/index.ts @@ -0,0 +1,17 @@ +import Root from "./alert.svelte"; +import Description from "./alert-description.svelte"; +import Title from "./alert-title.svelte"; +import Action from "./alert-action.svelte"; +export { alertVariants, type AlertVariant } from "./alert.svelte"; + +export { + Root, + Description, + Title, + Action, + // + Root as Alert, + Description as AlertDescription, + Title as AlertTitle, + Action as AlertAction, +}; diff --git a/web/src/lib/components/ui/badge/badge.svelte b/web/src/lib/components/ui/badge/badge.svelte index cb378f7..51bbc23 100644 --- a/web/src/lib/components/ui/badge/badge.svelte +++ b/web/src/lib/components/ui/badge/badge.svelte @@ -1,38 +1,49 @@ -{@render children?.()} + + {@render children?.()} + diff --git a/web/src/lib/components/ui/badge/index.ts b/web/src/lib/components/ui/badge/index.ts index 5033951..64e0aa9 100644 --- a/web/src/lib/components/ui/badge/index.ts +++ b/web/src/lib/components/ui/badge/index.ts @@ -1,2 +1,2 @@ -import Root, { badgeVariants, type BadgeVariant } from './badge.svelte'; -export { Root, Root as Badge, badgeVariants, type BadgeVariant }; +export { default as Badge } from "./badge.svelte"; +export { badgeVariants, type BadgeVariant } from "./badge.svelte"; diff --git a/web/src/lib/components/ui/button/button.svelte b/web/src/lib/components/ui/button/button.svelte index 9586b4d..89cedcb 100644 --- a/web/src/lib/components/ui/button/button.svelte +++ b/web/src/lib/components/ui/button/button.svelte @@ -1,54 +1,82 @@ - +{#if href} + + {@render children?.()} + +{:else} + +{/if} diff --git a/web/src/lib/components/ui/button/index.ts b/web/src/lib/components/ui/button/index.ts index bbdc224..fb585d7 100644 --- a/web/src/lib/components/ui/button/index.ts +++ b/web/src/lib/components/ui/button/index.ts @@ -1,8 +1,17 @@ -import Root, { buttonVariants, type ButtonSize, type ButtonVariant } from './button.svelte'; +import Root, { + type ButtonProps, + type ButtonSize, + type ButtonVariant, + buttonVariants, +} from "./button.svelte"; + export { Root, + type ButtonProps as Props, + // Root as Button, buttonVariants, + type ButtonProps, type ButtonSize, - type ButtonVariant + type ButtonVariant, }; diff --git a/web/src/lib/components/ui/card/card-action.svelte b/web/src/lib/components/ui/card/card-action.svelte new file mode 100644 index 0000000..7c48844 --- /dev/null +++ b/web/src/lib/components/ui/card/card-action.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/card/card-content.svelte b/web/src/lib/components/ui/card/card-content.svelte index 2dbed82..4f60ee3 100644 --- a/web/src/lib/components/ui/card/card-content.svelte +++ b/web/src/lib/components/ui/card/card-content.svelte @@ -1,12 +1,20 @@ -
{@render children?.()}
+
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/card/card-description.svelte b/web/src/lib/components/ui/card/card-description.svelte index 4527cde..9b20ac7 100644 --- a/web/src/lib/components/ui/card/card-description.svelte +++ b/web/src/lib/components/ui/card/card-description.svelte @@ -1,12 +1,20 @@ -

{@render children?.()}

+

+ {@render children?.()} +

diff --git a/web/src/lib/components/ui/card/card-footer.svelte b/web/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 0000000..1efff6d --- /dev/null +++ b/web/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/card/card-header.svelte b/web/src/lib/components/ui/card/card-header.svelte index 9094f13..7eb69e1 100644 --- a/web/src/lib/components/ui/card/card-header.svelte +++ b/web/src/lib/components/ui/card/card-header.svelte @@ -1,12 +1,23 @@ -
{@render children?.()}
+
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/card/card-title.svelte b/web/src/lib/components/ui/card/card-title.svelte index 0deb47b..1523fc5 100644 --- a/web/src/lib/components/ui/card/card-title.svelte +++ b/web/src/lib/components/ui/card/card-title.svelte @@ -1,14 +1,20 @@ -

+
{@render children?.()} -

+ diff --git a/web/src/lib/components/ui/card/card.svelte b/web/src/lib/components/ui/card/card.svelte index 0429da8..2b4f81a 100644 --- a/web/src/lib/components/ui/card/card.svelte +++ b/web/src/lib/components/ui/card/card.svelte @@ -1,17 +1,22 @@
img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col", className)} + {...restProps} > {@render children?.()}
diff --git a/web/src/lib/components/ui/card/index.ts b/web/src/lib/components/ui/card/index.ts index 318b5bb..4d3fce4 100644 --- a/web/src/lib/components/ui/card/index.ts +++ b/web/src/lib/components/ui/card/index.ts @@ -1,14 +1,25 @@ -import Root from './card.svelte'; -import Header from './card-header.svelte'; -import Title from './card-title.svelte'; -import Description from './card-description.svelte'; -import Content from './card-content.svelte'; +import Root from "./card.svelte"; +import Content from "./card-content.svelte"; +import Description from "./card-description.svelte"; +import Footer from "./card-footer.svelte"; +import Header from "./card-header.svelte"; +import Title from "./card-title.svelte"; +import Action from "./card-action.svelte"; export { Root, + Content, + Description, + Footer, + Header, + Title, + Action, + // Root as Card, + Content as CardContent, + Description as CardDescription, + Footer as CardFooter, Header as CardHeader, Title as CardTitle, - Description as CardDescription, - Content as CardContent + Action as CardAction, }; diff --git a/web/src/lib/components/ui/dialog/dialog-close.svelte b/web/src/lib/components/ui/dialog/dialog-close.svelte new file mode 100644 index 0000000..de68f2f --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-close.svelte @@ -0,0 +1,11 @@ + + + diff --git a/web/src/lib/components/ui/dialog/dialog-content.svelte b/web/src/lib/components/ui/dialog/dialog-content.svelte new file mode 100644 index 0000000..c0551ee --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-content.svelte @@ -0,0 +1,48 @@ + + + + + + {@render children?.()} + {#if showCloseButton} + + {#snippet child({ props })} + + {/snippet} + + {/if} + + diff --git a/web/src/lib/components/ui/dialog/dialog-description.svelte b/web/src/lib/components/ui/dialog/dialog-description.svelte new file mode 100644 index 0000000..0102d91 --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-description.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/dialog/dialog-footer.svelte b/web/src/lib/components/ui/dialog/dialog-footer.svelte new file mode 100644 index 0000000..e23160a --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-footer.svelte @@ -0,0 +1,32 @@ + + +
+ {@render children?.()} + {#if showCloseButton} + + {#snippet child({ props })} + + {/snippet} + + {/if} +
diff --git a/web/src/lib/components/ui/dialog/dialog-header.svelte b/web/src/lib/components/ui/dialog/dialog-header.svelte new file mode 100644 index 0000000..c3ce8a2 --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-header.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/dialog/dialog-overlay.svelte b/web/src/lib/components/ui/dialog/dialog-overlay.svelte new file mode 100644 index 0000000..19f69f0 --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-overlay.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/dialog/dialog-portal.svelte b/web/src/lib/components/ui/dialog/dialog-portal.svelte new file mode 100644 index 0000000..ccfa79c --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/dialog/dialog-title.svelte b/web/src/lib/components/ui/dialog/dialog-title.svelte new file mode 100644 index 0000000..6ff1a4a --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-title.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/dialog/dialog-trigger.svelte b/web/src/lib/components/ui/dialog/dialog-trigger.svelte new file mode 100644 index 0000000..589ee0c --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog-trigger.svelte @@ -0,0 +1,11 @@ + + + diff --git a/web/src/lib/components/ui/dialog/dialog.svelte b/web/src/lib/components/ui/dialog/dialog.svelte new file mode 100644 index 0000000..211672c --- /dev/null +++ b/web/src/lib/components/ui/dialog/dialog.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/dialog/index.ts b/web/src/lib/components/ui/dialog/index.ts new file mode 100644 index 0000000..076cef5 --- /dev/null +++ b/web/src/lib/components/ui/dialog/index.ts @@ -0,0 +1,34 @@ +import Root from "./dialog.svelte"; +import Portal from "./dialog-portal.svelte"; +import Title from "./dialog-title.svelte"; +import Footer from "./dialog-footer.svelte"; +import Header from "./dialog-header.svelte"; +import Overlay from "./dialog-overlay.svelte"; +import Content from "./dialog-content.svelte"; +import Description from "./dialog-description.svelte"; +import Trigger from "./dialog-trigger.svelte"; +import Close from "./dialog-close.svelte"; + +export { + Root, + Title, + Portal, + Footer, + Header, + Trigger, + Overlay, + Content, + Description, + Close, + // + Root as Dialog, + Title as DialogTitle, + Portal as DialogPortal, + Footer as DialogFooter, + Header as DialogHeader, + Trigger as DialogTrigger, + Overlay as DialogOverlay, + Content as DialogContent, + Description as DialogDescription, + Close as DialogClose, +}; diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte new file mode 100644 index 0000000..e0e1971 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte @@ -0,0 +1,16 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte new file mode 100644 index 0000000..a81b48d --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte @@ -0,0 +1,44 @@ + + + + {#snippet children({ checked, indeterminate })} + + {#if indeterminate} + + {:else if checked} + + {/if} + + {@render childrenProp?.()} + {/snippet} + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte new file mode 100644 index 0000000..261a5b0 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte new file mode 100644 index 0000000..433540f --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte @@ -0,0 +1,22 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte new file mode 100644 index 0000000..aca1f7b --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte new file mode 100644 index 0000000..c425190 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte @@ -0,0 +1,27 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte new file mode 100644 index 0000000..e0c534f --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte @@ -0,0 +1,24 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte new file mode 100644 index 0000000..274cfef --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte new file mode 100644 index 0000000..189aef4 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte @@ -0,0 +1,16 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte new file mode 100644 index 0000000..c8aa07b --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte @@ -0,0 +1,34 @@ + + + + {#snippet children({ checked })} + + {#if checked} + + {/if} + + {@render childrenProp?.({ checked })} + {/snippet} + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte new file mode 100644 index 0000000..90f1b6f --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte new file mode 100644 index 0000000..ed7cc85 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte new file mode 100644 index 0000000..b5750d4 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte new file mode 100644 index 0000000..fab0275 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte @@ -0,0 +1,29 @@ + + + + {@render children?.()} + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte new file mode 100644 index 0000000..f044581 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte new file mode 100644 index 0000000..cb05344 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte b/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte new file mode 100644 index 0000000..cb4bc62 --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/dropdown-menu/index.ts b/web/src/lib/components/ui/dropdown-menu/index.ts new file mode 100644 index 0000000..7850c6a --- /dev/null +++ b/web/src/lib/components/ui/dropdown-menu/index.ts @@ -0,0 +1,54 @@ +import Root from "./dropdown-menu.svelte"; +import Sub from "./dropdown-menu-sub.svelte"; +import CheckboxGroup from "./dropdown-menu-checkbox-group.svelte"; +import CheckboxItem from "./dropdown-menu-checkbox-item.svelte"; +import Content from "./dropdown-menu-content.svelte"; +import Group from "./dropdown-menu-group.svelte"; +import Item from "./dropdown-menu-item.svelte"; +import Label from "./dropdown-menu-label.svelte"; +import RadioGroup from "./dropdown-menu-radio-group.svelte"; +import RadioItem from "./dropdown-menu-radio-item.svelte"; +import Separator from "./dropdown-menu-separator.svelte"; +import Shortcut from "./dropdown-menu-shortcut.svelte"; +import Trigger from "./dropdown-menu-trigger.svelte"; +import SubContent from "./dropdown-menu-sub-content.svelte"; +import SubTrigger from "./dropdown-menu-sub-trigger.svelte"; +import GroupHeading from "./dropdown-menu-group-heading.svelte"; +import Portal from "./dropdown-menu-portal.svelte"; + +export { + CheckboxGroup, + CheckboxItem, + Content, + Portal, + Root as DropdownMenu, + CheckboxGroup as DropdownMenuCheckboxGroup, + CheckboxItem as DropdownMenuCheckboxItem, + Content as DropdownMenuContent, + Portal as DropdownMenuPortal, + Group as DropdownMenuGroup, + Item as DropdownMenuItem, + Label as DropdownMenuLabel, + RadioGroup as DropdownMenuRadioGroup, + RadioItem as DropdownMenuRadioItem, + Separator as DropdownMenuSeparator, + Shortcut as DropdownMenuShortcut, + Sub as DropdownMenuSub, + SubContent as DropdownMenuSubContent, + SubTrigger as DropdownMenuSubTrigger, + Trigger as DropdownMenuTrigger, + GroupHeading as DropdownMenuGroupHeading, + Group, + GroupHeading, + Item, + Label, + RadioGroup, + RadioItem, + Root, + Separator, + Shortcut, + Sub, + SubContent, + SubTrigger, + Trigger, +}; diff --git a/web/src/lib/components/ui/input/index.ts b/web/src/lib/components/ui/input/index.ts index f55e99c..f47b6d3 100644 --- a/web/src/lib/components/ui/input/index.ts +++ b/web/src/lib/components/ui/input/index.ts @@ -1,2 +1,7 @@ -import Root from './input.svelte'; -export { Root, Root as Input }; +import Root from "./input.svelte"; + +export { + Root, + // + Root as Input, +}; diff --git a/web/src/lib/components/ui/input/input.svelte b/web/src/lib/components/ui/input/input.svelte index ca430ed..fe7db38 100644 --- a/web/src/lib/components/ui/input/input.svelte +++ b/web/src/lib/components/ui/input/input.svelte @@ -1,19 +1,48 @@ - +{#if type === "file"} + +{:else} + +{/if} diff --git a/web/src/lib/components/ui/label/index.ts b/web/src/lib/components/ui/label/index.ts index 2543553..8bfca0b 100644 --- a/web/src/lib/components/ui/label/index.ts +++ b/web/src/lib/components/ui/label/index.ts @@ -1,2 +1,7 @@ -import Root from './label.svelte'; -export { Root, Root as Label }; +import Root from "./label.svelte"; + +export { + Root, + // + Root as Label, +}; diff --git a/web/src/lib/components/ui/label/label.svelte b/web/src/lib/components/ui/label/label.svelte index 407823c..d5e3086 100644 --- a/web/src/lib/components/ui/label/label.svelte +++ b/web/src/lib/components/ui/label/label.svelte @@ -1,15 +1,20 @@ - + diff --git a/web/src/lib/components/ui/popover/index.ts b/web/src/lib/components/ui/popover/index.ts new file mode 100644 index 0000000..5f18036 --- /dev/null +++ b/web/src/lib/components/ui/popover/index.ts @@ -0,0 +1,28 @@ +import Root from "./popover.svelte"; +import Close from "./popover-close.svelte"; +import Content from "./popover-content.svelte"; +import Description from "./popover-description.svelte"; +import Header from "./popover-header.svelte"; +import Title from "./popover-title.svelte"; +import Trigger from "./popover-trigger.svelte"; +import Portal from "./popover-portal.svelte"; + +export { + Root, + Content, + Description, + Header, + Title, + Trigger, + Close, + Portal, + // + Root as Popover, + Content as PopoverContent, + Description as PopoverDescription, + Header as PopoverHeader, + Title as PopoverTitle, + Trigger as PopoverTrigger, + Close as PopoverClose, + Portal as PopoverPortal, +}; diff --git a/web/src/lib/components/ui/popover/popover-close.svelte b/web/src/lib/components/ui/popover/popover-close.svelte new file mode 100644 index 0000000..c360925 --- /dev/null +++ b/web/src/lib/components/ui/popover/popover-close.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/popover/popover-content.svelte b/web/src/lib/components/ui/popover/popover-content.svelte new file mode 100644 index 0000000..dd9a38f --- /dev/null +++ b/web/src/lib/components/ui/popover/popover-content.svelte @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/lib/components/ui/popover/popover-description.svelte b/web/src/lib/components/ui/popover/popover-description.svelte new file mode 100644 index 0000000..c28ab23 --- /dev/null +++ b/web/src/lib/components/ui/popover/popover-description.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/popover/popover-header.svelte b/web/src/lib/components/ui/popover/popover-header.svelte new file mode 100644 index 0000000..69b85b1 --- /dev/null +++ b/web/src/lib/components/ui/popover/popover-header.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/popover/popover-portal.svelte b/web/src/lib/components/ui/popover/popover-portal.svelte new file mode 100644 index 0000000..dd8265f --- /dev/null +++ b/web/src/lib/components/ui/popover/popover-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/popover/popover-title.svelte b/web/src/lib/components/ui/popover/popover-title.svelte new file mode 100644 index 0000000..ee9f2ff --- /dev/null +++ b/web/src/lib/components/ui/popover/popover-title.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/popover/popover-trigger.svelte b/web/src/lib/components/ui/popover/popover-trigger.svelte new file mode 100644 index 0000000..586323c --- /dev/null +++ b/web/src/lib/components/ui/popover/popover-trigger.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/popover/popover.svelte b/web/src/lib/components/ui/popover/popover.svelte new file mode 100644 index 0000000..6b1aa5f --- /dev/null +++ b/web/src/lib/components/ui/popover/popover.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/scroll-area/index.ts b/web/src/lib/components/ui/scroll-area/index.ts index bec8204..e86a25b 100644 --- a/web/src/lib/components/ui/scroll-area/index.ts +++ b/web/src/lib/components/ui/scroll-area/index.ts @@ -1,2 +1,10 @@ -import Root from './scroll-area.svelte'; -export { Root, Root as ScrollArea }; +import Scrollbar from "./scroll-area-scrollbar.svelte"; +import Root from "./scroll-area.svelte"; + +export { + Root, + Scrollbar, + //, + Root as ScrollArea, + Scrollbar as ScrollAreaScrollbar, +}; diff --git a/web/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte b/web/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte new file mode 100644 index 0000000..b9518f3 --- /dev/null +++ b/web/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte @@ -0,0 +1,30 @@ + + + + {@render children?.()} + + diff --git a/web/src/lib/components/ui/scroll-area/scroll-area.svelte b/web/src/lib/components/ui/scroll-area/scroll-area.svelte index 20825c1..d4d96d0 100644 --- a/web/src/lib/components/ui/scroll-area/scroll-area.svelte +++ b/web/src/lib/components/ui/scroll-area/scroll-area.svelte @@ -1,12 +1,43 @@ -
{@render children?.()}
+ + + {@render children?.()} + + {#if orientation === "vertical" || orientation === "both"} + + {/if} + {#if orientation === "horizontal" || orientation === "both"} + + {/if} + + diff --git a/web/src/lib/components/ui/select/index.ts b/web/src/lib/components/ui/select/index.ts new file mode 100644 index 0000000..4dec358 --- /dev/null +++ b/web/src/lib/components/ui/select/index.ts @@ -0,0 +1,37 @@ +import Root from "./select.svelte"; +import Group from "./select-group.svelte"; +import Label from "./select-label.svelte"; +import Item from "./select-item.svelte"; +import Content from "./select-content.svelte"; +import Trigger from "./select-trigger.svelte"; +import Separator from "./select-separator.svelte"; +import ScrollDownButton from "./select-scroll-down-button.svelte"; +import ScrollUpButton from "./select-scroll-up-button.svelte"; +import GroupHeading from "./select-group-heading.svelte"; +import Portal from "./select-portal.svelte"; + +export { + Root, + Group, + Label, + Item, + Content, + Trigger, + Separator, + ScrollDownButton, + ScrollUpButton, + GroupHeading, + Portal, + // + Root as Select, + Group as SelectGroup, + Label as SelectLabel, + Item as SelectItem, + Content as SelectContent, + Trigger as SelectTrigger, + Separator as SelectSeparator, + ScrollDownButton as SelectScrollDownButton, + ScrollUpButton as SelectScrollUpButton, + GroupHeading as SelectGroupHeading, + Portal as SelectPortal, +}; diff --git a/web/src/lib/components/ui/select/select-content.svelte b/web/src/lib/components/ui/select/select-content.svelte new file mode 100644 index 0000000..bb1e2ac --- /dev/null +++ b/web/src/lib/components/ui/select/select-content.svelte @@ -0,0 +1,45 @@ + + + + + + + {@render children?.()} + + + + diff --git a/web/src/lib/components/ui/select/select-group-heading.svelte b/web/src/lib/components/ui/select/select-group-heading.svelte new file mode 100644 index 0000000..1fab5f0 --- /dev/null +++ b/web/src/lib/components/ui/select/select-group-heading.svelte @@ -0,0 +1,21 @@ + + + + {@render children?.()} + diff --git a/web/src/lib/components/ui/select/select-group.svelte b/web/src/lib/components/ui/select/select-group.svelte new file mode 100644 index 0000000..f666cb2 --- /dev/null +++ b/web/src/lib/components/ui/select/select-group.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/select/select-item.svelte b/web/src/lib/components/ui/select/select-item.svelte new file mode 100644 index 0000000..32fd5ce --- /dev/null +++ b/web/src/lib/components/ui/select/select-item.svelte @@ -0,0 +1,38 @@ + + + + {#snippet children({ selected, highlighted })} + + {#if selected} + + {/if} + + {#if childrenProp} + {@render childrenProp({ selected, highlighted })} + {:else} + {label || value} + {/if} + {/snippet} + diff --git a/web/src/lib/components/ui/select/select-label.svelte b/web/src/lib/components/ui/select/select-label.svelte new file mode 100644 index 0000000..69bcfdf --- /dev/null +++ b/web/src/lib/components/ui/select/select-label.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/web/src/lib/components/ui/select/select-portal.svelte b/web/src/lib/components/ui/select/select-portal.svelte new file mode 100644 index 0000000..424bcdd --- /dev/null +++ b/web/src/lib/components/ui/select/select-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/select/select-scroll-down-button.svelte b/web/src/lib/components/ui/select/select-scroll-down-button.svelte new file mode 100644 index 0000000..94f41cd --- /dev/null +++ b/web/src/lib/components/ui/select/select-scroll-down-button.svelte @@ -0,0 +1,20 @@ + + + + + diff --git a/web/src/lib/components/ui/select/select-scroll-up-button.svelte b/web/src/lib/components/ui/select/select-scroll-up-button.svelte new file mode 100644 index 0000000..035ea09 --- /dev/null +++ b/web/src/lib/components/ui/select/select-scroll-up-button.svelte @@ -0,0 +1,20 @@ + + + + + diff --git a/web/src/lib/components/ui/select/select-separator.svelte b/web/src/lib/components/ui/select/select-separator.svelte new file mode 100644 index 0000000..3b24bab --- /dev/null +++ b/web/src/lib/components/ui/select/select-separator.svelte @@ -0,0 +1,18 @@ + + + diff --git a/web/src/lib/components/ui/select/select-trigger.svelte b/web/src/lib/components/ui/select/select-trigger.svelte new file mode 100644 index 0000000..03d06d0 --- /dev/null +++ b/web/src/lib/components/ui/select/select-trigger.svelte @@ -0,0 +1,29 @@ + + + + {@render children?.()} + + diff --git a/web/src/lib/components/ui/select/select.svelte b/web/src/lib/components/ui/select/select.svelte new file mode 100644 index 0000000..05eb663 --- /dev/null +++ b/web/src/lib/components/ui/select/select.svelte @@ -0,0 +1,11 @@ + + + diff --git a/web/src/lib/components/ui/separator/index.ts b/web/src/lib/components/ui/separator/index.ts index 18cdeac..82442d2 100644 --- a/web/src/lib/components/ui/separator/index.ts +++ b/web/src/lib/components/ui/separator/index.ts @@ -1,2 +1,7 @@ -import Root from './separator.svelte'; -export { Root, Root as Separator }; +import Root from "./separator.svelte"; + +export { + Root, + // + Root as Separator, +}; diff --git a/web/src/lib/components/ui/separator/separator.svelte b/web/src/lib/components/ui/separator/separator.svelte index e42befd..5fd8a42 100644 --- a/web/src/lib/components/ui/separator/separator.svelte +++ b/web/src/lib/components/ui/separator/separator.svelte @@ -1,20 +1,23 @@ - + {...restProps} +/> diff --git a/web/src/lib/components/ui/switch/index.ts b/web/src/lib/components/ui/switch/index.ts new file mode 100644 index 0000000..f5533db --- /dev/null +++ b/web/src/lib/components/ui/switch/index.ts @@ -0,0 +1,7 @@ +import Root from "./switch.svelte"; + +export { + Root, + // + Root as Switch, +}; diff --git a/web/src/lib/components/ui/switch/switch.svelte b/web/src/lib/components/ui/switch/switch.svelte new file mode 100644 index 0000000..6aa57d5 --- /dev/null +++ b/web/src/lib/components/ui/switch/switch.svelte @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/lib/components/ui/table/index.ts b/web/src/lib/components/ui/table/index.ts index d80b74d..14695c8 100644 --- a/web/src/lib/components/ui/table/index.ts +++ b/web/src/lib/components/ui/table/index.ts @@ -1,16 +1,28 @@ -import Root from './table.svelte'; -import Header from './table-header.svelte'; -import Body from './table-body.svelte'; -import Row from './table-row.svelte'; -import Head from './table-head.svelte'; -import Cell from './table-cell.svelte'; +import Root from "./table.svelte"; +import Body from "./table-body.svelte"; +import Caption from "./table-caption.svelte"; +import Cell from "./table-cell.svelte"; +import Footer from "./table-footer.svelte"; +import Head from "./table-head.svelte"; +import Header from "./table-header.svelte"; +import Row from "./table-row.svelte"; export { Root, + Body, + Caption, + Cell, + Footer, + Head, + Header, + Row, + // Root as Table, - Header as TableHeader, Body as TableBody, - Row as TableRow, + Caption as TableCaption, + Cell as TableCell, + Footer as TableFooter, Head as TableHead, - Cell as TableCell + Header as TableHeader, + Row as TableRow, }; diff --git a/web/src/lib/components/ui/table/table-body.svelte b/web/src/lib/components/ui/table/table-body.svelte index 6d8168d..935feae 100644 --- a/web/src/lib/components/ui/table/table-body.svelte +++ b/web/src/lib/components/ui/table/table-body.svelte @@ -1,12 +1,15 @@ -{@render children?.()} + + {@render children?.()} + diff --git a/web/src/lib/components/ui/table/table-caption.svelte b/web/src/lib/components/ui/table/table-caption.svelte new file mode 100644 index 0000000..4696cff --- /dev/null +++ b/web/src/lib/components/ui/table/table-caption.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/web/src/lib/components/ui/table/table-cell.svelte b/web/src/lib/components/ui/table/table-cell.svelte index c6283bd..a998bf6 100644 --- a/web/src/lib/components/ui/table/table-cell.svelte +++ b/web/src/lib/components/ui/table/table-cell.svelte @@ -1,23 +1,15 @@ -[role=checkbox]]:translate-y-[2px]', className)} - {colspan} - {rowspan} - {...rest}>{@render children?.()} + + {@render children?.()} + diff --git a/web/src/lib/components/ui/table/table-footer.svelte b/web/src/lib/components/ui/table/table-footer.svelte new file mode 100644 index 0000000..b9b14eb --- /dev/null +++ b/web/src/lib/components/ui/table/table-footer.svelte @@ -0,0 +1,20 @@ + + +tr]:last:border-b-0", className)} + {...restProps} +> + {@render children?.()} + diff --git a/web/src/lib/components/ui/table/table-head.svelte b/web/src/lib/components/ui/table/table-head.svelte index d9eaec8..267c4e0 100644 --- a/web/src/lib/components/ui/table/table-head.svelte +++ b/web/src/lib/components/ui/table/table-head.svelte @@ -1,18 +1,15 @@ -[role=checkbox]]:translate-y-[2px]', - className - )} - {...rest}>{@render children?.()} + + {@render children?.()} + diff --git a/web/src/lib/components/ui/table/table-header.svelte b/web/src/lib/components/ui/table/table-header.svelte index 0814de1..f47d259 100644 --- a/web/src/lib/components/ui/table/table-header.svelte +++ b/web/src/lib/components/ui/table/table-header.svelte @@ -1,12 +1,20 @@ -{@render children?.()} + + {@render children?.()} + diff --git a/web/src/lib/components/ui/table/table-row.svelte b/web/src/lib/components/ui/table/table-row.svelte index 6dc7c3d..90b4e2a 100644 --- a/web/src/lib/components/ui/table/table-row.svelte +++ b/web/src/lib/components/ui/table/table-row.svelte @@ -1,15 +1,15 @@ -{@render children?.()} + + {@render children?.()} + diff --git a/web/src/lib/components/ui/table/table.svelte b/web/src/lib/components/ui/table/table.svelte index 0d629ca..d95a02e 100644 --- a/web/src/lib/components/ui/table/table.svelte +++ b/web/src/lib/components/ui/table/table.svelte @@ -1,14 +1,17 @@ -
- {@render children?.()}
+
+ + {@render children?.()} +
diff --git a/web/src/lib/components/ui/tabs/index.ts b/web/src/lib/components/ui/tabs/index.ts new file mode 100644 index 0000000..31267e5 --- /dev/null +++ b/web/src/lib/components/ui/tabs/index.ts @@ -0,0 +1,18 @@ +import Root from "./tabs.svelte"; +import Content from "./tabs-content.svelte"; +import List, { tabsListVariants, type TabsListVariant } from "./tabs-list.svelte"; +import Trigger from "./tabs-trigger.svelte"; + +export { + Root, + Content, + List, + Trigger, + tabsListVariants, + type TabsListVariant, + // + Root as Tabs, + Content as TabsContent, + List as TabsList, + Trigger as TabsTrigger, +}; diff --git a/web/src/lib/components/ui/tabs/tabs-content.svelte b/web/src/lib/components/ui/tabs/tabs-content.svelte new file mode 100644 index 0000000..394ab3e --- /dev/null +++ b/web/src/lib/components/ui/tabs/tabs-content.svelte @@ -0,0 +1,17 @@ + + + diff --git a/web/src/lib/components/ui/tabs/tabs-list.svelte b/web/src/lib/components/ui/tabs/tabs-list.svelte new file mode 100644 index 0000000..18dce00 --- /dev/null +++ b/web/src/lib/components/ui/tabs/tabs-list.svelte @@ -0,0 +1,40 @@ + + + + + diff --git a/web/src/lib/components/ui/tabs/tabs-trigger.svelte b/web/src/lib/components/ui/tabs/tabs-trigger.svelte new file mode 100644 index 0000000..8a0be4a --- /dev/null +++ b/web/src/lib/components/ui/tabs/tabs-trigger.svelte @@ -0,0 +1,23 @@ + + + diff --git a/web/src/lib/components/ui/tabs/tabs.svelte b/web/src/lib/components/ui/tabs/tabs.svelte new file mode 100644 index 0000000..bfb900d --- /dev/null +++ b/web/src/lib/components/ui/tabs/tabs.svelte @@ -0,0 +1,19 @@ + + + diff --git a/web/src/lib/components/ui/textarea/index.ts b/web/src/lib/components/ui/textarea/index.ts new file mode 100644 index 0000000..ace797a --- /dev/null +++ b/web/src/lib/components/ui/textarea/index.ts @@ -0,0 +1,7 @@ +import Root from "./textarea.svelte"; + +export { + Root, + // + Root as Textarea, +}; diff --git a/web/src/lib/components/ui/textarea/textarea.svelte b/web/src/lib/components/ui/textarea/textarea.svelte new file mode 100644 index 0000000..2e779ff --- /dev/null +++ b/web/src/lib/components/ui/textarea/textarea.svelte @@ -0,0 +1,23 @@ + + + diff --git a/web/src/lib/components/ui/tooltip/index.ts b/web/src/lib/components/ui/tooltip/index.ts new file mode 100644 index 0000000..1718604 --- /dev/null +++ b/web/src/lib/components/ui/tooltip/index.ts @@ -0,0 +1,19 @@ +import Root from "./tooltip.svelte"; +import Trigger from "./tooltip-trigger.svelte"; +import Content from "./tooltip-content.svelte"; +import Provider from "./tooltip-provider.svelte"; +import Portal from "./tooltip-portal.svelte"; + +export { + Root, + Trigger, + Content, + Provider, + Portal, + // + Root as Tooltip, + Content as TooltipContent, + Trigger as TooltipTrigger, + Provider as TooltipProvider, + Portal as TooltipPortal, +}; diff --git a/web/src/lib/components/ui/tooltip/tooltip-content.svelte b/web/src/lib/components/ui/tooltip/tooltip-content.svelte new file mode 100644 index 0000000..0cf0694 --- /dev/null +++ b/web/src/lib/components/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,52 @@ + + + + + {@render children?.()} + + {#snippet child({ props })} +
+ {/snippet} +
+
+
diff --git a/web/src/lib/components/ui/tooltip/tooltip-portal.svelte b/web/src/lib/components/ui/tooltip/tooltip-portal.svelte new file mode 100644 index 0000000..d234f7d --- /dev/null +++ b/web/src/lib/components/ui/tooltip/tooltip-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/tooltip/tooltip-provider.svelte b/web/src/lib/components/ui/tooltip/tooltip-provider.svelte new file mode 100644 index 0000000..6dba9a6 --- /dev/null +++ b/web/src/lib/components/ui/tooltip/tooltip-provider.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte b/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte new file mode 100644 index 0000000..1acdaa4 --- /dev/null +++ b/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/web/src/lib/components/ui/tooltip/tooltip.svelte b/web/src/lib/components/ui/tooltip/tooltip.svelte new file mode 100644 index 0000000..44bee9f --- /dev/null +++ b/web/src/lib/components/ui/tooltip/tooltip.svelte @@ -0,0 +1,10 @@ + + + + + diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index bc28a43..887395f 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -1,97 +1,121 @@ -
+

Обзор

-

- Краткая сводка по API. Укажите токен в разделе «Настройки», если запросы к защищённым путям - возвращают 401. -

+

Состояние EvoBGP control plane.

-
- - - Health - GET /v1/health - - - {#if health === 'ok'} - ok - {:else if health === 'err'} - недоступно - {:else} - проверка… - {/if} - - + + + + {#if healthy === null} +
+ Проверка… + {:else if healthy} + + API работает + {:else} + + API недоступен + {/if} +
+
- - - Модули - GET /v1/modules - - -

{modulesN}

-
-
- - - - Ревизии - GET /v1/revisions - - -

{revN}

-
-
- - - - Пиры - GET /v1/peers - - -

{peersN}

-
-
+ +
+ {#each stats as stat (stat.label)} + {@const Icon = stat.icon} + + +
+ + + {stat.label} + + +
+ + {loading ? '—' : stat.value} + +
+ +

{stat.description}

+
+
+ {/each}
+ + + + + Быстрые действия + + + + + + + + +
diff --git a/web/src/routes/directories/+page.svelte b/web/src/routes/directories/+page.svelte new file mode 100644 index 0000000..3d0779a --- /dev/null +++ b/web/src/routes/directories/+page.svelte @@ -0,0 +1,372 @@ + + +
+
+

Справочники

+

BGP Communities и DoH-профили для резолвинга доменов.

+
+ + + + Communities + DoH профили + + + + + + +
+ BGP Communities + Используются для тегирования префиксов +
+
+ + +
+
+ + + + + Название + Вид + ID + + + + + {#each communities as c (c.id)} + + {c.name} + + {#if c.kind} + {c.kind} + {:else} + + {/if} + + {c.id} + +
+ + +
+
+
+ {:else} + + + {commLoading ? 'Загрузка…' : 'Нет communities. Создайте первую.'} + + + {/each} +
+
+
+
+
+ + + + + +
+ DoH профили + DNS-over-HTTPS серверы для резолвинга доменных модулей +
+
+ + +
+
+ + + + + URL + Таймаут (мс) + ID + + + + + {#each dohProfiles as d (d.id)} + + {d.url} + {d.timeout_ms ?? '—'} + {d.id} + +
+ + +
+
+
+ {:else} + + + {dohLoading ? 'Загрузка…' : 'Нет DoH профилей.'} + + + {/each} +
+
+
+
+
+
+
+ + + + + + {commEdit ? 'Редактировать' : 'Новая'} community + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + { if (!v) commDeleteTarget = null; }}> + + + Удалить community «{commDeleteTarget?.name}»? + Это приведёт к удалению привязки во всех модулях. + + + (commDeleteTarget = null)}>Отмена + Удалить + + + + + + + + + {dohEdit ? 'Редактировать' : 'Новый'} DoH профиль + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + { if (!v) dohDeleteTarget = null; }}> + + + Удалить DoH профиль? + {dohDeleteTarget?.url} + + + (dohDeleteTarget = null)}>Отмена + Удалить + + + diff --git a/web/src/routes/modules/+page.svelte b/web/src/routes/modules/+page.svelte index 0f5cd5a..2ea48db 100644 --- a/web/src/routes/modules/+page.svelte +++ b/web/src/routes/modules/+page.svelte @@ -1,10 +1,27 @@ -
-
-

Модули префиксов

-

Список экземпляров модулей tenant (из API).

+
+
+
+

Модули префиксов

+

Управление модулями — AS, CDN, домены, IP-диапазоны.

+
+
+ + +
- - Модули - GET /v1/modules - - - {#if err} -

{err}

- {:else} - - - - - Имя - Тип - Приоритет - Статус - - - - {#each rows as m} - - {m.name} - - {m.type} - - {m.priority} - - {#if m.enabled} - вкл - {:else} - выкл - {/if} - - - {:else} - - Нет данных - - {/each} - -
-
- {/if} + + + + + Название + Тип + Приоритет + Интервал + Статус + + + + + {#each rows as m (m.id)} + + {m.name} + + {m.type} + + {m.priority} + + {m.cron_expr ?? (m.refresh_interval_sec ? `${m.refresh_interval_sec}с` : '—')} + + + {#if m.enabled} + вкл + {:else} + выкл + {/if} + + + + + + {:else} + + + {loading ? 'Загрузка…' : 'Нет модулей. Создайте первый.'} + + + {/each} + +
+ + + + + + Новый модуль + Создание нового модуля префиксов. + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + +
+
diff --git a/web/src/routes/modules/[moduleId]/+page.svelte b/web/src/routes/modules/[moduleId]/+page.svelte new file mode 100644 index 0000000..e8a70e1 --- /dev/null +++ b/web/src/routes/modules/[moduleId]/+page.svelte @@ -0,0 +1,909 @@ + + +{#if loadingMod} +
Загрузка…
+{:else if mod} +
+ +
+
+ +
+
+

{mod.name}

+ {mod.type} + {#if mod.enabled} + вкл + {:else} + выкл + {/if} +
+

{mod.id}

+
+
+
+ + + +
+
+ + +
+ +

Приоритет

+

{mod.priority}

+
+ +

Интервал

+

+ {mod.cron_expr ?? (mod.refresh_interval_sec ? `${mod.refresh_interval_sec}с` : '—')} +

+
+ +

DoH профиль

+

{mod.doh_profile_id ? mod.doh_profile_id.slice(0, 8) + '…' : '—'}

+
+ +

Community по умолч.

+

{communityName(mod.default_community_id)}

+
+
+ + + {#if mod.type === 'AS_PREFIXES'} + + +
+ AS-записи + ASN и/или префиксы для анонса +
+ +
+ + + + + ASN + Префикс + Community + + + + + {#each asEntries as entry (entry.id)} + + {entry.asn ?? '—'} + {entry.prefix ?? '—'} + {communityName(entry.community_id)} + +
+ + +
+
+
+ {:else} + + Нет записей + + {/each} +
+
+
+
+ {:else if mod.type === 'CDN_CIDRS'} + + +
+ CDN-источники + URL источников для скачивания списков CIDR +
+ +
+ + + + + URL + Тип + Community + Интервал + + + + + {#each cdnSources as src (src.id)} + + {src.url} + {src.source_kind} + {communityName(src.community_id)} + {src.refresh_interval_sec ? `${src.refresh_interval_sec}с` : '—'} + +
+ + +
+
+
+ {:else} + + Нет источников + + {/each} +
+
+
+
+ {:else if mod.type === 'DOMAINS'} + + +
+ Домены + FQDN для резолвинга через DoH +
+ +
+ + + + + FQDN + Community + + + + + {#each domainEntries as entry (entry.id)} + + {entry.fqdn} + {communityName(entry.community_id)} + +
+ + +
+
+
+ {:else} + + Нет доменов + + {/each} +
+
+
+
+ {:else if mod.type === 'IP_RANGES'} + + +
+ IP-диапазоны + Статические CIDR для анонса +
+ +
+ + + + + Префикс (CIDR) + Community + + + + + {#each ipEntries as entry (entry.id)} + + {entry.prefix} + {communityName(entry.community_id)} + +
+ + +
+
+
+ {:else} + + Нет диапазонов + + {/each} +
+
+
+
+ {/if} +
+{:else} +

Модуль не найден

+{/if} + + + + + + Редактировать модуль + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + + + + + Удалить модуль «{mod?.name}»? + Это действие необратимо. Модуль и все его записи будут удалены. + + + Отмена + + {deletingMod ? 'Удаление…' : 'Удалить'} + + + + + + + + + + {asEdit ? 'Редактировать запись' : 'Новая AS-запись'} + ASN и/или префикс для анонса через BGP. + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + { if (!v) asDeleteTarget = null; }}> + + + Удалить запись? + ASN: {asDeleteTarget?.asn ?? '—'}, Префикс: {asDeleteTarget?.prefix ?? '—'} + + + (asDeleteTarget = null)}>Отмена + Удалить + + + + + + + + + {cdnEdit ? 'Редактировать источник' : 'Новый CDN-источник'} + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + { if (!v) cdnDeleteTarget = null; }}> + + + Удалить CDN-источник? + {cdnDeleteTarget?.url} + + + (cdnDeleteTarget = null)}>Отмена + Удалить + + + + + + + + + {domainEdit ? 'Редактировать домен' : 'Новый домен'} + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + { if (!v) domainDeleteTarget = null; }}> + + + Удалить домен? + {domainDeleteTarget?.fqdn} + + + (domainDeleteTarget = null)}>Отмена + Удалить + + + + + + + + + {ipEdit ? 'Редактировать диапазон' : 'Новый IP-диапазон'} + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + { if (!v) ipDeleteTarget = null; }}> + + + Удалить диапазон? + {ipDeleteTarget?.prefix} + + + (ipDeleteTarget = null)}>Отмена + Удалить + + + diff --git a/web/src/routes/modules/[moduleId]/+page.ts b/web/src/routes/modules/[moduleId]/+page.ts new file mode 100644 index 0000000..d43d0cd --- /dev/null +++ b/web/src/routes/modules/[moduleId]/+page.ts @@ -0,0 +1 @@ +export const prerender = false; diff --git a/web/src/routes/monitoring/+page.svelte b/web/src/routes/monitoring/+page.svelte index 75d6e72..f23c967 100644 --- a/web/src/routes/monitoring/+page.svelte +++ b/web/src/routes/monitoring/+page.svelte @@ -1,148 +1,122 @@
-
-

Мониторинг

-

- Публичные системные эндпоинты и срез Prometheus-метрик (первые строки). Полный scrape обычно делает - Prometheus. -

+
+
+

Мониторинг

+

Доступность API и версия сборки.

+
+
-
+
+ - Health + Liveness GET /v1/health - - {#if healthOk === true} - OK - {:else if healthOk === false} - ошибка + + {#if health === null} + + {:else if health.ok} + OK + {#if health.status}

{health.status}

{/if} {:else} - + FAIL {/if} -
{healthBody || '—'}
+ - Ready + Readiness GET /v1/ready - {#if ready} -
{JSON.stringify(
-							ready,
-							null,
-							2
-						)}
+ {#if ready === null} + {:else} -

Недоступно

+ {ready.status} + {#if ready.checks} +
+ {#each Object.entries(ready.checks) as [k, v]} +
+ {k} + {JSON.stringify(v)} +
+ {/each} +
+ {/if} {/if}
+ Версия GET /v1/version - {#if version} -
-
-
api_version
-
{version.api_version ?? '—'}
-
-
-
git_sha
-
{version.git_sha ?? '—'}
-
-
+ {#if version === null} + {:else} -

Недоступно

+
+ {#each Object.entries(version) as [k, v]} +
+ {k} + {String(v)} +
+ {/each} +
{/if}
- - - - Метрики - GET /metrics (Prometheus) - - - - {#if metricsErr} -

{metricsErr}

- {/if} - -
{metricsSnippet ||
-							'Нажмите «Загрузить срез»'}
-
-
-
diff --git a/web/src/routes/network/+page.svelte b/web/src/routes/network/+page.svelte new file mode 100644 index 0000000..1106522 --- /dev/null +++ b/web/src/routes/network/+page.svelte @@ -0,0 +1,372 @@ + + +
+
+

Сеть

+

BGP-пиры и спикеры (BIRD-агенты).

+
+ + + + Пиры + Спикеры + + + + + + +
+ BGP-пиры + Настройка BGP-соседей +
+
+ + +
+
+ + + + + Адрес + Remote ASN + Состояние сессии + Спикер + + + + + {#each peers as p (p.id)} + + {p.neighbor} + {p.remote_asn ?? '—'} + + {p.session_state || '—'} + + {p.bgp_speaker_id ? p.bgp_speaker_id.slice(0, 8) + '…' : '—'} + +
+ + +
+
+
+ {:else} + + + {peersLoading ? 'Загрузка…' : 'Нет пиров.'} + + + {/each} +
+
+
+
+
+ + + + + +
+ Спикеры + BIRD-агенты, применяющие конфигурацию +
+
+ + +
+
+ + + + + Endpoint + Роль + Последняя ревизия + + + + + {#each speakers as s (s.id)} + + {s.endpoint} + {s.role} + {s.last_applied_revision_id ? s.last_applied_revision_id.slice(0, 8) + '…' : '—'} + +
+ + +
+
+
+ {:else} + + + {speakersLoading ? 'Загрузка…' : 'Нет спикеров.'} + + + {/each} +
+
+
+
+
+
+
+ + + + + + {peerEdit ? 'Редактировать пира' : 'Новый пир'} + BGP-сосед для установки сессии + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + { if (!v) peerDeleteTarget = null; }}> + + + Удалить пира? + {peerDeleteTarget?.neighbor} + + + (peerDeleteTarget = null)}>Отмена + Удалить + + + + + + + + + {speakerEdit ? 'Редактировать спикера' : 'Новый спикер'} + +
+
+ + +
+
+ + +
+
+ + + + +
+
diff --git a/web/src/routes/operations/+page.svelte b/web/src/routes/operations/+page.svelte new file mode 100644 index 0000000..8e22f20 --- /dev/null +++ b/web/src/routes/operations/+page.svelte @@ -0,0 +1,528 @@ + + +
+
+

Операции

+

Деплой конфигурации, управление ревизиями и задачами.

+
+ + +
+ +
+
+

Apply all speakers

+

Применить текущую конфигурацию на всех спикерах

+
+ +
+
+ +
+
+

BIRD Reload

+

Перезагрузить конфигурацию BIRD на всех спикерах

+
+ +
+
+
+ + + + Ревизии + Diff + Задачи + + + + + + +
+ История ревизий + Автоматически создаются при apply +
+ +
+ + + + + ID + Создана + Префиксов + Хэш + + + + + {#each revisions as rev (rev.id)} + + {rev.id.slice(0, 8)}… + {formatDate(rev.created_at)} + {rev.materialized_prefix_count} + {rev.content_hash.slice(0, 12)}… + +
+ + +
+
+
+ {:else} + + + {revLoading ? 'Загрузка…' : 'Нет ревизий'} + + + {/each} +
+
+
+
+
+ + + + + + Сравнение ревизий + Выберите ID двух ревизий для сравнения + + +
+ + + +
+ {#if diffData} +
+
+

+ Добавлено ({diffData.added?.length ?? 0})

+ + {#each diffData.added ?? [] as p} +

{typeof p === 'string' ? p : (p as {prefix?: string}).prefix ?? JSON.stringify(p)}

+ {:else} +

Нет изменений

+ {/each} +
+
+
+

- Удалено ({diffData.removed?.length ?? 0})

+ + {#each diffData.removed ?? [] as p} +

{typeof p === 'string' ? p : (p as {prefix?: string}).prefix ?? JSON.stringify(p)}

+ {:else} +

Нет изменений

+ {/each} +
+
+
+ {/if} +
+
+
+ + + + + +
+ Задачи + Фоновые задачи (ingest, apply, refresh) +
+ +
+ + + + + Вид + Статус + Создана + Завершена + + + + + {#each jobs as job (job.job_id)} + openJobDetail(job)}> + {job.kind} + {job.status} + {formatDate(job.created_at)} + {formatDate(job.finished_at)} + + {#if job.status === 'running' || job.status === 'queued'} + + {/if} + + + {:else} + + + {jobsLoading ? 'Загрузка…' : 'Нет задач'} + + + {/each} + +
+
+
+
+
+
+ + + + + + Запустить Apply на всех спикерах? + Текущая конфигурация будет применена на всех BIRD-агентах. Требуется роль operator. + + + Отмена + {applying ? 'Apply…' : 'Применить'} + + + + + + + + + Reload BIRD? + BIRD перезагрузит конфигурацию. Требуется роль operator. + + + Отмена + {reloading ? 'Reload…' : 'Reload'} + + + + + + { if (!v) rollbackTarget = null; }}> + + + Откатиться к ревизии {rollbackTarget?.id.slice(0, 8)}…? + Будет создана новая ревизия на основе выбранной. Требуется роль operator. + + + (rollbackTarget = null)}>Отмена + {rollingBack ? 'Откат…' : 'Откатить'} + + + + + + { if (!v) cancelTarget = null; }}> + + + Отменить задачу? + Задача: {cancelTarget?.kind} ({cancelTarget?.job_id?.slice(0, 8)}…) + + + (cancelTarget = null)}>Нет + {cancelling ? 'Отмена…' : 'Отменить'} + + + + + + + + + Ревизия {previewRevision?.id.slice(0, 8)}… + Предпросмотр префиксов ревизии + + {#if previewLoading} +

Загрузка…

+ {:else} +

Префиксов: {prefixesData.length}

+ + {#each prefixesData as pfx} +

{pfx}

+ {:else} +

Нет префиксов

+ {/each} +
+ {/if} +
+
+ + + + + + Задача: {jobDetail?.kind} + + {#if jobDetail} +
+
+ ID{jobDetail.job_id} + Статус{jobDetail.status} + Создана{formatDate(jobDetail.created_at)} + Начата{formatDate(jobDetail.started_at)} + Завершена{formatDate(jobDetail.finished_at)} + {#if jobDetail.error} + Ошибка{jobDetail.error} + {/if} +
+ {#if jobDetail.meta && Object.keys(jobDetail.meta).length > 0} +
+

Meta

+
{JSON.stringify(jobDetail.meta, null, 2)}
+
+ {/if} +
+ {/if} +
+
diff --git a/web/src/routes/peers/+page.svelte b/web/src/routes/peers/+page.svelte index c35cae0..1d74be7 100644 --- a/web/src/routes/peers/+page.svelte +++ b/web/src/routes/peers/+page.svelte @@ -1,118 +1,5 @@ - -
-
-

Пиры и спикеры

-

BGP-пиры и экземпляры BIRD.

-
- - {#if err} -

{err}

- {/if} - - - - Спикеры - GET /v1/speakers - - - - - - - Роль - Endpoint - Последняя ревизия - - - - {#each speakers as s} - - {s.role} - {s.endpoint} - {s.last_applied_revision_id ?? '—'} - - {:else} - - Нет данных - - {/each} - -
-
-
-
- - - - Пиры - GET /v1/peers - - - - - - - Имя - Neighbor - Сессия - - - - {#each peers as p} - - {p.name} - {p.neighbor} - - {p.session_state} - - - {:else} - - Нет данных - - {/each} - -
-
-
-
-
diff --git a/web/src/routes/revisions/+page.svelte b/web/src/routes/revisions/+page.svelte index 8ca56ff..b7f92f1 100644 --- a/web/src/routes/revisions/+page.svelte +++ b/web/src/routes/revisions/+page.svelte @@ -1,80 +1,5 @@ - -
-
-

Ревизии

-

История конфигурации BIRD.

-
- - - - Ревизии - GET /v1/revisions - - - {#if err} -

{err}

- {:else} - - - - - ID - Хэш - Префиксы - Создана - - - - {#each rows as r} - - {r.id} - {r.content_hash} - {r.materialized_prefix_count ?? '—'} - {r.created_at} - - {:else} - - Нет данных - - {/each} - -
-
- {/if} -
-
-
diff --git a/web/src/routes/schedule/+page.svelte b/web/src/routes/schedule/+page.svelte index 45debd5..51dad7a 100644 --- a/web/src/routes/schedule/+page.svelte +++ b/web/src/routes/schedule/+page.svelte @@ -1,11 +1,10 @@
-
-

Расписание и задачи

-

- Интервалы обновления модулей (поля из API) и ручной refresh → ingest. Ниже — последние задачи из - job_audit. -

+
+
+

Расписание и задачи

+

Интервалы обновления модулей и ручной запуск refresh.

+
+
- Модули и refresh - - POST /v1/modules/{id}/refresh (роль editor+). CDN/домены/AS — очередь; IP_RANGES — 204. - + Модули + Запустить refresh вручную (CDN/домены/AS → очередь; IP_RANGES → 204) - - - - + +
+ + + Модуль + Тип + Интервал + Cron + + + + + {#each modules as m (m.id)} - Модуль - Тип - Интервал - Cron - Действие + {m.name} + {m.type} + {intervalLabel(m.refresh_interval_sec)} + {m.cron_expr || '—'} + + + - - - {#each modules as m} - - {m.name} - - {m.type} - - {intervalLabel(m.refresh_interval_sec)} - {m.cron_expr || '—'} - - - - - {:else} - - Нет модулей - - {/each} - -
-
+ {:else} + + + {loading ? 'Загрузка…' : 'Нет модулей'} + + + {/each} + +
@@ -129,33 +131,33 @@ Последние задачи GET /v1/jobs - - - - + +
+ + + Вид + Статус + Создана + Ошибка + + + + {#each jobs as j (j.job_id)} - Вид - Статус - Создана + {j.kind} + {j.status} + {j.created_at ? new Date(j.created_at).toLocaleString('ru') : '—'} + {j.error ?? ''} - - - {#each jobs as j} - - {j.kind} - - {j.status} - - {j.created_at ?? '—'} - - {:else} - - Нет задач - - {/each} - -
-
+ {:else} + + + {loading ? 'Загрузка…' : 'Нет задач'} + + + {/each} + +
diff --git a/web/src/routes/settings/+page.svelte b/web/src/routes/settings/+page.svelte index bc7159f..0858b0f 100644 --- a/web/src/routes/settings/+page.svelte +++ b/web/src/routes/settings/+page.svelte @@ -1,13 +1,22 @@ -
+

Настройки

-

- Bearer-токен для заголовка Authorization. Для - локального демо с - EVOBGP_DEV_INSECURE=1 - можно использовать токен dev. -

+

Токен доступа и параметры API.

+ API-ключ - Хранится только в localStorage + + Bearer-токен хранится только в localStorage браузера. Для локального демо с + EVOBGP_DEV_INSECURE=1 + используйте токен dev. +
- + +
+
+ + + + + Настройки системы (API) + + GET/PATCH /v1/settings — глобальные параметры control plane. + Требуется роль operator. + + + + {#if loadingSettings} +

Загрузка…

+ {:else if apiSettings !== null} +
+ +