From 9b7d6b196fad548cbc9e4c9ee99afff6e8a4bd97 Mon Sep 17 00:00:00 2001
From: Jason Fischer <jazzfisch@outlook.com>
Date: Thu, 29 Sep 2022 21:15:25 -0700
Subject: [PATCH] Allow widget field visibility to be configurable

---
 src/components/services/widget/block.jsx     |  5 +++-
 src/components/services/widget/container.jsx | 15 ++++++++++--
 src/utils/config/service-helpers.js          |  2 ++
 src/widgets/adguard/component.jsx            | 20 ++++++++--------
 src/widgets/authentik/component.jsx          | 16 ++++++-------
 src/widgets/bazarr/component.jsx             | 14 ++++++------
 src/widgets/coinmarketcap/component.jsx      |  6 ++---
 src/widgets/docker/component.jsx             | 20 ++++++++--------
 src/widgets/gotify/component.jsx             | 19 ++++++++++++----
 src/widgets/jackett/component.jsx            | 12 +++++-----
 src/widgets/jellyseerr/component.jsx         | 16 ++++++-------
 src/widgets/lidarr/component.jsx             | 16 ++++++-------
 src/widgets/mastodon/component.jsx           | 16 ++++++-------
 src/widgets/npm/component.jsx                | 16 ++++++-------
 src/widgets/nzbget/component.jsx             | 16 ++++++-------
 src/widgets/ombi/component.jsx               | 16 ++++++-------
 src/widgets/overseerr/component.jsx          | 16 ++++++-------
 src/widgets/pihole/component.jsx             | 16 ++++++-------
 src/widgets/portainer/component.jsx          | 16 ++++++-------
 src/widgets/prowlarr/component.jsx           | 24 ++++++++++----------
 src/widgets/qbittorrent/component.jsx        | 20 ++++++++--------
 src/widgets/radarr/component.jsx             | 16 ++++++-------
 src/widgets/readarr/component.jsx            | 16 ++++++-------
 src/widgets/rutorrent/component.jsx          | 16 ++++++-------
 src/widgets/sabnzbd/component.jsx            | 16 ++++++-------
 src/widgets/sonarr/component.jsx             | 16 ++++++-------
 src/widgets/speedtest/component.jsx          | 16 ++++++-------
 src/widgets/strelaysrv/component.jsx         | 16 ++++++-------
 src/widgets/traefik/component.jsx            | 16 ++++++-------
 src/widgets/transmission/component.jsx       | 20 ++++++++--------
 30 files changed, 246 insertions(+), 219 deletions(-)

diff --git a/src/components/services/widget/block.jsx b/src/components/services/widget/block.jsx
index 295330d6..00a50772 100644
--- a/src/components/services/widget/block.jsx
+++ b/src/components/services/widget/block.jsx
@@ -1,6 +1,9 @@
+import { useTranslation } from "next-i18next";
 import classNames from "classnames";
 
 export default function Block({ value, label }) {
+  const { t } = useTranslation();
+
   return (
     <div
       className={classNames(
@@ -9,7 +12,7 @@ export default function Block({ value, label }) {
       )}
     >
       <div className="font-thin text-sm">{value === undefined || value === null ? "-" : value}</div>
-      <div className="font-bold text-xs uppercase">{label}</div>
+      <div className="font-bold text-xs uppercase">{t(label)}</div>
     </div>
   );
 }
diff --git a/src/components/services/widget/container.jsx b/src/components/services/widget/container.jsx
index deb5fdc2..6aa9aad0 100644
--- a/src/components/services/widget/container.jsx
+++ b/src/components/services/widget/container.jsx
@@ -1,4 +1,4 @@
-export default function Container({ error = false, children }) {
+export default function Container({ error = false, children, service }) {
   if (error) {
     return (
       <div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1">
@@ -7,5 +7,16 @@ export default function Container({ error = false, children }) {
     );
   }
 
-  return <div className="relative flex flex-row w-full">{children}</div>;
+  let visibleChildren = children;
+  const fields = service?.widget?.fields;
+  const type = service?.widget?.type;
+  if (fields && type) {
+    visibleChildren = children.filter(child => fields.some(field => `${type}.${field}` === child.props?.label));
+  }
+
+  return (
+    <div className="relative flex flex-row w-full">
+      {visibleChildren}
+    </div>
+  );
 }
diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js
index f36e0a56..813972b2 100644
--- a/src/utils/config/service-helpers.js
+++ b/src/utils/config/service-helpers.js
@@ -113,6 +113,7 @@ export function cleanServiceGroups(groups) {
         // whitelisted set of keys to pass to the frontend
         const {
           type, // all widgets
+          fields,
           server, // docker widget
           container,
           currency, // coinmarketcap widget
@@ -121,6 +122,7 @@ export function cleanServiceGroups(groups) {
 
         cleanedService.widget = {
           type,
+          fields: fields || null,
           service_name: service.name,
           service_group: serviceGroup.name,
         };
diff --git a/src/widgets/adguard/component.jsx b/src/widgets/adguard/component.jsx
index dbd67644..0c78113d 100644
--- a/src/widgets/adguard/component.jsx
+++ b/src/widgets/adguard/component.jsx
@@ -17,11 +17,11 @@ export default function Component({ service }) {
 
   if (!adguardData) {
     return (
-      <Container>
-        <Block label={t("adguard.queries")} />
-        <Block label={t("adguard.blocked")} />
-        <Block label={t("adguard.filtered")} />
-        <Block label={t("adguard.latency")} />
+      <Container service={service}>
+        <Block label="adguard.queries" />
+        <Block label="adguard.blocked" />
+        <Block label="adguard.filtered" />
+        <Block label="adguard.latency" />
       </Container>
     );
   }
@@ -30,12 +30,12 @@ export default function Component({ service }) {
     adguardData.num_replaced_safebrowsing + adguardData.num_replaced_safesearch + adguardData.num_replaced_parental;
 
   return (
-    <Container>
-      <Block label={t("adguard.queries")} value={t("common.number", { value: adguardData.num_dns_queries })} />
-      <Block label={t("adguard.blocked")} value={t("common.number", { value: adguardData.num_blocked_filtering })} />
-      <Block label={t("adguard.filtered")} value={t("common.number", { value: filtered })} />
+    <Container service={service}>
+      <Block label="adguard.queries" value={t("common.number", { value: adguardData.num_dns_queries })} />
+      <Block label="adguard.blocked" value={t("common.number", { value: adguardData.num_blocked_filtering })} />
+      <Block label="adguard.filtered" value={t("common.number", { value: filtered })} />
       <Block
-        label={t("adguard.latency")}
+        label="adguard.latency"
         value={t("common.ms", { value: adguardData.avg_processing_time * 1000, style: "unit", unit: "millisecond" })}
       />
     </Container>
diff --git a/src/widgets/authentik/component.jsx b/src/widgets/authentik/component.jsx
index 7087c205..31f864d1 100644
--- a/src/widgets/authentik/component.jsx
+++ b/src/widgets/authentik/component.jsx
@@ -19,10 +19,10 @@ export default function Component({ service }) {
 
   if (!usersData || !loginsData || !failedLoginsData) {
     return (
-      <Container>
-        <Block label={t("authentik.users")} />
-        <Block label={t("authentik.loginsLast24H")} />
-        <Block label={t("authentik.failedLoginsLast24H")} />
+      <Container service={service}>
+        <Block label="authentik.users" />
+        <Block label="authentik.loginsLast24H" />
+        <Block label="authentik.failedLoginsLast24H" />
       </Container>
     );
   }
@@ -38,10 +38,10 @@ export default function Component({ service }) {
   );
 
   return (
-    <Container>
-      <Block label={t("authentik.users")} value={t("common.number", { value: usersData.pagination.count })} />
-      <Block label={t("authentik.loginsLast24H")} value={t("common.number", { value: loginsLast24H })} />
-      <Block label={t("authentik.failedLoginsLast24H")} value={t("common.number", { value: failedLoginsLast24H })} />
+    <Container service={service}>
+      <Block label="authentik.users" value={t("common.number", { value: usersData.pagination.count })} />
+      <Block label="authentik.loginsLast24H" value={t("common.number", { value: loginsLast24H })} />
+      <Block label="authentik.failedLoginsLast24H" value={t("common.number", { value: failedLoginsLast24H })} />
     </Container>
   );
 }
diff --git a/src/widgets/bazarr/component.jsx b/src/widgets/bazarr/component.jsx
index 921529da..24fef1ce 100644
--- a/src/widgets/bazarr/component.jsx
+++ b/src/widgets/bazarr/component.jsx
@@ -13,22 +13,22 @@ export default function Component({ service }) {
   const { data: moviesData, error: moviesError } = useWidgetAPI(widget, "movies");
 
   if (episodesError || moviesError) {
-    return <Container error={t("widget.api_error")} />;
+    return <Container error="widget.api_error" />;
   }
 
   if (!episodesData || !moviesData) {
     return (
-      <Container>
-        <Block label={t("bazarr.missingEpisodes")} />
-        <Block label={t("bazarr.missingMovies")} />
+      <Container service={service}>
+        <Block label="bazarr.missingEpisodes" />
+        <Block label="bazarr.missingMovies" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("bazarr.missingEpisodes")} value={t("common.number", { value: episodesData.total })} />
-      <Block label={t("bazarr.missingMovies")} value={t("common.number", { value: moviesData.total })} />
+    <Container service={service}>
+      <Block label="bazarr.missingEpisodes" value={t("common.number", { value: episodesData.total })} />
+      <Block label="bazarr.missingMovies" value={t("common.number", { value: moviesData.total })} />
     </Container>
   );
 }
diff --git a/src/widgets/coinmarketcap/component.jsx b/src/widgets/coinmarketcap/component.jsx
index 113eb40e..0b970b31 100644
--- a/src/widgets/coinmarketcap/component.jsx
+++ b/src/widgets/coinmarketcap/component.jsx
@@ -30,7 +30,7 @@ export default function Component({ service }) {
 
   if (!symbols || symbols.length === 0) {
     return (
-      <Container>
+      <Container service={service}>
         <Block value={t("coinmarketcap.configure")} />
       </Container>
     );
@@ -42,7 +42,7 @@ export default function Component({ service }) {
 
   if (!statsData || !dateRange) {
     return (
-      <Container>
+      <Container service={service}>
         <Block value={t("coinmarketcap.configure")} />
       </Container>
     );
@@ -51,7 +51,7 @@ export default function Component({ service }) {
   const { data } = statsData;
 
   return (
-    <Container>
+    <Container service={service}>
       <div className={classNames(service.description ? "-top-10" : "-top-8", "absolute right-1")}>
         <Dropdown options={dateRangeOptions} value={dateRange} setValue={setDateRange} />
       </div>
diff --git a/src/widgets/docker/component.jsx b/src/widgets/docker/component.jsx
index 015a1f25..10e55fcb 100644
--- a/src/widgets/docker/component.jsx
+++ b/src/widgets/docker/component.jsx
@@ -31,23 +31,23 @@ export default function Component({ service }) {
 
   if (!statsData || !statusData) {
     return (
-      <Container>
-        <Block label={t("docker.cpu")} />
-        <Block label={t("docker.mem")} />
-        <Block label={t("docker.rx")} />
-        <Block label={t("docker.tx")} />
+      <Container service={service}>
+        <Block label="docker.cpu" />
+        <Block label="docker.mem" />
+        <Block label="docker.rx" />
+        <Block label="docker.tx" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("docker.cpu")} value={t("common.percent", { value: calculateCPUPercent(statsData.stats) })} />
-      <Block label={t("docker.mem")} value={t("common.bytes", { value: statsData.stats.memory_stats.usage })} />
+    <Container service={service}>
+      <Block label="docker.cpu" value={t("common.percent", { value: calculateCPUPercent(statsData.stats) })} />
+      <Block label="docker.mem" value={t("common.bytes", { value: statsData.stats.memory_stats.usage })} />
       {statsData.stats.networks && (
         <>
-          <Block label={t("docker.rx")} value={t("common.bytes", { value: statsData.stats.networks.eth0.rx_bytes })} />
-          <Block label={t("docker.tx")} value={t("common.bytes", { value: statsData.stats.networks.eth0.tx_bytes })} />
+          <Block label="docker.rx" value={t("common.bytes", { value: statsData.stats.networks.eth0.rx_bytes })} />
+          <Block label="docker.tx" value={t("common.bytes", { value: statsData.stats.networks.eth0.tx_bytes })} />
         </>
       )}
     </Container>
diff --git a/src/widgets/gotify/component.jsx b/src/widgets/gotify/component.jsx
index f12b0e11..40f5793b 100644
--- a/src/widgets/gotify/component.jsx
+++ b/src/widgets/gotify/component.jsx
@@ -17,11 +17,22 @@ export default function Component({ service }) {
     return <Container error={t("widget.api_error")} />;
   }
 
+
+  if (!appsData || !messagesData || !clientsData) {
+    return (
+      <Container service={service}>
+        <Block label="gotify.apps" />
+        <Block label="gotify.clients" />
+        <Block label="gotify.messages" />
+      </Container>
+    );
+  }
+
   return (
-    <Container>
-      <Block label={t("gotify.apps")} value={appsData?.length} />
-      <Block label={t("gotify.clients")} value={clientsData?.length} />
-      <Block label={t("gotify.messages")} value={messagesData?.messages?.length} />
+    <Container service={service}>
+      <Block label="gotify.apps" value={appsData?.length} />
+      <Block label="gotify.clients" value={clientsData?.length} />
+      <Block label="gotify.messages" value={messagesData?.messages?.length} />
     </Container>
   );
 }
diff --git a/src/widgets/jackett/component.jsx b/src/widgets/jackett/component.jsx
index 98f9bc46..9629e266 100644
--- a/src/widgets/jackett/component.jsx
+++ b/src/widgets/jackett/component.jsx
@@ -17,9 +17,9 @@ export default function Component({ service }) {
 
   if (!indexersData) {
     return (
-      <Container>
-        <Block label={t("jackett.configured")} />
-        <Block label={t("jackett.errored")} />
+      <Container service={service}>
+        <Block label="jackett.configured" />
+        <Block label="jackett.errored" />
       </Container>
     );
   }
@@ -27,9 +27,9 @@ export default function Component({ service }) {
   const errored = indexersData.filter((indexer) => indexer.last_error);
 
   return (
-    <Container>
-      <Block label={t("jackett.configured")} value={t("common.number", { value: indexersData.length })} />
-      <Block label={t("jackett.errored")} value={t("common.number", { value: errored.length })} />
+    <Container service={service}>
+      <Block label="jackett.configured" value={t("common.number", { value: indexersData.length })} />
+      <Block label="jackett.errored" value={t("common.number", { value: errored.length })} />
     </Container>
   );
 }
diff --git a/src/widgets/jellyseerr/component.jsx b/src/widgets/jellyseerr/component.jsx
index 9e685f64..217e406e 100644
--- a/src/widgets/jellyseerr/component.jsx
+++ b/src/widgets/jellyseerr/component.jsx
@@ -17,19 +17,19 @@ export default function Component({ service }) {
 
   if (!statsData) {
     return (
-      <Container>
-        <Block label={t("jellyseerr.pending")} />
-        <Block label={t("jellyseerr.approved")} />
-        <Block label={t("jellyseerr.available")} />
+      <Container service={service}>
+        <Block label="jellyseerr.pending" />
+        <Block label="jellyseerr.approved" />
+        <Block label="jellyseerr.available" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("jellyseerr.pending")} value={statsData.pending} />
-      <Block label={t("jellyseerr.approved")} value={statsData.approved} />
-      <Block label={t("jellyseerr.available")} value={statsData.available} />
+    <Container service={service}>
+      <Block label="jellyseerr.pending" value={statsData.pending} />
+      <Block label="jellyseerr.approved" value={statsData.approved} />
+      <Block label="jellyseerr.available" value={statsData.available} />
     </Container>
   );
 }
diff --git a/src/widgets/lidarr/component.jsx b/src/widgets/lidarr/component.jsx
index 96df170e..343760e7 100644
--- a/src/widgets/lidarr/component.jsx
+++ b/src/widgets/lidarr/component.jsx
@@ -19,19 +19,19 @@ export default function Component({ service }) {
 
   if (!albumsData || !wantedData || !queueData) {
     return (
-      <Container>
-        <Block label={t("lidarr.wanted")} />
-        <Block label={t("lidarr.queued")} />
-        <Block label={t("lidarr.albums")} />
+      <Container service={service}>
+        <Block label="lidarr.wanted" />
+        <Block label="lidarr.queued" />
+        <Block label="lidarr.albums" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("lidarr.wanted")} value={t("common.number", { value: wantedData.totalRecords })} />
-      <Block label={t("lidarr.queued")} value={t("common.number", { value: queueData.totalCount })} />
-      <Block label={t("lidarr.albums")} value={t("common.number", { value: albumsData.have })} />
+    <Container service={service}>
+      <Block label="lidarr.wanted" value={t("common.number", { value: wantedData.totalRecords })} />
+      <Block label="lidarr.queued" value={t("common.number", { value: queueData.totalCount })} />
+      <Block label="lidarr.albums" value={t("common.number", { value: albumsData.have })} />
     </Container>
   );
 }
diff --git a/src/widgets/mastodon/component.jsx b/src/widgets/mastodon/component.jsx
index aa1dad01..ec12fca1 100644
--- a/src/widgets/mastodon/component.jsx
+++ b/src/widgets/mastodon/component.jsx
@@ -17,19 +17,19 @@ export default function Component({ service }) {
 
   if (!statsData) {
     return (
-      <Container>
-        <Block label={t("mastodon.user_count")} />
-        <Block label={t("mastodon.status_count")} />
-        <Block label={t("mastodon.domain_count")} />
+      <Container service={service}>
+        <Block label="mastodon.user_count" />
+        <Block label="mastodon.status_count" />
+        <Block label="mastodon.domain_count" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("mastodon.user_count")} value={t("common.number", { value: statsData.stats.user_count })} />
-      <Block label={t("mastodon.status_count")} value={t("common.number", { value: statsData.stats.status_count })} />
-      <Block label={t("mastodon.domain_count")} value={t("common.number", { value: statsData.stats.domain_count })} />
+    <Container service={service}>
+      <Block label="mastodon.user_count" value={t("common.number", { value: statsData.stats.user_count })} />
+      <Block label="mastodon.status_count" value={t("common.number", { value: statsData.stats.status_count })} />
+      <Block label="mastodon.domain_count" value={t("common.number", { value: statsData.stats.domain_count })} />
     </Container>
   );
 }
diff --git a/src/widgets/npm/component.jsx b/src/widgets/npm/component.jsx
index 518fc3eb..b35e27c8 100644
--- a/src/widgets/npm/component.jsx
+++ b/src/widgets/npm/component.jsx
@@ -17,10 +17,10 @@ export default function Component({ service }) {
 
   if (!infoData) {
     return (
-      <Container>
-        <Block label={t("npm.enabled")} />
-        <Block label={t("npm.disabled")} />
-        <Block label={t("npm.total")} />
+      <Container service={service}>
+        <Block label="npm.enabled" />
+        <Block label="npm.disabled" />
+        <Block label="npm.total" />
       </Container>
     );
   }
@@ -30,10 +30,10 @@ export default function Component({ service }) {
   const total = infoData.length;
 
   return (
-    <Container>
-      <Block label={t("npm.enabled")} value={enabled} />
-      <Block label={t("npm.disabled")} value={disabled} />
-      <Block label={t("npm.total")} value={total} />
+    <Container service={service}>
+      <Block label="npm.enabled" value={enabled} />
+      <Block label="npm.disabled" value={disabled} />
+      <Block label="npm.total" value={total} />
     </Container>
   );
 }
diff --git a/src/widgets/nzbget/component.jsx b/src/widgets/nzbget/component.jsx
index f69f4cf0..f9ace707 100644
--- a/src/widgets/nzbget/component.jsx
+++ b/src/widgets/nzbget/component.jsx
@@ -17,23 +17,23 @@ export default function Component({ service }) {
 
   if (!statusData) {
     return (
-      <Container>
-        <Block label={t("nzbget.rate")} />
-        <Block label={t("nzbget.remaining")} />
-        <Block label={t("nzbget.downloaded")} />
+      <Container service={service}>
+        <Block label="nzbget.rate" />
+        <Block label="nzbget.remaining" />
+        <Block label="nzbget.downloaded" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("nzbget.rate")} value={t("common.bitrate", { value: statusData.DownloadRate })} />
+    <Container service={service}>
+      <Block label="nzbget.rate" value={t("common.bitrate", { value: statusData.DownloadRate })} />
       <Block
-        label={t("nzbget.remaining")}
+        label="nzbget.remaining"
         value={t("common.bytes", { value: statusData.RemainingSizeMB * 1024 * 1024 })}
       />
       <Block
-        label={t("nzbget.downloaded")}
+        label="nzbget.downloaded"
         value={t("common.bytes", { value: statusData.DownloadedSizeMB * 1024 * 1024 })}
       />
     </Container>
diff --git a/src/widgets/ombi/component.jsx b/src/widgets/ombi/component.jsx
index e7402721..60128c37 100644
--- a/src/widgets/ombi/component.jsx
+++ b/src/widgets/ombi/component.jsx
@@ -17,19 +17,19 @@ export default function Component({ service }) {
 
   if (!statsData) {
     return (
-      <Container>
-        <Block label={t("ombi.pending")} />
-        <Block label={t("ombi.approved")} />
-        <Block label={t("ombi.available")} />
+      <Container service={service}>
+        <Block label="ombi.pending" />
+        <Block label="ombi.approved" />
+        <Block label="ombi.available" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("ombi.pending")} value={statsData.pending} />
-      <Block label={t("ombi.approved")} value={statsData.approved} />
-      <Block label={t("ombi.available")} value={statsData.available} />
+    <Container service={service}>
+      <Block label="ombi.pending" value={statsData.pending} />
+      <Block label="ombi.approved" value={statsData.approved} />
+      <Block label="ombi.available" value={statsData.available} />
     </Container>
   );
 }
diff --git a/src/widgets/overseerr/component.jsx b/src/widgets/overseerr/component.jsx
index ad46a27e..47131f6e 100644
--- a/src/widgets/overseerr/component.jsx
+++ b/src/widgets/overseerr/component.jsx
@@ -17,19 +17,19 @@ export default function Component({ service }) {
 
   if (!statsData) {
     return (
-      <Container>
-        <Block label={t("overseerr.pending")} />
-        <Block label={t("overseerr.approved")} />
-        <Block label={t("overseerr.available")} />
+      <Container service={service}>
+        <Block label="overseerr.pending" />
+        <Block label="overseerr.approved" />
+        <Block label="overseerr.available" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("overseerr.pending")} value={statsData.pending} />
-      <Block label={t("overseerr.approved")} value={statsData.approved} />
-      <Block label={t("overseerr.available")} value={statsData.available} />
+    <Container service={service}>
+      <Block label="overseerr.pending" value={statsData.pending} />
+      <Block label="overseerr.approved" value={statsData.approved} />
+      <Block label="overseerr.available" value={statsData.available} />
     </Container>
   );
 }
diff --git a/src/widgets/pihole/component.jsx b/src/widgets/pihole/component.jsx
index a956594e..17a18627 100644
--- a/src/widgets/pihole/component.jsx
+++ b/src/widgets/pihole/component.jsx
@@ -17,19 +17,19 @@ export default function Component({ service }) {
 
   if (!piholeData) {
     return (
-      <Container>
-        <Block label={t("pihole.queries")} />
-        <Block label={t("pihole.blocked")} />
-        <Block label={t("pihole.gravity")} />
+      <Container service={service}>
+        <Block label="pihole.queries" />
+        <Block label="pihole.blocked" />
+        <Block label="pihole.gravity" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("pihole.queries")} value={t("common.number", { value: piholeData.dns_queries_today })} />
-      <Block label={t("pihole.blocked")} value={t("common.number", { value: piholeData.ads_blocked_today })} />
-      <Block label={t("pihole.gravity")} value={t("common.number", { value: piholeData.domains_being_blocked })} />
+    <Container service={service}>
+      <Block label="pihole.queries" value={t("common.number", { value: piholeData.dns_queries_today })} />
+      <Block label="pihole.blocked" value={t("common.number", { value: piholeData.ads_blocked_today })} />
+      <Block label="pihole.gravity" value={t("common.number", { value: piholeData.domains_being_blocked })} />
     </Container>
   );
 }
diff --git a/src/widgets/portainer/component.jsx b/src/widgets/portainer/component.jsx
index 140078bc..bd44d77e 100644
--- a/src/widgets/portainer/component.jsx
+++ b/src/widgets/portainer/component.jsx
@@ -19,10 +19,10 @@ export default function Component({ service }) {
 
   if (!containersData) {
     return (
-      <Container>
-        <Block label={t("portainer.running")} />
-        <Block label={t("portainer.stopped")} />
-        <Block label={t("portainer.total")} />
+      <Container service={service}>
+        <Block label="portainer.running" />
+        <Block label="portainer.stopped" />
+        <Block label="portainer.total" />
       </Container>
     );
   }
@@ -36,10 +36,10 @@ export default function Component({ service }) {
   const total = containersData.length;
 
   return (
-    <Container>
-      <Block label={t("portainer.running")} value={running} />
-      <Block label={t("portainer.stopped")} value={stopped} />
-      <Block label={t("portainer.total")} value={total} />
+    <Container service={service}>
+      <Block label="portainer.running" value={running} />
+      <Block label="portainer.stopped" value={stopped} />
+      <Block label="portainer.total" value={total} />
     </Container>
   );
 }
diff --git a/src/widgets/prowlarr/component.jsx b/src/widgets/prowlarr/component.jsx
index 85c50186..bb082519 100644
--- a/src/widgets/prowlarr/component.jsx
+++ b/src/widgets/prowlarr/component.jsx
@@ -18,12 +18,12 @@ export default function Component({ service }) {
 
   if (!indexersData || !grabsData) {
     return (
-      <Container>
-        <Block label={t("prowlarr.enableIndexers")} />
-        <Block label={t("prowlarr.numberOfGrabs")} />
-        <Block label={t("prowlarr.numberOfQueries")} />
-        <Block label={t("prowlarr.numberOfFailGrabs")} />
-        <Block label={t("prowlarr.numberOfFailQueries")} />
+      <Container service={service}>
+        <Block label="prowlarr.enableIndexers" />
+        <Block label="prowlarr.numberOfGrabs" />
+        <Block label="prowlarr.numberOfQueries" />
+        <Block label="prowlarr.numberOfFailGrabs" />
+        <Block label="prowlarr.numberOfFailQueries" />
       </Container>
     );
   }
@@ -42,12 +42,12 @@ export default function Component({ service }) {
   });
 
   return (
-    <Container>
-      <Block label={t("prowlarr.enableIndexers")} value={indexers.length} />
-      <Block label={t("prowlarr.numberOfGrabs")} value={numberOfGrabs} />
-      <Block label={t("prowlarr.numberOfQueries")} value={numberOfQueries} />
-      <Block label={t("prowlarr.numberOfFailGrabs")} value={numberOfFailedGrabs} />
-      <Block label={t("prowlarr.numberOfFailQueries")} value={numberOfFailedQueries} />
+    <Container service={service}>
+      <Block label="prowlarr.enableIndexers" value={indexers.length} />
+      <Block label="prowlarr.numberOfGrabs" value={numberOfGrabs} />
+      <Block label="prowlarr.numberOfQueries" value={numberOfQueries} />
+      <Block label="prowlarr.numberOfFailGrabs" value={numberOfFailedGrabs} />
+      <Block label="prowlarr.numberOfFailQueries" value={numberOfFailedQueries} />
     </Container>
   );
 }
diff --git a/src/widgets/qbittorrent/component.jsx b/src/widgets/qbittorrent/component.jsx
index 28458312..4d3a3585 100644
--- a/src/widgets/qbittorrent/component.jsx
+++ b/src/widgets/qbittorrent/component.jsx
@@ -17,11 +17,11 @@ export default function Component({ service }) {
 
   if (!torrentData) {
     return (
-      <Container>
-        <Block label={t("qbittorrent.leech")} />
-        <Block label={t("qbittorrent.download")} />
-        <Block label={t("qbittorrent.seed")} />
-        <Block label={t("qbittorrent.upload")} />
+      <Container service={service}>
+        <Block label="qbittorrent.leech" />
+        <Block label="qbittorrent.download" />
+        <Block label="qbittorrent.seed" />
+        <Block label="qbittorrent.upload" />
       </Container>
     );
   }
@@ -42,11 +42,11 @@ export default function Component({ service }) {
   const leech = torrentData.length - completed;
 
   return (
-    <Container>
-      <Block label={t("qbittorrent.leech")} value={t("common.number", { value: leech })} />
-      <Block label={t("qbittorrent.download")} value={t("common.bitrate", { value: rateDl })} />
-      <Block label={t("qbittorrent.seed")} value={t("common.number", { value: completed })} />
-      <Block label={t("qbittorrent.upload")} value={t("common.bitrate", { value: rateUl })} />
+    <Container service={service}>
+      <Block label="qbittorrent.leech" value={t("common.number", { value: leech })} />
+      <Block label="qbittorrent.download" value={t("common.bitrate", { value: rateDl })} />
+      <Block label="qbittorrent.seed" value={t("common.number", { value: completed })} />
+      <Block label="qbittorrent.upload" value={t("common.bitrate", { value: rateUl })} />
     </Container>
   );
 }
diff --git a/src/widgets/radarr/component.jsx b/src/widgets/radarr/component.jsx
index d6df7cf0..4b16f75f 100644
--- a/src/widgets/radarr/component.jsx
+++ b/src/widgets/radarr/component.jsx
@@ -18,19 +18,19 @@ export default function Component({ service }) {
 
   if (!moviesData || !queuedData) {
     return (
-      <Container>
-        <Block label={t("radarr.wanted")} />
-        <Block label={t("radarr.queued")} />
-        <Block label={t("radarr.movies")} />
+      <Container service={service}>
+        <Block label="radarr.wanted" />
+        <Block label="radarr.queued" />
+        <Block label="radarr.movies" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("radarr.wanted")} value={moviesData.wanted} />
-      <Block label={t("radarr.queued")} value={queuedData.totalCount} />
-      <Block label={t("radarr.movies")} value={moviesData.have} />
+    <Container service={service}>
+      <Block label="radarr.wanted" value={moviesData.wanted} />
+      <Block label="radarr.queued" value={queuedData.totalCount} />
+      <Block label="radarr.movies" value={moviesData.have} />
     </Container>
   );
 }
diff --git a/src/widgets/readarr/component.jsx b/src/widgets/readarr/component.jsx
index 794a6ab8..1e55d7cd 100644
--- a/src/widgets/readarr/component.jsx
+++ b/src/widgets/readarr/component.jsx
@@ -19,19 +19,19 @@ export default function Component({ service }) {
 
   if (!booksData || !wantedData || !queueData) {
     return (
-      <Container>
-        <Block label={t("readarr.wanted")} />
-        <Block label={t("readarr.queued")} />
-        <Block label={t("readarr.books")} />
+      <Container service={service}>
+        <Block label="readarr.wanted" />
+        <Block label="readarr.queued" />
+        <Block label="readarr.books" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("readarr.wanted")} value={t("common.number", { value: wantedData.totalRecords })} />
-      <Block label={t("readarr.queued")} value={t("common.number", { value: queueData.totalCount })} />
-      <Block label={t("readarr.books")} value={t("common.number", { value: booksData.have })} />
+    <Container service={service}>
+      <Block label="readarr.wanted" value={t("common.number", { value: wantedData.totalRecords })} />
+      <Block label="readarr.queued" value={t("common.number", { value: queueData.totalCount })} />
+      <Block label="readarr.books" value={t("common.number", { value: booksData.have })} />
     </Container>
   );
 }
diff --git a/src/widgets/rutorrent/component.jsx b/src/widgets/rutorrent/component.jsx
index cc0d03f5..279bdf0e 100644
--- a/src/widgets/rutorrent/component.jsx
+++ b/src/widgets/rutorrent/component.jsx
@@ -17,10 +17,10 @@ export default function Component({ service }) {
 
   if (!statusData) {
     return (
-      <Container>
-        <Block label={t("rutorrent.active")} />
-        <Block label={t("rutorrent.upload")} />
-        <Block label={t("rutorrent.download")} />
+      <Container service={service}>
+        <Block label="rutorrent.active" />
+        <Block label="rutorrent.upload" />
+        <Block label="rutorrent.download" />
       </Container>
     );
   }
@@ -32,10 +32,10 @@ export default function Component({ service }) {
   const active = statusData.filter((torrent) => torrent["d.get_state"] === "1");
 
   return (
-    <Container>
-      <Block label={t("rutorrent.active")} value={active.length} />
-      <Block label={t("rutorrent.upload")} value={t("common.bitrate", { value: upload })} />
-      <Block label={t("rutorrent.download")} value={t("common.bitrate", { value: download })} />
+    <Container service={service}>
+      <Block label="rutorrent.active" value={active.length} />
+      <Block label="rutorrent.upload" value={t("common.bitrate", { value: upload })} />
+      <Block label="rutorrent.download" value={t("common.bitrate", { value: download })} />
     </Container>
   );
 }
diff --git a/src/widgets/sabnzbd/component.jsx b/src/widgets/sabnzbd/component.jsx
index b38cb90f..c4e64c9a 100644
--- a/src/widgets/sabnzbd/component.jsx
+++ b/src/widgets/sabnzbd/component.jsx
@@ -27,19 +27,19 @@ export default function Component({ service }) {
 
   if (!queueData) {
     return (
-      <Container>
-        <Block label={t("sabnzbd.rate")} />
-        <Block label={t("sabnzbd.queue")} />
-        <Block label={t("sabnzbd.timeleft")} />
+      <Container service={service}>
+        <Block label="sabnzbd.rate" />
+        <Block label="sabnzbd.queue" />
+        <Block label="sabnzbd.timeleft" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("sabnzbd.rate")} value={t("common.bitrate", { value: fromUnits(queueData.queue.speed) * 8 })} />
-      <Block label={t("sabnzbd.queue")} value={t("common.number", { value: queueData.queue.noofslots })} />
-      <Block label={t("sabnzbd.timeleft")} value={queueData.queue.timeleft} />
+    <Container service={service}>
+      <Block label="sabnzbd.rate" value={t("common.bitrate", { value: fromUnits(queueData.queue.speed) * 8 })} />
+      <Block label="sabnzbd.queue" value={t("common.number", { value: queueData.queue.noofslots })} />
+      <Block label="sabnzbd.timeleft" value={queueData.queue.timeleft} />
     </Container>
   );
 }
diff --git a/src/widgets/sonarr/component.jsx b/src/widgets/sonarr/component.jsx
index 71aeb69c..8618b512 100644
--- a/src/widgets/sonarr/component.jsx
+++ b/src/widgets/sonarr/component.jsx
@@ -19,19 +19,19 @@ export default function Component({ service }) {
 
   if (!wantedData || !queuedData || !seriesData) {
     return (
-      <Container>
-        <Block label={t("sonarr.wanted")} />
-        <Block label={t("sonarr.queued")} />
-        <Block label={t("sonarr.series")} />
+      <Container service={service}>
+        <Block label="sonarr.wanted" />
+        <Block label="sonarr.queued" />
+        <Block label="sonarr.series" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("sonarr.wanted")} value={wantedData.totalRecords} />
-      <Block label={t("sonarr.queued")} value={queuedData.totalRecords} />
-      <Block label={t("sonarr.series")} value={seriesData.total} />
+    <Container service={service}>
+      <Block label="sonarr.wanted" value={wantedData.totalRecords} />
+      <Block label="sonarr.queued" value={queuedData.totalRecords} />
+      <Block label="sonarr.series" value={seriesData.total} />
     </Container>
   );
 }
diff --git a/src/widgets/speedtest/component.jsx b/src/widgets/speedtest/component.jsx
index edf8c66e..778d31c5 100644
--- a/src/widgets/speedtest/component.jsx
+++ b/src/widgets/speedtest/component.jsx
@@ -17,26 +17,26 @@ export default function Component({ service }) {
 
   if (!speedtestData) {
     return (
-      <Container>
-        <Block label={t("speedtest.download")} />
-        <Block label={t("speedtest.upload")} />
-        <Block label={t("speedtest.ping")} />
+      <Container service={service}>
+        <Block label="speedtest.download" />
+        <Block label="speedtest.upload" />
+        <Block label="speedtest.ping" />
       </Container>
     );
   }
 
   return (
-    <Container>
+    <Container service={service}>
       <Block
-        label={t("speedtest.download")}
+        label="speedtest.download"
         value={t("common.bitrate", { value: speedtestData.data.download * 1024 * 1024 })}
       />
       <Block
-        label={t("speedtest.upload")}
+        label="speedtest.upload"
         value={t("common.bitrate", { value: speedtestData.data.upload * 1024 * 1024 })}
       />
       <Block
-        label={t("speedtest.ping")}
+        label="speedtest.ping"
         value={t("common.ms", {
           value: speedtestData.data.ping,
           style: "unit",
diff --git a/src/widgets/strelaysrv/component.jsx b/src/widgets/strelaysrv/component.jsx
index f5b67d73..c7b887db 100644
--- a/src/widgets/strelaysrv/component.jsx
+++ b/src/widgets/strelaysrv/component.jsx
@@ -17,24 +17,24 @@ export default function Component({ service }) {
 
   if (!statsData) {
     return (
-      <Container>
-        <Block label={t("strelaysrv.numActiveSessions")} />
-        <Block label={t("strelaysrv.numConnections")} />
-        <Block label={t("strelaysrv.bytesProxied")} />
+      <Container service={service}>
+        <Block label="strelaysrv.numActiveSessions" />
+        <Block label="strelaysrv.numConnections" />
+        <Block label="strelaysrv.bytesProxied" />
       </Container>
     );
   }
 
   return (
-    <Container>
+    <Container service={service}>
       <Block
-        label={t("strelaysrv.numActiveSessions")}
+        label="strelaysrv.numActiveSessions"
         value={t("common.number", { value: statsData.numActiveSessions })}
       />
-      <Block label={t("strelaysrv.numConnections")} value={t("common.number", { value: statsData.numConnections })} />
+      <Block label="strelaysrv.numConnections" value={t("common.number", { value: statsData.numConnections })} />
       <Block label={t("strelaysrv.dataRelayed")} value={t("common.bytes", { value: statsData.bytesProxied })} />
       <Block
-        label={t("strelaysrv.transferRate")}
+        label="strelaysrv.transferRate"
         value={t("common.bitrate", { value: statsData.kbps10s1m5m15m30m60m[5] })}
       />
     </Container>
diff --git a/src/widgets/traefik/component.jsx b/src/widgets/traefik/component.jsx
index efa0e8fa..d24edb9e 100644
--- a/src/widgets/traefik/component.jsx
+++ b/src/widgets/traefik/component.jsx
@@ -17,19 +17,19 @@ export default function Component({ service }) {
 
   if (!traefikData) {
     return (
-      <Container>
-        <Block label={t("traefik.routers")} />
-        <Block label={t("traefik.services")} />
-        <Block label={t("traefik.middleware")} />
+      <Container service={service}>
+        <Block label="traefik.routers" />
+        <Block label="traefik.services" />
+        <Block label="traefik.middleware" />
       </Container>
     );
   }
 
   return (
-    <Container>
-      <Block label={t("traefik.routers")} value={traefikData.http.routers.total} />
-      <Block label={t("traefik.services")} value={traefikData.http.services.total} />
-      <Block label={t("traefik.middleware")} value={traefikData.http.middlewares.total} />
+    <Container service={service}>
+      <Block label="traefik.routers" value={traefikData.http.routers.total} />
+      <Block label="traefik.services" value={traefikData.http.services.total} />
+      <Block label="traefik.middleware" value={traefikData.http.middlewares.total} />
     </Container>
   );
 }
diff --git a/src/widgets/transmission/component.jsx b/src/widgets/transmission/component.jsx
index 5e471666..3c2f38ef 100644
--- a/src/widgets/transmission/component.jsx
+++ b/src/widgets/transmission/component.jsx
@@ -17,11 +17,11 @@ export default function Component({ service }) {
 
   if (!torrentData) {
     return (
-      <Container>
-        <Block label={t("transmission.leech")} />
-        <Block label={t("transmission.download")} />
-        <Block label={t("transmission.seed")} />
-        <Block label={t("transmission.upload")} />
+      <Container service={service}>
+        <Block label="transmission.leech" />
+        <Block label="transmission.download" />
+        <Block label="transmission.seed" />
+        <Block label="transmission.upload" />
       </Container>
     );
   }
@@ -34,11 +34,11 @@ export default function Component({ service }) {
   const leech = torrents.length - completed || 0;
 
   return (
-    <Container>
-      <Block label={t("transmission.leech")} value={t("common.number", { value: leech })} />
-      <Block label={t("transmission.download")} value={t("common.bitrate", { value: rateDl * 8 })} />
-      <Block label={t("transmission.seed")} value={t("common.number", { value: completed })} />
-      <Block label={t("transmission.upload")} value={t("common.bitrate", { value: rateUl * 8 })} />
+    <Container service={service}>
+      <Block label="transmission.leech" value={t("common.number", { value: leech })} />
+      <Block label="transmission.download" value={t("common.bitrate", { value: rateDl * 8 })} />
+      <Block label="transmission.seed" value={t("common.number", { value: completed })} />
+      <Block label="transmission.upload" value={t("common.bitrate", { value: rateUl * 8 })} />
     </Container>
   );
 }