diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index a4b0628d..8784443a 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -309,5 +309,11 @@
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
+ },
+ "truenas": {
+ "load": "System Load",
+ "uptime": "Uptime",
+ "alerts": "Alerts",
+ "time": "{{value, number(style: unit; unitDisplay: long;)}}"
}
}
diff --git a/src/widgets/components.js b/src/widgets/components.js
index 47502403..33d09eac 100644
--- a/src/widgets/components.js
+++ b/src/widgets/components.js
@@ -37,6 +37,7 @@ const components = {
traefik: dynamic(() => import("./traefik/component")),
transmission: dynamic(() => import("./transmission/component")),
tubearchivist: dynamic(() => import("./tubearchivist/component")),
+ truenas: dynamic(() => import("./truenas/component")),
unifi: dynamic(() => import("./unifi/component")),
watchtower: dynamic(() => import("./watchtower/component")),
};
diff --git a/src/widgets/truenas/component.jsx b/src/widgets/truenas/component.jsx
new file mode 100644
index 00000000..1e5c7b2d
--- /dev/null
+++ b/src/widgets/truenas/component.jsx
@@ -0,0 +1,65 @@
+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 processUptime = uptime => {
+
+ let seconds = uptime.toFixed(0);
+
+ var levels = [
+ [Math.floor(seconds / 31536000), 'year'],
+ [Math.floor((seconds % 31536000) / 2592000), 'month'],
+ [Math.floor(((seconds % 31536000) % 2592000) / 86400), 'day'],
+ [Math.floor(((seconds % 31536000) % 86400) / 3600), 'hour'],
+ [Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'minute'],
+ [(((seconds % 31536000) % 86400) % 3600) % 60, 'second'],
+ ];
+
+ for(let i = 0; i< levels.length; i++){
+ let level = levels[i];
+ if(level[0] > 0){
+ return {
+ value: level[0],
+ unit: level[1]
+ }
+ }
+ }
+
+ return {
+ value: 0,
+ unit: 'second'
+ };
+}
+
+export default function Component({ service }) {
+ const { t } = useTranslation();
+
+ const { widget } = service;
+
+ const { data: alertData, error: alertError } = useWidgetAPI(widget, "alerts");
+ const { data: statusData, error: statusError } = useWidgetAPI(widget, "status");
+
+ if (alertError || statusError) {
+ return ;
+ }
+
+ if (!alertData || !statusData) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/widgets/truenas/widget.js b/src/widgets/truenas/widget.js
new file mode 100644
index 00000000..7269e36a
--- /dev/null
+++ b/src/widgets/truenas/widget.js
@@ -0,0 +1,21 @@
+import { jsonArrayFilter } from "utils/proxy/api-helpers";
+import genericProxyHandler from "utils/proxy/handlers/generic";
+
+const widget = {
+ api: "{url}/api/v2.0/{endpoint}",
+ proxyHandler: genericProxyHandler,
+
+ mappings: {
+ alerts: {
+ endpoint: "alert/list",
+ map: (data) => ({
+ pending: jsonArrayFilter(data, (item) => item?.dismissed === false).length,
+ }),
+ },
+ status: {
+ endpoint: "system/info",
+ },
+ },
+};
+
+export default widget;
diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js
index 0352466d..7bad4013 100644
--- a/src/widgets/widgets.js
+++ b/src/widgets/widgets.js
@@ -32,6 +32,7 @@ import tautulli from "./tautulli/widget";
import traefik from "./traefik/widget";
import transmission from "./transmission/widget";
import tubearchivist from "./tubearchivist/widget";
+import truenas from "./truenas/widget";
import unifi from "./unifi/widget";
import watchtower from './watchtower/widget'
@@ -71,6 +72,7 @@ const widgets = {
traefik,
transmission,
tubearchivist,
+ truenas,
unifi,
unifi_console: unifi,
watchtower,