diff --git a/docs/widgets/services/planit.md b/docs/widgets/services/planit.md
new file mode 100644
index 00000000..d1cebfaa
--- /dev/null
+++ b/docs/widgets/services/planit.md
@@ -0,0 +1,15 @@
+---
+title: Plant-it
+description: Plant-it Widget Configuration
+---
+
+Learn more about [Plantit](https://github.com/MDeLuise/plant-it).
+
+API key can be created from the REST API.
+
+```yaml
+widget:
+ type: plantit
+ url: http://plant-it.host.or.ip:port # api port
+ key: plantit-api-key
+```
diff --git a/mkdocs.yml b/mkdocs.yml
index 572d36b4..e9d531ba 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -103,6 +103,7 @@ nav:
- widgets/services/photoprism.md
- widgets/services/pialert.md
- widgets/services/pihole.md
+ - widgets/services/plantit.md
- widgets/services/plex-tautulli.md
- widgets/services/plex.md
- widgets/services/portainer.md
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index 5521fd0c..cc6846a0 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -825,5 +825,11 @@
"netdata": {
"warnings": "Warnings",
"criticals": "Criticals"
+ },
+ "plantit": {
+ "events": "Events",
+ "plants": "Plants",
+ "photos": "Photos",
+ "species": "Species"
}
}
diff --git a/public/locales/it/common.json b/public/locales/it/common.json
index 6f10baf7..e61fff8b 100644
--- a/public/locales/it/common.json
+++ b/public/locales/it/common.json
@@ -803,5 +803,11 @@
"netdata": {
"warnings": "Warnings",
"criticals": "Criticals"
+ },
+ "plantit": {
+ "events": "Eventi",
+ "plants": "Piante",
+ "species": "Specie",
+ "images": "Immagini"
}
}
diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js
index bc087593..02338b82 100644
--- a/src/utils/proxy/handlers/credentialed.js
+++ b/src/utils/proxy/handlers/credentialed.js
@@ -65,6 +65,8 @@ export default async function credentialedProxyHandler(req, res, map) {
headers.Authorization = `Basic ${Buffer.from(`$:${widget.key}`).toString("base64")}`;
} else if (widget.type === "glances") {
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
+ } else if (widget.type === "plantit") {
+ headers.Key = `${widget.key}`;
} else {
headers["X-API-Key"] = `${widget.key}`;
}
diff --git a/src/widgets/components.js b/src/widgets/components.js
index bb9b00fe..784f05b2 100644
--- a/src/widgets/components.js
+++ b/src/widgets/components.js
@@ -78,6 +78,7 @@ const components = {
proxmoxbackupserver: dynamic(() => import("./proxmoxbackupserver/component")),
pialert: dynamic(() => import("./pialert/component")),
pihole: dynamic(() => import("./pihole/component")),
+ plantit: dynamic(() => import("./plantit/component")),
plex: dynamic(() => import("./plex/component")),
portainer: dynamic(() => import("./portainer/component")),
prometheus: dynamic(() => import("./prometheus/component")),
diff --git a/src/widgets/plantit/component.jsx b/src/widgets/plantit/component.jsx
new file mode 100644
index 00000000..ea203b87
--- /dev/null
+++ b/src/widgets/plantit/component.jsx
@@ -0,0 +1,37 @@
+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: plantitData, error: plantitError } = useWidgetAPI(widget, "plantit");
+
+ if (plantitError) {
+ return ;
+ }
+
+ if (!plantitData) {
+ return (
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/widgets/plantit/widget.js b/src/widgets/plantit/widget.js
new file mode 100644
index 00000000..5a4bebc1
--- /dev/null
+++ b/src/widgets/plantit/widget.js
@@ -0,0 +1,21 @@
+import { asJson } from "utils/proxy/api-helpers";
+import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
+
+const widget = {
+ api: "{url}/api/{endpoint}",
+ proxyHandler: credentialedProxyHandler,
+
+ mappings: {
+ plantit: {
+ endpoint: "stats",
+ },
+ map: (data) => ({
+ events: Object.values(asJson(data).diaryEntryCount).reduce((acc, i) => acc + i, 0),
+ plants: Object.values(asJson(data).plantCount).reduce((acc, i) => acc + i, 0),
+ photos: Object.values(asJson(data).imageCount).reduce((acc, i) => acc + i, 0),
+ species: Object.values(asJson(data).botanicalInfoCount).reduce((acc, i) => acc + i, 0),
+ }),
+ },
+};
+
+export default widget;
diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js
index fe474406..6f50d9ef 100644
--- a/src/widgets/widgets.js
+++ b/src/widgets/widgets.js
@@ -71,6 +71,7 @@ import photoprism from "./photoprism/widget";
import proxmoxbackupserver from "./proxmoxbackupserver/widget";
import pialert from "./pialert/widget";
import pihole from "./pihole/widget";
+import plantit from "./plantit/widget";
import plex from "./plex/widget";
import portainer from "./portainer/widget";
import prometheus from "./prometheus/widget";
@@ -180,6 +181,7 @@ const widgets = {
proxmoxbackupserver,
pialert,
pihole,
+ plantit,
plex,
portainer,
prometheus,