Compare commits
28 commits
5e988b4098
...
6e91c779bd
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e91c779bd | |||
| b8b02ea125 | |||
| 6133ee0321 | |||
| 40a92f97dd | |||
| 59c50d12c0 | |||
| c06cbfa8cd | |||
| 7a1e74e836 | |||
| 7e762df161 | |||
| 6705dc8d56 | |||
| ee6b7a8763 | |||
| 865b4db24f | |||
| 6a36cbd7c0 | |||
| a6aa363fa5 | |||
| 7d422df708 | |||
| 444949ded6 | |||
| 0633538e88 | |||
| faa2cbb4d7 | |||
| 7ff5fa7a58 | |||
| f8e1bfac03 | |||
| 7331d4dfbe | |||
| 1e9e7b2161 | |||
| 34788c145f | |||
| 640c848c98 | |||
| 6424be8f6b | |||
| d9468df619 | |||
| 5afb2797b4 | |||
| e7753a84b2 | |||
| 5726b267e6 |
13 changed files with 104 additions and 195 deletions
2
go.sum
2
go.sum
|
|
@ -12,8 +12,6 @@ git.happydns.org/checker-matrix v0.0.0-20260407211824-2bb91d33d489 h1:pTGfGq88Dj
|
||||||
git.happydns.org/checker-matrix v0.0.0-20260407211824-2bb91d33d489/go.mod h1:fQjY1yWYFucu+Ebn5uYM7ZWTJNQIgjMENI/8tqlaR98=
|
git.happydns.org/checker-matrix v0.0.0-20260407211824-2bb91d33d489/go.mod h1:fQjY1yWYFucu+Ebn5uYM7ZWTJNQIgjMENI/8tqlaR98=
|
||||||
git.happydns.org/checker-ping v0.0.0-20260407194626-a2ebf17774fc h1:jKEOx2NDbHHxjCy1fUkcn1RgpzOKbE+bGRsF+ITNigI=
|
git.happydns.org/checker-ping v0.0.0-20260407194626-a2ebf17774fc h1:jKEOx2NDbHHxjCy1fUkcn1RgpzOKbE+bGRsF+ITNigI=
|
||||||
git.happydns.org/checker-ping v0.0.0-20260407194626-a2ebf17774fc/go.mod h1:wphWmslFhKcpWfJTrHdChv8DkhUP9jwis7V2jy7vOX0=
|
git.happydns.org/checker-ping v0.0.0-20260407194626-a2ebf17774fc/go.mod h1:wphWmslFhKcpWfJTrHdChv8DkhUP9jwis7V2jy7vOX0=
|
||||||
git.happydns.org/checker-sdk-go v0.4.0 h1:MDUnzdIy+o4yXQkcGl6QRXVprwlERmIJ9nuO7cspUBs=
|
|
||||||
git.happydns.org/checker-sdk-go v0.4.0/go.mod h1:aNAcfYFfbhvH9kJhE0Njp5GX0dQbxdRB0rJ0KvSC5nI=
|
|
||||||
git.happydns.org/checker-sdk-go v0.5.0 h1:wpFIK/vxanrAYf1OlewSnSCYc7KOJKdu88uUWB7HIQI=
|
git.happydns.org/checker-sdk-go v0.5.0 h1:wpFIK/vxanrAYf1OlewSnSCYc7KOJKdu88uUWB7HIQI=
|
||||||
git.happydns.org/checker-sdk-go v0.5.0/go.mod h1:aNAcfYFfbhvH9kJhE0Njp5GX0dQbxdRB0rJ0KvSC5nI=
|
git.happydns.org/checker-sdk-go v0.5.0/go.mod h1:aNAcfYFfbhvH9kJhE0Njp5GX0dQbxdRB0rJ0KvSC5nI=
|
||||||
git.happydns.org/checker-zonemaster v0.0.0-20260407202727-979757b5a8fc h1:y5xjoqLA/WztFWhEUifOwnJ6POjl+Udw6bWjzQ2afOw=
|
git.happydns.org/checker-zonemaster v0.0.0-20260407202727-979757b5a8fc h1:y5xjoqLA/WztFWhEUifOwnJ6POjl+Udw6bWjzQ2afOw=
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,11 @@
|
||||||
let inheritedValues = $state<Record<string, unknown>>({});
|
let inheritedValues = $state<Record<string, unknown>>({});
|
||||||
let savingOptions = $state(false);
|
let savingOptions = $state(false);
|
||||||
|
|
||||||
|
let checkerDef = $derived($checkers?.[checkerId]);
|
||||||
|
let intervalSpec = $derived(checkerDef?.interval);
|
||||||
|
|
||||||
let plan = $state<HappydnsCheckPlanWritable>({
|
let plan = $state<HappydnsCheckPlanWritable>({
|
||||||
enabled: {},
|
enabled: {},
|
||||||
interval: 3600,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
|
@ -142,7 +144,7 @@
|
||||||
<Row class="mb-4">
|
<Row class="mb-4">
|
||||||
{#if showSchedule}
|
{#if showSchedule}
|
||||||
<Col md={6}>
|
<Col md={6}>
|
||||||
<CheckerScheduleCard {scope} {checkerId} bind:plan />
|
<CheckerScheduleCard {scope} {checkerId} bind:plan {intervalSpec} />
|
||||||
|
|
||||||
{#if status.rules && status.rules.length > 0}
|
{#if status.rules && status.rules.length > 0}
|
||||||
<CheckerRulesCard
|
<CheckerRulesCard
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
Input,
|
Input,
|
||||||
Label,
|
Label,
|
||||||
} from "@sveltestrap/sveltestrap";
|
} from "@sveltestrap/sveltestrap";
|
||||||
import type { HappydnsCheckPlan, HappydnsCheckPlanWritable } from "$lib/api-base/types.gen";
|
import type { CheckerCheckIntervalSpec, HappydnsCheckPlan, HappydnsCheckPlanWritable } from "$lib/api-base/types.gen";
|
||||||
import { t } from "$lib/translations";
|
import { t } from "$lib/translations";
|
||||||
import { toasts } from "$lib/stores/toasts";
|
import { toasts } from "$lib/stores/toasts";
|
||||||
import type { CheckerScope } from "$lib/api/checkers";
|
import type { CheckerScope } from "$lib/api/checkers";
|
||||||
|
|
@ -43,17 +43,31 @@
|
||||||
updateScopedCheckPlan,
|
updateScopedCheckPlan,
|
||||||
} from "$lib/api/checkers";
|
} from "$lib/api/checkers";
|
||||||
|
|
||||||
|
const NS_PER_MINUTE = 60_000_000_000;
|
||||||
|
const NS_PER_HOUR = 3_600_000_000_000;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
scope: CheckerScope;
|
scope: CheckerScope;
|
||||||
checkerId: string;
|
checkerId: string;
|
||||||
plan: HappydnsCheckPlan | HappydnsCheckPlanWritable;
|
plan: HappydnsCheckPlan | HappydnsCheckPlanWritable;
|
||||||
|
intervalSpec?: CheckerCheckIntervalSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { scope, checkerId, plan = $bindable() }: Props = $props();
|
let { scope, checkerId, plan = $bindable(), intervalSpec }: Props = $props();
|
||||||
|
|
||||||
let existingPlanId = $state<string | undefined>(undefined);
|
let existingPlanId = $state<string | undefined>(undefined);
|
||||||
let saving = $state(false);
|
let saving = $state(false);
|
||||||
|
|
||||||
|
// Determine whether to use minutes or hours as the UI unit.
|
||||||
|
let useMinutes = $derived(
|
||||||
|
intervalSpec != null && intervalSpec.min != null && intervalSpec.min < NS_PER_HOUR
|
||||||
|
);
|
||||||
|
let unitNs = $derived(useMinutes ? NS_PER_MINUTE : NS_PER_HOUR);
|
||||||
|
|
||||||
|
let defaultIntervalNs = $derived(intervalSpec?.default ?? NS_PER_HOUR);
|
||||||
|
let minNs = $derived(intervalSpec?.min ?? NS_PER_HOUR);
|
||||||
|
let maxNs = $derived(intervalSpec?.max ?? 24 * NS_PER_HOUR);
|
||||||
|
|
||||||
let schedulesPromise = $derived(getScopedCheckPlans(scope, checkerId));
|
let schedulesPromise = $derived(getScopedCheckPlans(scope, checkerId));
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
|
@ -63,7 +77,7 @@
|
||||||
existingPlanId = s.id;
|
existingPlanId = s.id;
|
||||||
plan = {
|
plan = {
|
||||||
enabled: s.enabled ?? {},
|
enabled: s.enabled ?? {},
|
||||||
interval: s.interval ?? 3600,
|
interval: s.interval ?? defaultIntervalNs,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -97,12 +111,31 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function intervalHours(): number {
|
function intervalDisplayValue(): number {
|
||||||
return Math.round((plan.interval ?? 3600) / 3600);
|
return Math.round((plan.interval ?? defaultIntervalNs) / unitNs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setIntervalHours(hours: number) {
|
function setIntervalValue(val: number) {
|
||||||
plan.interval = Math.max(3600, hours * 3600);
|
const clamped = Math.max(minNs, Math.min(maxNs, val * unitNs));
|
||||||
|
plan.interval = clamped;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NS_PER_DAY = 24 * NS_PER_HOUR;
|
||||||
|
const NS_PER_WEEK = 7 * NS_PER_DAY;
|
||||||
|
|
||||||
|
function formatDuration(ns: number): string {
|
||||||
|
if (ns >= NS_PER_WEEK && ns % NS_PER_WEEK === 0) {
|
||||||
|
return `${ns / NS_PER_WEEK}w`;
|
||||||
|
}
|
||||||
|
if (ns >= NS_PER_DAY && ns % NS_PER_DAY === 0) {
|
||||||
|
return `${ns / NS_PER_DAY}d`;
|
||||||
|
}
|
||||||
|
if (ns >= NS_PER_HOUR) {
|
||||||
|
const h = Math.round(ns / NS_PER_HOUR);
|
||||||
|
return `${h}h`;
|
||||||
|
}
|
||||||
|
const m = Math.round(ns / NS_PER_MINUTE);
|
||||||
|
return `${m}min`;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -125,15 +158,22 @@
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
min={1}
|
min={Math.round(minNs / unitNs)}
|
||||||
value={intervalHours()}
|
max={Math.round(maxNs / unitNs)}
|
||||||
|
value={intervalDisplayValue()}
|
||||||
oninput={(e: Event) =>
|
oninput={(e: Event) =>
|
||||||
setIntervalHours(parseInt((e.target as HTMLInputElement).value) || 1)}
|
setIntervalValue(parseInt((e.target as HTMLInputElement).value) || 1)}
|
||||||
style="width: 100px"
|
style="width: 100px"
|
||||||
/>
|
/>
|
||||||
<span>{$t("checkers.schedule.hours")}</span>
|
<span>{useMinutes ? $t("checkers.schedule.minutes") : $t("checkers.schedule.hours")}</span>
|
||||||
</div>
|
</div>
|
||||||
<small class="text-muted">{$t("checkers.schedule.interval-hint")}</small>
|
<small class="text-muted">
|
||||||
|
{$t("checkers.schedule.interval-hint", {
|
||||||
|
intervalMin: formatDuration(minNs),
|
||||||
|
intervalMax: formatDuration(maxNs),
|
||||||
|
intervalDefault: formatDuration(defaultIntervalNs),
|
||||||
|
})}
|
||||||
|
</small>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,22 @@
|
||||||
|
|
||||||
import { t } from "$lib/translations";
|
import { t } from "$lib/translations";
|
||||||
import type { CheckerScope, CheckMetric } from "$lib/api/checkers";
|
import type { CheckerScope, CheckMetric } from "$lib/api/checkers";
|
||||||
|
import type { HappydnsCheckEvaluation } from "$lib/api-base/types.gen";
|
||||||
import {
|
import {
|
||||||
getScopedExecution,
|
getScopedExecution,
|
||||||
getScopedExecutionObservations,
|
getScopedExecutionObservations,
|
||||||
getScopedExecutionMetrics,
|
getScopedExecutionMetrics,
|
||||||
|
getScopedExecutionResults,
|
||||||
getCheckStatus,
|
getCheckStatus,
|
||||||
} from "$lib/api/checkers";
|
} from "$lib/api/checkers";
|
||||||
import { currentExecution, currentCheckInfo, currentObservations, reportViewMode, cachedHTMLReport } from "$lib/stores/checkers";
|
import {
|
||||||
|
currentExecution,
|
||||||
|
currentCheckInfo,
|
||||||
|
currentObservations,
|
||||||
|
reportViewMode,
|
||||||
|
cachedHTMLReport,
|
||||||
|
} from "$lib/stores/checkers";
|
||||||
|
import ExecutionResultsCard from "./ExecutionResultsCard.svelte";
|
||||||
import ObservationReportCard from "./ObservationReportCard.svelte";
|
import ObservationReportCard from "./ObservationReportCard.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -48,11 +57,13 @@
|
||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let error = $state<string | undefined>(undefined);
|
let error = $state<string | undefined>(undefined);
|
||||||
let metricsData = $state<CheckMetric[] | null>(null);
|
let metricsData = $state<CheckMetric[] | null>(null);
|
||||||
|
let evaluationData = $state<HappydnsCheckEvaluation | null>(null);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
loading = true;
|
loading = true;
|
||||||
error = undefined;
|
error = undefined;
|
||||||
metricsData = null;
|
metricsData = null;
|
||||||
|
evaluationData = null;
|
||||||
cachedHTMLReport.set(null);
|
cachedHTMLReport.set(null);
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
|
|
@ -65,7 +76,11 @@
|
||||||
currentCheckInfo.set(checkerInfo);
|
currentCheckInfo.set(checkerInfo);
|
||||||
currentObservations.set(observations);
|
currentObservations.set(observations);
|
||||||
checkerName = checkerInfo.name ?? checkerId;
|
checkerName = checkerInfo.name ?? checkerId;
|
||||||
// Default to metrics view if supported, then HTML, then JSON
|
// Load rules data
|
||||||
|
getScopedExecutionResults(scope, checkerId, execId)
|
||||||
|
.then((e) => (evaluationData = e))
|
||||||
|
.catch((e) => console.warn("Failed to load execution results", e));
|
||||||
|
// Default to metrics view if supported, then HTML, then rules, then JSON
|
||||||
if (checkerInfo.has_metrics) {
|
if (checkerInfo.has_metrics) {
|
||||||
reportViewMode.set("metrics");
|
reportViewMode.set("metrics");
|
||||||
getScopedExecutionMetrics(scope, checkerId, execId)
|
getScopedExecutionMetrics(scope, checkerId, execId)
|
||||||
|
|
@ -74,7 +89,7 @@
|
||||||
} else if (checkerInfo.has_html_report) {
|
} else if (checkerInfo.has_html_report) {
|
||||||
reportViewMode.set("html");
|
reportViewMode.set("html");
|
||||||
} else {
|
} else {
|
||||||
reportViewMode.set("json");
|
reportViewMode.set("rules");
|
||||||
}
|
}
|
||||||
loading = false;
|
loading = false;
|
||||||
},
|
},
|
||||||
|
|
@ -114,6 +129,10 @@
|
||||||
{$t("checkers.result.error-loading", { error })}
|
{$t("checkers.result.error-loading", { error })}
|
||||||
</Alert>
|
</Alert>
|
||||||
</Container>
|
</Container>
|
||||||
|
{:else if $reportViewMode === "rules" && evaluationData}
|
||||||
|
<Container class="flex-fill d-flex flex-column mt-3">
|
||||||
|
<ExecutionResultsCard evaluation={evaluationData} />
|
||||||
|
</Container>
|
||||||
{:else if $currentObservations}
|
{:else if $currentObservations}
|
||||||
<ObservationReportCard
|
<ObservationReportCard
|
||||||
observations={$currentObservations}
|
observations={$currentObservations}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@
|
||||||
let metricsData = $state<CheckMetric[] | null>(null);
|
let metricsData = $state<CheckMetric[] | null>(null);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
metricsData = null;
|
||||||
getCheckStatus(checkerId).then((s) => {
|
getCheckStatus(checkerId).then((s) => {
|
||||||
resolvedName = s.name ?? checkerId;
|
resolvedName = s.name ?? checkerId;
|
||||||
if (s.has_metrics) {
|
if (s.has_metrics) {
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,11 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Card, CardBody, CardHeader, Table } from "@sveltestrap/sveltestrap";
|
import { Badge, Card, CardBody, CardHeader, Table } from "@sveltestrap/sveltestrap";
|
||||||
|
|
||||||
import { t } from "$lib/translations";
|
import { t } from "$lib/translations";
|
||||||
import type { HappydnsCheckEvaluation } from "$lib/api-base/types.gen";
|
import type { HappydnsCheckEvaluation } from "$lib/api-base/types.gen";
|
||||||
|
import { getStatusColor, getStatusI18nKey } from "$lib/utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
evaluation: HappydnsCheckEvaluation;
|
evaluation: HappydnsCheckEvaluation;
|
||||||
|
|
@ -40,10 +41,11 @@
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
{#if evaluation.states && evaluation.states.length > 0}
|
{#if evaluation.states && evaluation.states.length > 0}
|
||||||
<Table size="sm" borderless>
|
<Table class="mb-0" size="sm" borderless hover>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t("checkers.result.field.rule")}</th>
|
<th>{$t("checkers.result.field.rule")}</th>
|
||||||
|
<th>{$t("checkers.result.field.status")}</th>
|
||||||
<th>{$t("checkers.result.field.message")}</th>
|
<th>{$t("checkers.result.field.message")}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -51,6 +53,7 @@
|
||||||
{#each evaluation.states as state}
|
{#each evaluation.states as state}
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>{state.code ?? ""}</code></td>
|
<td><code>{state.code ?? ""}</code></td>
|
||||||
|
<td><Badge color={getStatusColor(state.status)}>{$t(getStatusI18nKey(state.status))}</Badge></td>
|
||||||
<td>{state.message ?? ""}</td>
|
<td>{state.message ?? ""}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
<!--
|
|
||||||
This file is part of the happyDomain (R) project.
|
|
||||||
Copyright (c) 2022-2026 happyDomain
|
|
||||||
Authors: Pierre-Olivier Mercier, et al.
|
|
||||||
|
|
||||||
This program is offered under a commercial and under the AGPL license.
|
|
||||||
For commercial licensing, contact us at <contact@happydomain.org>.
|
|
||||||
|
|
||||||
For AGPL licensing:
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { Alert, Icon } from "@sveltestrap/sveltestrap";
|
|
||||||
|
|
||||||
import { t } from "$lib/translations";
|
|
||||||
import type { CheckerScope } from "$lib/api/checkers";
|
|
||||||
import { getCheckStatus, getScopedExecutionResults } from "$lib/api/checkers";
|
|
||||||
import PageTitle from "$lib/components/PageTitle.svelte";
|
|
||||||
import ExecutionResultsCard from "./ExecutionResultsCard.svelte";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
scope: CheckerScope;
|
|
||||||
checkerId: string;
|
|
||||||
execId: string;
|
|
||||||
domainName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { scope, checkerId, execId, domainName }: Props = $props();
|
|
||||||
|
|
||||||
let resultsPromise = $derived(getScopedExecutionResults(scope, checkerId, execId));
|
|
||||||
let checkerName = $state<string>("");
|
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
getCheckStatus(checkerId).then((s) => {
|
|
||||||
checkerName = s.name ?? checkerId;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:head>
|
|
||||||
<title>{$t("checkers.detail.check-rules")} - {checkerName || checkerId} - happyDomain</title>
|
|
||||||
</svelte:head>
|
|
||||||
|
|
||||||
<div class="flex-fill mt-1 mb-5">
|
|
||||||
<PageTitle title={$t("checkers.detail.check-rules")} subtitle={checkerName} domain={domainName} />
|
|
||||||
|
|
||||||
{#await resultsPromise}
|
|
||||||
<p class="text-center">
|
|
||||||
<span class="spinner-border spinner-border-sm me-2"></span>
|
|
||||||
{$t("checkers.result.loading")}
|
|
||||||
</p>
|
|
||||||
{:then evaluation}
|
|
||||||
{#if evaluation}
|
|
||||||
<ExecutionResultsCard {evaluation} />
|
|
||||||
{:else}
|
|
||||||
<Alert color="info">
|
|
||||||
<Icon name="info-circle" />
|
|
||||||
{$t("checkers.result.no-results")}
|
|
||||||
</Alert>
|
|
||||||
{/if}
|
|
||||||
{:catch error}
|
|
||||||
<Alert color="danger">
|
|
||||||
<Icon name="exclamation-triangle-fill" />
|
|
||||||
{$t("checkers.result.error-loading", { error: error.message })}
|
|
||||||
</Alert>
|
|
||||||
{/await}
|
|
||||||
</div>
|
|
||||||
|
|
@ -161,17 +161,10 @@
|
||||||
{/if}
|
{/if}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{$t("checkers.result.field.status")}</th>
|
<th>{$t("checkers.result.field.status")}</th>
|
||||||
<td class="d-flex gap-2 align-items-center">
|
<td>
|
||||||
<Badge color={getStatusColor($currentExecution.result?.status)}>
|
<Badge color={getStatusColor($currentExecution.result?.status)}>
|
||||||
{$t(getStatusI18nKey($currentExecution.result?.status))}
|
{$t(getStatusI18nKey($currentExecution.result?.status))}
|
||||||
</Badge>
|
</Badge>
|
||||||
<a
|
|
||||||
href="{checksBase}/{encodeURIComponent(
|
|
||||||
checkerId,
|
|
||||||
)}/executions/{encodeURIComponent(execId)}/rules"
|
|
||||||
>
|
|
||||||
{$t("checkers.detail.check-rules")}
|
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{#if $currentExecution.result?.message}
|
{#if $currentExecution.result?.message}
|
||||||
|
|
@ -232,6 +225,18 @@
|
||||||
{$t("checkers.result.view-html")}
|
{$t("checkers.result.view-html")}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
color="secondary"
|
||||||
|
outline
|
||||||
|
active={$reportViewMode === "rules"}
|
||||||
|
onclick={() => {
|
||||||
|
reportViewMode.set("rules");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon name="list-check"></Icon>
|
||||||
|
{$t("checkers.detail.check-rules")}
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
|
|
||||||
|
|
@ -609,8 +609,9 @@
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"card-title": "Automatic scheduling",
|
"card-title": "Automatic scheduling",
|
||||||
"interval-label": "Check interval",
|
"interval-label": "Check interval",
|
||||||
|
"minutes": "minutes",
|
||||||
"hours": "hours",
|
"hours": "hours",
|
||||||
"interval-hint": "Minimum 1 hour. The check will run once per interval.",
|
"interval-hint": "Between {{intervalMin}} and {{intervalMax}}. Default: {{intervalDefault}}. The check will run once per interval.",
|
||||||
"no-schedule-yet": "No schedule created yet. Save to create one.",
|
"no-schedule-yet": "No schedule created yet. Save to create one.",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"save-failed": "Failed to save schedule",
|
"save-failed": "Failed to save schedule",
|
||||||
|
|
@ -711,7 +712,7 @@
|
||||||
"name": "Name:",
|
"name": "Name:",
|
||||||
"availability": "Availability:",
|
"availability": "Availability:",
|
||||||
"loading-options": "Loading options...",
|
"loading-options": "Loading options...",
|
||||||
"check-rules": "Check Individual Rules",
|
"check-rules": "Rules",
|
||||||
"admin-options": "Admin Options",
|
"admin-options": "Admin Options",
|
||||||
"configuration": "Configuration",
|
"configuration": "Configuration",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export const currentCheckInfo: Writable<CheckerCheckerDefinition | undefined> =
|
||||||
export const currentObservations: Writable<ObservationSnapshotWithData | undefined> = writable(undefined);
|
export const currentObservations: Writable<ObservationSnapshotWithData | undefined> = writable(undefined);
|
||||||
|
|
||||||
// Report view mode: which panel the main area shows
|
// Report view mode: which panel the main area shows
|
||||||
export type ReportViewMode = "json" | "html" | "metrics";
|
export type ReportViewMode = "json" | "html" | "metrics" | "rules";
|
||||||
export const reportViewMode: Writable<ReportViewMode> = writable("json");
|
export const reportViewMode: Writable<ReportViewMode> = writable("json");
|
||||||
export const showHTMLReport: Readable<boolean> = derived(reportViewMode, ($m) => $m === "html");
|
export const showHTMLReport: Readable<boolean> = derived(reportViewMode, ($m) => $m === "html");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@ interface Params {
|
||||||
error?: string;
|
error?: string;
|
||||||
options?: string;
|
options?: string;
|
||||||
key?: string;
|
key?: string;
|
||||||
|
intervalMin?: string;
|
||||||
|
intervalMax?: string;
|
||||||
|
intervalDefault?: string;
|
||||||
// add more parameters that are used here
|
// add more parameters that are used here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
<!--
|
|
||||||
This file is part of the happyDomain (R) project.
|
|
||||||
Copyright (c) 2022-2026 happyDomain
|
|
||||||
Authors: Pierre-Olivier Mercier, et al.
|
|
||||||
|
|
||||||
This program is offered under a commercial and under the AGPL license.
|
|
||||||
For commercial licensing, contact us at <contact@happydomain.org>.
|
|
||||||
|
|
||||||
For AGPL licensing:
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { page } from "$app/state";
|
|
||||||
|
|
||||||
import type { Domain } from "$lib/model/domain";
|
|
||||||
import { fqdn } from "$lib/dns";
|
|
||||||
import ExecutionRulesPage from "$lib/components/checkers/ExecutionRulesPage.svelte";
|
|
||||||
|
|
||||||
let domain: Domain = $derived(page.data.domain);
|
|
||||||
let zoneId: string = $derived(page.data.zoneId);
|
|
||||||
let subdomain: string = $derived(page.data.subdomain);
|
|
||||||
let serviceid: string = $derived(page.data.serviceid);
|
|
||||||
let checkerId = $derived(page.params.checkerId!);
|
|
||||||
let execId = $derived(page.params.execId!);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<ExecutionRulesPage
|
|
||||||
scope={{ domainId: domain.id, zoneId, subdomain, serviceId: serviceid }}
|
|
||||||
{checkerId}
|
|
||||||
{execId}
|
|
||||||
domainName={fqdn(subdomain, domain.domain)}
|
|
||||||
/>
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<!--
|
|
||||||
This file is part of the happyDomain (R) project.
|
|
||||||
Copyright (c) 2022-2026 happyDomain
|
|
||||||
Authors: Pierre-Olivier Mercier, et al.
|
|
||||||
|
|
||||||
This program is offered under a commercial and under the AGPL license.
|
|
||||||
For commercial licensing, contact us at <contact@happydomain.org>.
|
|
||||||
|
|
||||||
For AGPL licensing:
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { page } from "$app/state";
|
|
||||||
|
|
||||||
import type { Domain } from "$lib/model/domain";
|
|
||||||
import ExecutionRulesPage from "$lib/components/checkers/ExecutionRulesPage.svelte";
|
|
||||||
|
|
||||||
let domain: Domain = $derived(page.data.domain);
|
|
||||||
let checkerId = $derived(page.params.checkerId!);
|
|
||||||
let execId = $derived(page.params.execId!);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<ExecutionRulesPage
|
|
||||||
scope={{ domainId: domain.id }}
|
|
||||||
{checkerId}
|
|
||||||
{execId}
|
|
||||||
domainName={domain.domain}
|
|
||||||
/>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue