diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index 6faba3213..9202c249c 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -433,5 +433,11 @@
"cloudflared": {
"origin_ip": "Origin IP",
"status": "Status"
+ },
+ "proxmoxbackupserver": {
+ "datastore_usage": "Datastore",
+ "failed_tasks_24h": "Failed Tasks 24h",
+ "cpu_usage": "CPU",
+ "memory_usage": "Memory"
}
}
\ No newline at end of file
diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js
index 7dc9f9e6a..23e065246 100644
--- a/src/utils/proxy/handlers/credentialed.js
+++ b/src/utils/proxy/handlers/credentialed.js
@@ -34,6 +34,9 @@ export default async function credentialedProxyHandler(req, res, map) {
headers.Authorization = `Bearer ${widget.key}`;
} else if (widget.type === "proxmox") {
headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`;
+ } else if (widget.type === "proxmoxbackupserver") {
+ delete headers["Content-Type"];
+ headers.Authorization = `PBSAPIToken=${widget.username}:${widget.password}`;
} else if (widget.type === "autobrr") {
headers["X-API-Token"] = `${widget.key}`;
} else if (widget.type === "tubearchivist") {
diff --git a/src/widgets/components.js b/src/widgets/components.js
index 2896f159f..17a2d7e34 100644
--- a/src/widgets/components.js
+++ b/src/widgets/components.js
@@ -37,6 +37,7 @@ const components = {
opnsense: dynamic(() => import("./opnsense/component")),
overseerr: dynamic(() => import("./overseerr/component")),
paperlessngx: dynamic(() => import("./paperlessngx/component")),
+ proxmoxbackupserver: dynamic(() => import("./proxmoxbackupserver/component")),
pihole: dynamic(() => import("./pihole/component")),
plex: dynamic(() => import("./plex/component")),
portainer: dynamic(() => import("./portainer/component")),
diff --git a/src/widgets/proxmoxbackupserver/component.jsx b/src/widgets/proxmoxbackupserver/component.jsx
new file mode 100644
index 000000000..96151e256
--- /dev/null
+++ b/src/widgets/proxmoxbackupserver/component.jsx
@@ -0,0 +1,45 @@
+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";
+
+export default function Component({ service }) {
+ const { t } = useTranslation();
+
+ const { widget } = service;
+
+ const { data: datastoreData, error: datastoreError } = useWidgetAPI(widget, "status/datastore-usage");
+ const { data: tasksData, error: tasksError } = useWidgetAPI(widget, "nodes/localhost/tasks");
+ const { data: hostData, error: hostError } = useWidgetAPI(widget, "nodes/localhost/status");
+
+ if (datastoreError || tasksError || hostError) {
+ const finalError = tasksError ?? datastoreError ?? hostError;
+ return ;
+ }
+
+ if (!datastoreData || !tasksData || !hostData) {
+ return (
+
+
+
+
+
+
+ );
+ }
+
+ const datastoreUsage = datastoreData.data[0].used / datastoreData.data[0].total * 100;
+ const cpuUsage = hostData.data.cpu * 100;
+ const memoryUsage = hostData.data.memory.used / hostData.data.memory.total * 100;
+ const failedTasks = tasksData.total >= 100 ? "99+" : tasksData.total;
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/widgets/proxmoxbackupserver/widget.js b/src/widgets/proxmoxbackupserver/widget.js
new file mode 100644
index 000000000..0f2623304
--- /dev/null
+++ b/src/widgets/proxmoxbackupserver/widget.js
@@ -0,0 +1,22 @@
+import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
+
+const since = Date.now() - (24 * 60 * 60 * 1000);
+
+const widget = {
+ api: "{url}/api2/json/{endpoint}",
+ proxyHandler: credentialedProxyHandler,
+
+ mappings: {
+ "status/datastore-usage": {
+ endpoint: "status/datastore-usage",
+ },
+ "nodes/localhost/tasks": {
+ endpoint: `nodes/localhost/tasks?errors=true&limit=100&since=${since}`,
+ },
+ "nodes/localhost/status": {
+ endpoint: "nodes/localhost/status",
+ },
+ },
+};
+
+export default widget;
diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js
index a1cc061c1..42f7aa7b6 100644
--- a/src/widgets/widgets.js
+++ b/src/widgets/widgets.js
@@ -31,6 +31,7 @@ import ombi from "./ombi/widget";
import opnsense from "./opnsense/widget";
import overseerr from "./overseerr/widget";
import paperlessngx from "./paperlessngx/widget";
+import proxmoxbackupserver from "./proxmoxbackupserver/widget";
import pihole from "./pihole/widget";
import plex from "./plex/widget";
import portainer from "./portainer/widget";
@@ -92,6 +93,7 @@ const widgets = {
opnsense,
overseerr,
paperlessngx,
+ proxmoxbackupserver,
pihole,
plex,
portainer,