diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index cd6012f8..9b3d06b7 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -757,5 +757,10 @@
"inCinemas": "In cinemas",
"physicalRelease": "Physical release",
"digitalRelease": "Digital release"
+ },
+ "synapse": {
+ "users": "Users",
+ "rooms": "Rooms",
+ "peers": "Peers"
}
}
diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js
index 9840c30a..20cd74e5 100644
--- a/src/utils/proxy/handlers/credentialed.js
+++ b/src/utils/proxy/handlers/credentialed.js
@@ -36,6 +36,7 @@ export default async function credentialedProxyHandler(req, res, map) {
"tailscale",
"truenas",
"pterodactyl",
+ "synapse",
].includes(widget.type))
{
headers.Authorization = `Bearer ${widget.key}`;
diff --git a/src/widgets/components.js b/src/widgets/components.js
index 9d311b97..4cefb113 100644
--- a/src/widgets/components.js
+++ b/src/widgets/components.js
@@ -88,6 +88,7 @@ const components = {
scrutiny: dynamic(() => import("./scrutiny/component")),
sonarr: dynamic(() => import("./sonarr/component")),
speedtest: dynamic(() => import("./speedtest/component")),
+ synapse: dynamic(() => import("./synapse/component")),
strelaysrv: dynamic(() => import("./strelaysrv/component")),
tailscale: dynamic(() => import("./tailscale/component")),
tautulli: dynamic(() => import("./tautulli/component")),
diff --git a/src/widgets/synapse/component.jsx b/src/widgets/synapse/component.jsx
new file mode 100644
index 00000000..15f67c69
--- /dev/null
+++ b/src/widgets/synapse/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: usersData, error: usersError } = useWidgetAPI(widget, "users");
+ const { data: roomsData, error: roomsError } = useWidgetAPI(widget, "rooms");
+ const { data: peersData, error: peersError } = useWidgetAPI(widget, "peers");
+
+ if (usersError || roomsError || peersError) {
+ return ;
+ }
+
+ if (!usersData || !roomsData || !peersData) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/widgets/synapse/widget.js b/src/widgets/synapse/widget.js
new file mode 100644
index 00000000..5ceb85d3
--- /dev/null
+++ b/src/widgets/synapse/widget.js
@@ -0,0 +1,20 @@
+import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
+
+const widget = {
+ api: "{url}/_synapse/admin/{endpoint}",
+ proxyHandler: credentialedProxyHandler,
+
+ mappings: {
+ users: {
+ endpoint: "v2/users",
+ },
+ rooms: {
+ endpoint: "v1/rooms",
+ },
+ peers: {
+ endpoint: "v1/federation/destinations",
+ },
+ },
+};
+
+export default widget;
diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js
index 6bc682da..d5f0fc3a 100644
--- a/src/widgets/widgets.js
+++ b/src/widgets/widgets.js
@@ -81,6 +81,7 @@ import sabnzbd from "./sabnzbd/widget";
import scrutiny from "./scrutiny/widget";
import sonarr from "./sonarr/widget";
import speedtest from "./speedtest/widget";
+import synapse from "./synapse/widget";
import strelaysrv from "./strelaysrv/widget";
import tailscale from "./tailscale/widget";
import tautulli from "./tautulli/widget";
@@ -183,6 +184,7 @@ const widgets = {
scrutiny,
sonarr,
speedtest,
+ synapse,
strelaysrv,
tailscale,
tautulli,