diff --git a/web-admin/routes.go b/web-admin/routes.go index f3ab3f32..b3e92d71 100644 --- a/web-admin/routes.go +++ b/web-admin/routes.go @@ -110,6 +110,7 @@ func DeclareRoutes(cfg *happydns.Options, router *gin.Engine) { // Routes to virtual content router.GET("/auth_users/*_", serveOrReverse("/", cfg)) + router.GET("/checks/*_", serveOrReverse("/", cfg)) router.GET("/domains/*_", serveOrReverse("/", cfg)) router.GET("/providers/*_", serveOrReverse("/", cfg)) router.GET("/sessions/*_", serveOrReverse("/", cfg)) diff --git a/web-admin/src/routes/+layout.svelte b/web-admin/src/routes/+layout.svelte index f28ed70e..b80aee4a 100644 --- a/web-admin/src/routes/+layout.svelte +++ b/web-admin/src/routes/+layout.svelte @@ -101,6 +101,9 @@ Sessions + + Checkers + diff --git a/web-admin/src/routes/checkers/+page.svelte b/web-admin/src/routes/checkers/+page.svelte new file mode 100644 index 00000000..737f7ef5 --- /dev/null +++ b/web-admin/src/routes/checkers/+page.svelte @@ -0,0 +1,150 @@ + + + + + + + +

+ + Checkers +

+

+ Manage all checkers + {#await checkersQ then checkersR} + Total: {Object.keys(checkersR.data ?? {}).length} checkers + {/await} +

+ +
+ + + + + + + + + + + + + {#await checkersQ} + Please wait... + {:then checkersR} + {@const checkers = checkersR.data} +
+ + + + + + + + + + {#if !checkers || Object.keys(checkers).length == 0} + + + + {:else} + {#each Object.entries(checkers ?? {}).filter(([name, _info]) => name + .toLowerCase() + .indexOf(searchQuery.toLowerCase()) > -1) as [checkerName, checkerInfo]} + + + + + + {/each} + {/if} + +
Plugin NameAvailabilityActions
+ No checkers available +
{checkerInfo.name || checkerName} + {#if checkerInfo.availability} + {#if checkerInfo.availability.applyToDomain} + Domain + {/if} + {#if checkerInfo.availability.limitToProviders && checkerInfo.availability.limitToProviders.length > 0} + + Provider-specific + + {/if} + {#if checkerInfo.availability.limitToServices && checkerInfo.availability.limitToServices.length > 0} + + Service-specific + + {/if} + {:else} + General + {/if} + + + + Manage + +
+
+ {:catch error} + +

+ + Error loading checkers: {error.message} +

+
+ {/await} +
diff --git a/web-admin/src/routes/checkers/[cname]/+page.svelte b/web-admin/src/routes/checkers/[cname]/+page.svelte new file mode 100644 index 00000000..9012cd02 --- /dev/null +++ b/web-admin/src/routes/checkers/[cname]/+page.svelte @@ -0,0 +1,322 @@ + + + + + + + + +

+ + {cname} +

+ +
+ + {#await checkerStatusQ} + +

+ + Loading checker status... +

+
+ {:then status} + {#if status} + + + + + Checker Information + + +
+
Name:
+
{status.name}
+ +
Availability:
+
+ {#if status.availableOn} +
+ {#if status.availableOn.applyToDomain} + Domain-level + {/if} + {#if status.availableOn.limitToProviders && status.availableOn.limitToProviders.length > 0} + + Providers: {status.availableOn.limitToProviders.join( + ", ", + )} + + {/if} + {#if status.availableOn.limitToServices && status.availableOn.limitToServices.length > 0} + + Services: {status.availableOn.limitToServices.join( + ", ", + )} + + {/if} + {#if !status.availableOn.applyToDomain && (!status.availableOn.limitToProviders || status.availableOn.limitToProviders.length === 0) && (!status.availableOn.limitToServices || status.availableOn.limitToServices.length === 0)} + General + {/if} +
+ {:else} + General + {/if} +
+
+
+
+ + + + {#await checkerOptionsQ} + + +

+ + Loading options... +

+
+
+ {:then _optionsR} + {@const adminOpts = status.options?.adminOpts || []} + {@const readOnlyOptGroups = [ + { + key: "userOpts", + label: "User Options", + opts: status.options?.userOpts || [], + }, + { + key: "domainOpts", + label: "Domain Options", + opts: status.options?.domainOpts || [], + }, + { + key: "serviceOpts", + label: "Service Options", + opts: status.options?.serviceOpts || [], + }, + { + key: "runOpts", + label: "Run Options", + opts: status.options?.runOpts || [], + }, + ]} + {@const hasAnyOpts = + adminOpts.length > 0 || + readOnlyOptGroups.some((g) => g.opts.length > 0)} + {@const orphanedOpts = getOrphanedOptions(adminOpts)} + + {#if orphanedOpts.length > 0} + +
+
+ + Orphaned options detected: + {orphanedOpts.join(", ")} +
+ +
+
+ {/if} + + {#if adminOpts.length > 0} + + + Admin Options + + +
+ {#each adminOpts as optDoc} + {#if optDoc.id} + {@const optName = optDoc.id} + + + + {/if} + {/each} +
+ +
+
+
+
+ {/if} + + + + {#if !hasAnyOpts} + + + + + This checker has no configurable options. + + + + {/if} + {:catch error} + + + + + Error loading options: {error.message} + + + + {/await} + +
+ {:else} + + + Error: checker data not found + + {/if} + {:catch error} + + + Error loading checker: {error.message} + + {/await} +
diff --git a/web/src/lib/components/checkers/CheckerOptionsGroups.svelte b/web/src/lib/components/checkers/CheckerOptionsGroups.svelte new file mode 100644 index 00000000..03dfee0e --- /dev/null +++ b/web/src/lib/components/checkers/CheckerOptionsGroups.svelte @@ -0,0 +1,84 @@ + + + + +{#each groups as optGroup} + {#if optGroup.opts.length > 0} + + + {optGroup.label} + (Read-only) + + +
+ {#each optGroup.opts as optDoc} + {@const optName = optDoc.id!} +
+ {optDoc.label || optDoc.id}: +
+
+ {#if optDoc.default} + {optDoc.default} + {:else if optDoc.placeholder} + {optDoc.placeholder} + {/if} + {#if optDoc.description} + {optDoc.description} + {/if} + + Type: {optDoc.type || "string"} + + {#if optDoc.required} + Required + {/if} +
+ {/each} +
+
+
+ {/if} +{/each}