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-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-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/go.mod h1:aNAcfYFfbhvH9kJhE0Njp5GX0dQbxdRB0rJ0KvSC5nI=
|
||||
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 savingOptions = $state(false);
|
||||
|
||||
let checkerDef = $derived($checkers?.[checkerId]);
|
||||
let intervalSpec = $derived(checkerDef?.interval);
|
||||
|
||||
let plan = $state<HappydnsCheckPlanWritable>({
|
||||
enabled: {},
|
||||
interval: 3600,
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
|
|
@ -142,7 +144,7 @@
|
|||
<Row class="mb-4">
|
||||
{#if showSchedule}
|
||||
<Col md={6}>
|
||||
<CheckerScheduleCard {scope} {checkerId} bind:plan />
|
||||
<CheckerScheduleCard {scope} {checkerId} bind:plan {intervalSpec} />
|
||||
|
||||
{#if status.rules && status.rules.length > 0}
|
||||
<CheckerRulesCard
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
Input,
|
||||
Label,
|
||||
} 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 { toasts } from "$lib/stores/toasts";
|
||||
import type { CheckerScope } from "$lib/api/checkers";
|
||||
|
|
@ -43,17 +43,31 @@
|
|||
updateScopedCheckPlan,
|
||||
} from "$lib/api/checkers";
|
||||
|
||||
const NS_PER_MINUTE = 60_000_000_000;
|
||||
const NS_PER_HOUR = 3_600_000_000_000;
|
||||
|
||||
interface Props {
|
||||
scope: CheckerScope;
|
||||
checkerId: string;
|
||||
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 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));
|
||||
|
||||
$effect(() => {
|
||||
|
|
@ -63,7 +77,7 @@
|
|||
existingPlanId = s.id;
|
||||
plan = {
|
||||
enabled: s.enabled ?? {},
|
||||
interval: s.interval ?? 3600,
|
||||
interval: s.interval ?? defaultIntervalNs,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
@ -97,12 +111,31 @@
|
|||
}
|
||||
}
|
||||
|
||||
function intervalHours(): number {
|
||||
return Math.round((plan.interval ?? 3600) / 3600);
|
||||
function intervalDisplayValue(): number {
|
||||
return Math.round((plan.interval ?? defaultIntervalNs) / unitNs);
|
||||
}
|
||||
|
||||
function setIntervalHours(hours: number) {
|
||||
plan.interval = Math.max(3600, hours * 3600);
|
||||
function setIntervalValue(val: number) {
|
||||
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>
|
||||
|
||||
|
|
@ -125,15 +158,22 @@
|
|||
<div class="d-flex align-items-center gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
min={1}
|
||||
value={intervalHours()}
|
||||
min={Math.round(minNs / unitNs)}
|
||||
max={Math.round(maxNs / unitNs)}
|
||||
value={intervalDisplayValue()}
|
||||
oninput={(e: Event) =>
|
||||
setIntervalHours(parseInt((e.target as HTMLInputElement).value) || 1)}
|
||||
setIntervalValue(parseInt((e.target as HTMLInputElement).value) || 1)}
|
||||
style="width: 100px"
|
||||
/>
|
||||
<span>{$t("checkers.schedule.hours")}</span>
|
||||
<span>{useMinutes ? $t("checkers.schedule.minutes") : $t("checkers.schedule.hours")}</span>
|
||||
</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>
|
||||
</form>
|
||||
|
||||
|
|
|
|||
|
|
@ -27,13 +27,22 @@
|
|||
|
||||
import { t } from "$lib/translations";
|
||||
import type { CheckerScope, CheckMetric } from "$lib/api/checkers";
|
||||
import type { HappydnsCheckEvaluation } from "$lib/api-base/types.gen";
|
||||
import {
|
||||
getScopedExecution,
|
||||
getScopedExecutionObservations,
|
||||
getScopedExecutionMetrics,
|
||||
getScopedExecutionResults,
|
||||
getCheckStatus,
|
||||
} 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";
|
||||
|
||||
interface Props {
|
||||
|
|
@ -48,11 +57,13 @@
|
|||
let loading = $state(true);
|
||||
let error = $state<string | undefined>(undefined);
|
||||
let metricsData = $state<CheckMetric[] | null>(null);
|
||||
let evaluationData = $state<HappydnsCheckEvaluation | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
loading = true;
|
||||
error = undefined;
|
||||
metricsData = null;
|
||||
evaluationData = null;
|
||||
cachedHTMLReport.set(null);
|
||||
|
||||
Promise.all([
|
||||
|
|
@ -65,7 +76,11 @@
|
|||
currentCheckInfo.set(checkerInfo);
|
||||
currentObservations.set(observations);
|
||||
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) {
|
||||
reportViewMode.set("metrics");
|
||||
getScopedExecutionMetrics(scope, checkerId, execId)
|
||||
|
|
@ -74,7 +89,7 @@
|
|||
} else if (checkerInfo.has_html_report) {
|
||||
reportViewMode.set("html");
|
||||
} else {
|
||||
reportViewMode.set("json");
|
||||
reportViewMode.set("rules");
|
||||
}
|
||||
loading = false;
|
||||
},
|
||||
|
|
@ -114,6 +129,10 @@
|
|||
{$t("checkers.result.error-loading", { error })}
|
||||
</Alert>
|
||||
</Container>
|
||||
{:else if $reportViewMode === "rules" && evaluationData}
|
||||
<Container class="flex-fill d-flex flex-column mt-3">
|
||||
<ExecutionResultsCard evaluation={evaluationData} />
|
||||
</Container>
|
||||
{:else if $currentObservations}
|
||||
<ObservationReportCard
|
||||
observations={$currentObservations}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
let metricsData = $state<CheckMetric[] | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
metricsData = null;
|
||||
getCheckStatus(checkerId).then((s) => {
|
||||
resolvedName = s.name ?? checkerId;
|
||||
if (s.has_metrics) {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@
|
|||
-->
|
||||
|
||||
<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 type { HappydnsCheckEvaluation } from "$lib/api-base/types.gen";
|
||||
import { getStatusColor, getStatusI18nKey } from "$lib/utils";
|
||||
|
||||
interface Props {
|
||||
evaluation: HappydnsCheckEvaluation;
|
||||
|
|
@ -40,10 +41,11 @@
|
|||
</CardHeader>
|
||||
<CardBody>
|
||||
{#if evaluation.states && evaluation.states.length > 0}
|
||||
<Table size="sm" borderless>
|
||||
<Table class="mb-0" size="sm" borderless hover>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{$t("checkers.result.field.rule")}</th>
|
||||
<th>{$t("checkers.result.field.status")}</th>
|
||||
<th>{$t("checkers.result.field.message")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -51,6 +53,7 @@
|
|||
{#each evaluation.states as state}
|
||||
<tr>
|
||||
<td><code>{state.code ?? ""}</code></td>
|
||||
<td><Badge color={getStatusColor(state.status)}>{$t(getStatusI18nKey(state.status))}</Badge></td>
|
||||
<td>{state.message ?? ""}</td>
|
||||
</tr>
|
||||
{/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}
|
||||
<tr>
|
||||
<th>{$t("checkers.result.field.status")}</th>
|
||||
<td class="d-flex gap-2 align-items-center">
|
||||
<td>
|
||||
<Badge color={getStatusColor($currentExecution.result?.status)}>
|
||||
{$t(getStatusI18nKey($currentExecution.result?.status))}
|
||||
</Badge>
|
||||
<a
|
||||
href="{checksBase}/{encodeURIComponent(
|
||||
checkerId,
|
||||
)}/executions/{encodeURIComponent(execId)}/rules"
|
||||
>
|
||||
{$t("checkers.detail.check-rules")}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{#if $currentExecution.result?.message}
|
||||
|
|
@ -232,6 +225,18 @@
|
|||
{$t("checkers.result.view-html")}
|
||||
</Button>
|
||||
{/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
|
||||
size="sm"
|
||||
color="secondary"
|
||||
|
|
|
|||
|
|
@ -609,8 +609,9 @@
|
|||
"schedule": {
|
||||
"card-title": "Automatic scheduling",
|
||||
"interval-label": "Check interval",
|
||||
"minutes": "minutes",
|
||||
"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.",
|
||||
"save": "Save",
|
||||
"save-failed": "Failed to save schedule",
|
||||
|
|
@ -711,7 +712,7 @@
|
|||
"name": "Name:",
|
||||
"availability": "Availability:",
|
||||
"loading-options": "Loading options...",
|
||||
"check-rules": "Check Individual Rules",
|
||||
"check-rules": "Rules",
|
||||
"admin-options": "Admin Options",
|
||||
"configuration": "Configuration",
|
||||
"save": "Save",
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export const currentCheckInfo: Writable<CheckerCheckerDefinition | undefined> =
|
|||
export const currentObservations: Writable<ObservationSnapshotWithData | undefined> = writable(undefined);
|
||||
|
||||
// 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 showHTMLReport: Readable<boolean> = derived(reportViewMode, ($m) => $m === "html");
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ interface Params {
|
|||
error?: string;
|
||||
options?: string;
|
||||
key?: string;
|
||||
intervalMin?: string;
|
||||
intervalMax?: string;
|
||||
intervalDefault?: string;
|
||||
// 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