Commit graph

312 commits

Author SHA1 Message Date
75861fe990 help: map app routes to the correct help pages
Update getHelpPathFromRoute to point at the help pages that actually
exist: rename source-* links to provider-*, the home alias to domains,
and add coverage for login, signup, notifications, provider features,
domain history, import/export, subdomains, services, checks,
availability and whois routes.
2026-07-12 20:46:15 +08:00
ef4d4f601b web: add ETags to no-cache index.html and manifest.json
Both documents are served no-cache but had no validator, so every
revalidation re-downloaded the full body and could never return 304.
Serve them via http.ServeContent with an ETag computed once at handler
creation, letting conditional requests answer 304. manifest.json is now
pre-rendered once instead of re-read and re-transformed per request.
2026-07-12 20:46:15 +08:00
d20b758c52 web: always revalidate service-worker.js
The service worker controls all client-side caching, so it must never be
pinned to an old version. It was served with no explicit cache policy;
mark it no-cache so updates are always picked up.
2026-07-12 20:46:15 +08:00
d19a28783a web: stop marking stable static assets immutable
/fonts, /img and /favicon.ico live at stable, non-content-hashed URLs, so
the 7-day immutable header meant a changed favicon, image or font would
not reach already-cached clients for up to a week.

Serve them with a revalidated policy (max-age=86400, must-revalidate) set
on the successful response instead, and drop the now-unused immutable
middleware. Only the content-hashed /_app tree keeps immutable.
2026-07-12 20:46:15 +08:00
b9f3314e12 web: don't let /_app 404s be cached as immutable
The immutable middleware set Cache-Control before the handler ran, so a
missing content-hashed asset under /_app/immutable/ 404'd with the 7-day
immutable header still attached: a stale client could pin a negative
response for a week. The stale-bundle fallback also only covered .js,
leaving dropped .css (and other) chunks exposed.

Open the asset first and set the immutable directive only on a successful
serve, so a 404 never inherits it. Broaden the stale-asset path to mark
any missing /_app/immutable/ response no-cache, still returning the
self-healing reload module for .js.
2026-07-12 20:46:15 +08:00
96935f11c5 web: recover stale cached clients after deploy instead of freezing
All checks were successful
continuous-integration/drone/push Build is passing
The SPA references content-hashed bundles under /_app/immutable/ embedded
in the binary. After a deploy the binary ships new hashes and drops the old
ones, so a browser reusing a cached HTML page (or a stale /_app bundle)
requests hashes that 404: the page renders but the app never starts, leaving
it visible but frozen.

- routes.go: serve the page HTML (and the rewritten manifest.json) with
  Cache-Control no-cache so clients always revalidate and load a page that
  points at bundles which actually exist; /_app/* stays immutable.
- routes.go: when a missing /_app/immutable/*.js is requested (a stale cached
  client), return a self-healing reload module (200) instead of a dead 404 so
  already-stuck clients recover on their own.

The reload module is issued synchronously and throws at the end of evaluation
so the failing import() rejects: SvelteKit's bootstrap never reaches
kit.start(...), avoiding a "kit.start is not a function" TypeError. We do not
touch the Cache Storage API: the service worker manages its own cache
lifecycle and async caches.* work would lose the race against kit.start.
2026-06-14 21:44:20 +09:00
16bc06359c web: fix service update navigating to stale zone after edit
Some checks failed
continuous-integration/drone/push Build is failing
When updating a service on a published zone, the backend creates a new
derivative zone with a new ID. The frontend was navigating back using the
old zone ID, causing the layout loader to re-fetch the pre-update zone and
overwrite the store, making the change appear lost. Unify add and update
paths to always refresh domains and navigate to the returned zone ID.
2026-06-13 16:15:10 +09:00
6c2b2595ab web: use toasts for checker schedule save status
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-08 09:08:21 +09:00
b641f893bb web: Fix is_auth_user call when not auth_user
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-06 22:04:11 +09:00
d5a651ad70 web: In case of error, fallback on rules 2026-06-06 22:04:11 +09:00
e453e20916 web: Disable buttons to run tests when checker scheduler is disabled 2026-06-06 22:04:11 +09:00
73f36271dc web: missing split checker config from runtime results 2026-06-06 22:04:11 +09:00
5b7271ed2d web: extract Sidebar component from domain layout 2026-05-26 11:54:13 +08:00
ce0e8e2cfe web: sort listScopedCheckers results alphabetically at the source
Move the by-name sort into listScopedCheckers so every consumer gets a
stable ordering, and drop the redundant sort wrappers in CheckerListPage
and CheckResultsDashboard.
2026-05-25 16:34:08 +08:00
02a53e85ce checker: filter listing to scheduled checkers by default
Add with_availables query param to checker status endpoint; restrict
default listing to checkers that auto-schedule or have an active plan.
Introduce IsAutoScheduled helper unifying scheduler eligibility logic.
2026-05-25 16:10:27 +08:00
3213d00ff4 web: split checker config (/checkers) from runtime results (/checks)
The route at /domains/[dn]/checks listed checker configurations, not check
runs. Rename it to /checkers and use /checks for a new aggregated dashboard
that surfaces the latest result for every enabled checker across the domain
and its services in one place. Same split applied at service scope.
2026-05-25 16:10:24 +08:00
f28cdefa8b Add user data export (GDPR/DSAR)
Refactors the admin backup usecase to share per-user collection logic
via backupOneUser(), then adds BackupUser() which filters system-wide
collections (checker configs, plans, evaluations, executions, discovery)
down to the requesting user by UserId.

Wires the backup usecase into the public API dependency graph and adds
a download button in the /me settings page near the delete-account
section.
2026-05-25 12:25:43 +08:00
f2a13fc12c chore(deps): replace svelte-preprocess with vitePreprocess
All checks were successful
continuous-integration/drone/push Build is passing
svelte-preprocess v6 dropped the TypeScript transformer since Svelte 5
and @sveltejs/vite-plugin-svelte handle TypeScript natively via Vite.
2026-05-25 11:30:36 +08:00
e1eac4dd1f web: refactor checker config pages to scope-aware unified groups layout
Some checks failed
continuous-integration/drone/push Build is failing
Replace the per-route editableGroups/readOnlyGroups callback pair in
CheckerConfigPage with a single groups prop that returns both lists, and
switch all call-sites to buildOptionGroupLayout. Add showCheckerInfo and
showExecutions flags so the admin checker page can reuse CheckerConfigPage
without schedule controls or execution links.

CheckerOptionsPanel now shows an "Overriding inherited" badge and a
"Reset to inherited" link for fields where a local value shadows an
inherited one. CheckerOptionsGroups shows the effective inherited value
next to the type hint in read-only groups.
2026-05-24 18:24:50 +08:00
6954f312f9 web: add serviceOpts support and buildOptionGroupLayout utility
Extend collectAllOptionDocs, splitPositionalOptions, and
collectAutoFillKeys to include serviceOpts alongside the existing
adminOpts/userOpts/domainOpts buckets.

Add buildOptionGroupLayout which derives editable/read-only group lists
from the checker's option documentation and a CheckerPageScope ("admin",
"domain", or "service"). This consolidates the per-route hand-curated
arrays into one place.

Improve splitPositionalOptions with an optional isCurrentScope predicate
so the correct positional is selected for the page's scope instead of
always taking the last stored entry.
2026-05-24 18:24:36 +08:00
6005dbd18a web: add admin scope support to checker API helpers
Make CheckerScope.domainId optional so callers can target the global
admin scope (no domain). getScopedCheckStatus, getScopedCheckOptions,
and updateScopedCheckOptions now short-circuit to the admin /checkers/*
routes when domainId is absent. All narrower-scope callsites gain the
non-null assertion required by the type change.
2026-05-24 18:24:21 +08:00
6ceebe2adb web: disable metrics/json view buttons when data is unavailable
Add a `disableMetrics` store that gets set when metrics fail to load,
preventing users from switching to a broken metrics view. Also disable
the JSON view button when no observations data is present.
2026-05-24 18:23:42 +08:00
680e4dc6e2 web: Improve ui when captcha is required 2026-05-24 17:26:35 +08:00
47049c5b6e web: fix screen freeze after service deletion when zone ID changes
Remove the invalid bind:rr chain between RecordLine and RecordText (RecordText only reads rr, never writes back), and use refreshDomains + invalidateAll instead of directly setting thisZone when the returned zone has a new ID, matching the pattern already used in the domain layout.
2026-05-24 17:26:35 +08:00
2045beb1b1 api-admin: fix reset_password returning empty password when no body sent
Treat io.EOF from ShouldBindJSON as "no body provided" so callers can
POST without a request body to trigger random password generation. Also
fix double-pointer bug (&urp where urp is already *resetPassword) and
bump checker dependencies.
2026-05-24 17:26:31 +08:00
8a7146f4ca web: fix login error showing wrong message and sometimes duplicate toast
When POST /auth returned 401 with an errmsg (e.g. "Invalid username or
password"), customFetch was ignoring it and attempting a session refresh
via GET /auth. The refresh also failed, ultimately throwing
NotAuthorizedError("Not authenticated") instead of the actual credential
error. This also triggered an extra toast in some cases.

Fix by reading errmsg from any 401 response body first: if present, throw
it directly as a plain Error, bypassing the session-refresh logic entirely.
2026-05-24 17:25:34 +08:00
5115ed1993 web: replace Prometheus metrics copy button with explanatory modal
The previous click-to-copy behavior wasn't obvious to users. Show the
URL in a modal with an explicit copy button and a brief scrape_configs
example so users understand what the endpoint is for.
2026-05-24 17:25:34 +08:00
0a120a6d97 web: reset checker state on navigation to avoid stale enabled/options
When switching between checkers via the sidebar, plan.enabled retained
the previous checker's values because the guard condition prevented
re-initialization. Reset all derived state eagerly on checkerId change
and always repopulate plan.enabled from fresh status.
2026-05-24 17:25:34 +08:00
3eca2f3800 web: redesign CheckerScheduleCard with autosave and improved UX
- Move enable/disable toggle to card header (inverted to "Enable scheduling")
- Replace Save button with debounced autosave (700ms) with inline status indicator
- Show interval controls only when enabled; paused hint when disabled
- Remove obsolete no-schedule-yet alert and save button translation keys
2026-05-24 17:25:34 +08:00
31ecf89624 web: mask secret field placeholders when hidden
The HTML placeholder attribute is rendered in plaintext even on
type="password" inputs, so an inherited secret value injected as a
placeholder was visible without toggling the eye button. Replace the
placeholder with bullets of the same length while the secret is hidden, and
reveal the real value only when the user explicitly toggles visibility.
2026-05-24 17:25:34 +08:00
f8c6eb8a88 web: hide rules behind advanced options and show rule descriptions
Rules are now collapsed under the Advanced options toggle instead of
being always visible, and each rule's description is displayed as
helper text below the checkbox when available.
2026-05-24 17:25:34 +08:00
b18c9dc918 web: exclude auto-fill positional from current-scope split
The GetCheckerOptions controller appends a synthetic positional carrying
resolved auto-fill values (consumed by RunCheckModal). splitPositionalOptions
was treating that last entry as the current scope, pushing actual stored
options into inheritedValues — they then showed as placeholders, broke
<select> value matching, and were sent as nil overrides on save. Callers now
pass the auto-fill key set so the synthetic positional is filtered out before
splitting.
2026-05-24 17:25:34 +08:00
3ae7366b00 checker: add plan-level disable toggle to pause scheduling
Adds an explicit Disabled field on CheckPlan so users can pause a
checker's automatic execution without clearing per-rule state. The
scheduler skips Disabled plans alongside fully-disabled ones, and the
schedule card exposes a switch bound through the existing save path.
2026-05-24 17:25:34 +08:00
10c10bc846 web: treat checker All toggle as on when any rule is enabled
Switch the bulk toggle from every-enabled to some-enabled so the
"All" switch reflects an OR across rules: on when at least one is
active, off only when all are disabled.
2026-05-24 17:25:34 +08:00
d8f542a829 web: show distinct toast when toggling checker rules enabled/disabled
Rule toggle switches now call a dedicated handleSavePlan() wrapper with
"rules-updated"/"rules-update-failed" messages, separate from the schedule
card's "Schedule saved" toast. CheckerScheduleCard.save() is split into a
raw export (no toasts) and an internal handleSave() used by its own button.
2026-05-24 17:25:34 +08:00
6983e097ba web: move save toast feedback into checker card/panel components
Each component now owns its success/error toast UX via a handleSave()
wrapper, removing duplicate toast logic from parent saveOptions functions.
2026-05-24 17:25:34 +08:00
3c03bb1306 checker: surface per-rule precheck failures on scoped status
The SDK's new POST /definition returns per-rule precheck errors for the
current options. happyDomain now calls it (or the in-process equivalent
when no remote endpoint is configured) while building each
CheckerStatus, exposes the result as CheckerStatus.PrecheckFailures,
and the rules card in the UI disables the toggle and shows the reason
for any rule whose prerequisites are unmet.
2026-05-24 17:25:34 +08:00
7cfc0ff7e0 web: Display rules page when no observations exists 2026-05-24 17:25:34 +08:00
0d0e220c06 web: use ClassValue from svelte/elements for class props
Replace class?: string with class?: ClassValue across Svelte components,
adopting the idiomatic Svelte 5 array syntax (class={["base", className]})
instead of string interpolation for combining static and dynamic classes.
2026-05-24 17:25:34 +08:00
98ceb57175 web: Improve sidebar in domain/services/checks 2026-05-24 17:25:34 +08:00
7cb67c452f web: Fix sidebar button hell 2026-05-24 17:25:34 +08:00
056ceb1778 checkers: poll execution status while running instead of fetching empty data
When opening an execution detail page while the execution is still
pending or running, defer fetching observations/results/metrics and
poll the execution status every 3s until it reaches a terminal state.
The loading view shows a "Running" label in the meantime.
2026-05-24 17:25:34 +08:00
ff6dbc1f7a checkers: prefer HTML report over metrics as default view
HTML reports typically provide a richer summary than raw metrics, so
when both are available we open the HTML tab first.
2026-05-24 17:25:34 +08:00
20de284c25 checkers: default to rules view when execution failed
Surfaces error details immediately instead of opening metrics or HTML
report tabs that may be empty or misleading for failed runs.
2026-05-24 17:25:34 +08:00
075448ef67 web: silence isAuthUser errors on settings page for OIDC users 2026-05-24 17:25:34 +08:00
ed80de9e71 web: Prioritize HTML report view over metrics as default 2026-05-24 17:25:34 +08:00
6cf60bf17f web: sort checker list alphabetically in sidebar 2026-05-24 17:25:34 +08:00
b94bc83e58 chore(deps): update dependency typescript to v6
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-10 14:11:03 +00:00
f0b3a0f94d ci: fix pipeline inconsistencies and improve Docker builds
- Replace DRONE_TAG##v with DRONE_SEMVER across all pipelines
- Add missing VERSION build_args and tag-specific Docker publish steps to amd64 pipeline
- Add prerelease: true to amd64 release publish steps for consistency with arm64
- Pin swag and go-licenses versions with renovate annotations
- Add renovate regex manager to track go install versions in .drone.yml
- Add BuildKit cache mounts and OCI labels to Dockerfiles
- Improve Dockerfile layer efficiency (separate web/web-admin asset copies, smaller COPY targets)
- Move npm build/generate directives to separate generate_npm.go files with //go:build ignore
- Update README build instructions to include web-admin and correct step order
2026-05-10 20:17:55 +08:00
a037e39df2 Fix malformed manifest.json 2026-05-10 20:17:55 +08:00