diff --git a/public/locales/en/modules/dns-hole-controls.json b/public/locales/en/modules/dns-hole-controls.json
index 279931f04..2059f802a 100644
--- a/public/locales/en/modules/dns-hole-controls.json
+++ b/public/locales/en/modules/dns-hole-controls.json
@@ -7,6 +7,12 @@
"showToggleAllButtons": {
"label": "Show 'Enable/Disable All' Buttons"
}
+ },
+ "errors": {
+ "general": {
+ "title": "Unable to find a DNS hole",
+ "text": "There was a problem connecting to your DNS Hole(s). Please verify your configuration/integration(s)."
+ }
}
}
}
\ No newline at end of file
diff --git a/src/server/api/routers/dns-hole/router.ts b/src/server/api/routers/dns-hole/router.ts
index 6de3f91a3..8c7f73553 100644
--- a/src/server/api/routers/dns-hole/router.ts
+++ b/src/server/api/routers/dns-hole/router.ts
@@ -62,22 +62,24 @@ export const dnsHoleRouter = createTRPCRouter({
)
);
- const data = result.reduce(
- (prev: AdStatistics, curr) => ({
- domainsBeingBlocked: prev.domainsBeingBlocked + curr.domainsBeingBlocked,
- adsBlockedToday: prev.adsBlockedToday + curr.adsBlockedToday,
- dnsQueriesToday: prev.dnsQueriesToday + curr.dnsQueriesToday,
- status: [...prev.status, curr.status],
- adsBlockedTodayPercentage: 0,
- }),
- {
- domainsBeingBlocked: 0,
- adsBlockedToday: 0,
- adsBlockedTodayPercentage: 0,
- dnsQueriesToday: 0,
- status: [],
- }
- );
+ const data = result
+ .filter((x) => x !== null)
+ .reduce(
+ (prev: AdStatistics, curr) => ({
+ domainsBeingBlocked: prev.domainsBeingBlocked + curr!.domainsBeingBlocked,
+ adsBlockedToday: prev.adsBlockedToday + curr!.adsBlockedToday,
+ dnsQueriesToday: prev.dnsQueriesToday + curr!.dnsQueriesToday,
+ status: [...prev.status, curr!.status],
+ adsBlockedTodayPercentage: 0,
+ }),
+ {
+ domainsBeingBlocked: 0,
+ adsBlockedToday: 0,
+ adsBlockedTodayPercentage: 0,
+ dnsQueriesToday: 0,
+ status: [],
+ }
+ );
data.adsBlockedTodayPercentage = data.adsBlockedToday / data.dnsQueriesToday;
if (Number.isNaN(data.adsBlockedTodayPercentage)) {
@@ -131,7 +133,13 @@ const processPiHole = async (app: ConfigAppType, enable: boolean) => {
const collectPiHoleSummary = async (app: ConfigAppType) => {
const piHole = new PiHoleClient(app.url, findAppProperty(app, 'apiKey'));
- const summary = await piHole.getSummary();
+ const summary = await piHole.getSummary().catch(() => {
+ return null;
+ });
+
+ if (!summary) {
+ return null;
+ }
return {
domainsBeingBlocked: summary.domains_being_blocked,
@@ -152,7 +160,14 @@ const collectAdGuardSummary = async (app: ConfigAppType) => {
findAppProperty(app, 'password')
);
- const stats = await adGuard.getStats();
+ const stats = await adGuard.getStats().catch(() => {
+ return null;
+ });
+
+ if (!stats) {
+ return null;
+ }
+
const status = await adGuard.getStatus();
const countFilteredDomains = await adGuard.getCountFilteringDomains();
diff --git a/src/tools/server/sdk/adGuard/adGuard.schema.ts b/src/tools/server/sdk/adGuard/adGuard.schema.ts
index a2c843062..556db1ffb 100644
--- a/src/tools/server/sdk/adGuard/adGuard.schema.ts
+++ b/src/tools/server/sdk/adGuard/adGuard.schema.ts
@@ -32,7 +32,7 @@ export const adGuardApiStatusResponseSchema = z.object({
export const adGuardApiFilteringStatusSchema = z.object({
filters: z.array(
z.object({
- url: z.string().url(),
+ url: z.string(),
name: z.string(),
last_updated: z.string().optional(),
id: z.number().nonnegative(),
diff --git a/src/widgets/dnshole/DnsHoleControls.tsx b/src/widgets/dnshole/DnsHoleControls.tsx
index 664088088..d8285001b 100644
--- a/src/widgets/dnshole/DnsHoleControls.tsx
+++ b/src/widgets/dnshole/DnsHoleControls.tsx
@@ -3,11 +3,13 @@ import {
Box,
Button,
Card,
+ Center,
Group,
Image,
SimpleGrid,
Stack,
Text,
+ Title,
UnstyledButton,
} from '@mantine/core';
import { useElementSize } from '@mantine/hooks';
@@ -71,7 +73,7 @@ function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
const { isInitialLoading, data, isFetching: fetchingDnsSummary } = useDnsHoleSummeryQuery();
const { mutateAsync, isLoading: changingStatus } = useDnsHoleControlMutation();
const { width, ref } = useElementSize();
- const { t } = useTranslation('common');
+ const { t } = useTranslation(['common', 'modules/dns-hole-controls']);
const { name: configName, config } = useConfigContext();
@@ -81,6 +83,20 @@ function DnsHoleControlsWidgetTile({ widget }: DnsHoleControlsWidgetProps) {
return