Feature: Technitium DNS Widget (#3904)

---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
pull/3915/head
Bobby Driggs 2 months ago committed by GitHub
parent e2518b37d9
commit 4c6150a545
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -113,6 +113,7 @@ You can also find a list of all available service widgets in the sidebar navigat
- [Syncthing Relay Server](syncthing-relay-server.md)
- [Tailscale](tailscale.md)
- [Tandoor](tandoor.md)
- [Technitium DNS](technitium.md)
- [TDarr](tdarr.md)
- [Traefik](traefik.md)
- [Transmission](transmission.md)

@ -0,0 +1,26 @@
---
title: Technitium DNS Server
description: Technitium DNS Server Widget Configuration
---
Learn more about [Technitium DNS Server](https://technitium.com/dns/).
Allowed fields (up to 4): `["totalQueries","totalNoError","totalServerFailure","totalNxDomain","totalRefused","totalAuthoritative","totalRecursive","totalCached","totalBlocked","totalDropped","totalClients"]`.
Defaults to: `["totalQueries", "totalAuthoritative", "totalCached", "totalServerFailure"]`
```yaml
widget:
type: technitium
url: <url to dns server>
key: biglongapitoken
range: LastDay # optional, defaults to LastHour
```
#### API Key
This can be generated via the Technitium DNS Dashboard, and should be generated from a special API specific user.
#### Range
`range` value determines how far back of statistics to pull data for. The value comes directly from Technitium API documentation found [here](https://github.com/TechnitiumSoftware/DnsServer/blob/master/APIDOCS.md#dashboard-api-calls), defined as `"type"`. The value can be one of: `LastHour`, `LastDay`, `LastWeek`, `LastMonth`, `LastYear`.

@ -137,6 +137,7 @@ nav:
- widgets/services/syncthing-relay-server.md
- widgets/services/tailscale.md
- widgets/services/tandoor.md
- widgets/services/technitium.md
- widgets/services/tdarr.md
- widgets/services/traefik.md
- widgets/services/transmission.md

@ -323,6 +323,19 @@
"seconds": "{{number}}s",
"ago": "{{value}} Ago"
},
"technitium": {
"totalQueries": "Queries",
"totalNoError": "Success",
"totalServerFailure": "Failures",
"totalNxDomain": "NX Domains",
"totalRefused": "Refused",
"totalAuthoritative": "Authoritative",
"totalRecursive": "Recursive",
"totalCached": "Cached",
"totalBlocked": "Blocked",
"totalDropped": "Dropped",
"totalClients": "Clients"
},
"tdarr": {
"queue": "Queue",
"processed": "Processed",

@ -473,6 +473,9 @@ export function cleanServiceGroups(groups) {
// wgeasy
threshold,
// technitium
range,
} = cleanedService.widget;
let fieldsList = fields;
@ -617,6 +620,9 @@ export function cleanServiceGroups(groups) {
if (type === "frigate") {
if (enableRecentEvents !== undefined) cleanedService.widget.enableRecentEvents = enableRecentEvents;
}
if (type === "technitium") {
if (range !== undefined) cleanedService.widget.range = range;
}
}
return cleanedService;

@ -112,6 +112,7 @@ const components = {
tailscale: dynamic(() => import("./tailscale/component")),
tandoor: dynamic(() => import("./tandoor/component")),
tautulli: dynamic(() => import("./tautulli/component")),
technitium: dynamic(() => import("./technitium/component")),
tdarr: dynamic(() => import("./tdarr/component")),
traefik: dynamic(() => import("./traefik/component")),
transmission: dynamic(() => import("./transmission/component")),

@ -0,0 +1,121 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
const MAX_ALLOWED_FIELDS = 4;
export const technitiumDefaultFields = ["totalQueries", "totalAuthoritative", "totalCached", "totalServerFailure"];
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const params = {
type: widget.range ?? "LastHour",
};
const { data: statsData, error: statsError } = useWidgetAPI(widget, "stats", params);
// Default fields
if (!widget.fields?.length > 0) {
widget.fields = technitiumDefaultFields;
}
// Limits max number of displayed fields
if (widget.fields?.length > MAX_ALLOWED_FIELDS) {
widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS);
}
if (statsError) {
return <Container service={service} error={statsError} />;
}
if (!statsData) {
return (
<Container service={service}>
<Block label="technitium.totalQueries" />
<Block label="technitium.totalNoError" />
<Block label="technitium.totalServerFailure" />
<Block label="technitium.totalNxDomain" />
<Block label="technitium.totalRefused" />
<Block label="technitium.totalAuthoritative" />
<Block label="technitium.totalRecursive" />
<Block label="technitium.totalCached" />
<Block label="technitium.totalBlocked" />
<Block label="technitium.totalDropped" />
<Block label="technitium.totalClients" />
</Container>
);
}
function toPercent(value, total) {
return t("common.percent", {
value: !Number.isNaN(value / total) ? value / total : 0,
maximumFractionDigits: 2,
});
}
return (
<Container service={service}>
<Block label="technitium.totalQueries" value={`${t("common.number", { value: statsData.totalQueries })}`} />
<Block
label="technitium.totalNoError"
value={`${t("common.number", { value: statsData.totalNoError })} (${toPercent(
statsData.totalNoError / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalServerFailure"
value={`${t("common.number", { value: statsData.totalServerFailure })} (${toPercent(
statsData.totalServerFailure / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalNxDomain"
value={`${t("common.number", { value: statsData.totalNxDomain })} (${toPercent(
statsData.totalNxDomain / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalRefused"
value={`${t("common.number", { value: statsData.totalRefused })} (${toPercent(
statsData.totalRefused / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalAuthoritative"
value={`${t("common.number", { value: statsData.totalAuthoritative })} (${toPercent(
statsData.totalAuthoritative / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalRecursive"
value={`${t("common.number", { value: statsData.totalRecursive })} (${toPercent(
statsData.totalRecursive / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalCached"
value={`${t("common.number", { value: statsData.totalCached })} (${toPercent(
statsData.totalCached / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalBlocked"
value={`${t("common.number", { value: statsData.totalBlocked })} (${toPercent(
statsData.totalBlocked / statsData.totalQueries,
)})`}
/>
<Block
label="technitium.totalDropped"
value={`${t("common.number", { value: statsData.totalDropped })} (${toPercent(
statsData.totalDropped / statsData.totalQueries,
)})`}
/>
<Block label="technitium.totalClients" value={`${t("common.number", { value: statsData.totalClients })}`} />
</Container>
);
}

@ -0,0 +1,17 @@
import genericProxyHandler from "utils/proxy/handlers/generic";
import { asJson } from "utils/proxy/api-helpers";
const widget = {
api: "{url}/api/{endpoint}?token={key}&utc=true",
proxyHandler: genericProxyHandler,
mappings: {
stats: {
endpoint: "dashboard/stats/get",
validate: ["response", "status"],
params: ["type"],
map: (data) => asJson(data).response.stats,
},
},
};
export default widget;

@ -103,6 +103,7 @@ import swagdashboard from "./swagdashboard/widget";
import tailscale from "./tailscale/widget";
import tandoor from "./tandoor/widget";
import tautulli from "./tautulli/widget";
import technitium from "./technitium/widget";
import tdarr from "./tdarr/widget";
import traefik from "./traefik/widget";
import transmission from "./transmission/widget";
@ -228,6 +229,7 @@ const widgets = {
tailscale,
tandoor,
tautulli,
technitium,
tdarr,
traefik,
transmission,

Loading…
Cancel
Save