diff --git a/public/app.js b/public/app.js
index 0b19aed..2c8f977 100644
--- a/public/app.js
+++ b/public/app.js
@@ -778,9 +778,13 @@ async function toggleStatusPanel() {
return;
}
panel.style.display = 'block';
- // Show webhooks section for admin users
+ // Show webhooks section for admin users (collapsed by default)
if (webhooksSection && isAdmin) {
webhooksSection.style.display = '';
+ // Ensure webhooks section starts collapsed
+ webhookSectionExpanded = false;
+ document.getElementById('webhooks-content').style.display = 'none';
+ document.getElementById('webhooks-toggle').classList.remove('expanded');
await fetchWebhookStatus();
}
await refreshStatusPanel();
@@ -859,6 +863,26 @@ function renderStatusPanel(data, panel) {
html += ``;
+ // Webhook metrics card (admin only)
+ if (isAdmin && data.webhooks) {
+ const wh = data.webhooks;
+ const sonarrEnabled = wh.sonarr?.enabled ? '●' : '○';
+ const radarrEnabled = wh.radarr?.enabled ? '●' : '○';
+ const sonarrEvents = wh.sonarr?.eventsReceived || 0;
+ const radarrEvents = wh.radarr?.eventsReceived || 0;
+ const sonarrPolls = wh.sonarr?.pollsSkipped || 0;
+ const radarrPolls = wh.radarr?.pollsSkipped || 0;
+
+ html += `
+
+
Webhooks
+
Sonarr${sonarrEnabled} ${wh.sonarr?.enabled ? 'Enabled' : 'Disabled'}
+
Radarr${radarrEnabled} ${wh.radarr?.enabled ? 'Enabled' : 'Disabled'}
+
EventsS:${sonarrEvents} R:${radarrEvents}
+
Polls skippedS:${sonarrPolls} R:${radarrPolls}
+
`;
+ }
+
// Poll timings card
const lp = data.polling.lastPoll;
if (lp) {
diff --git a/server/routes/dashboard.js b/server/routes/dashboard.js
index e72fa29..ee1ae1c 100644
--- a/server/routes/dashboard.js
+++ b/server/routes/dashboard.js
@@ -782,6 +782,35 @@ router.get('/status', requireAuth, (req, res) => {
const cacheStats = cache.getStats();
const uptime = process.uptime();
+ // Get webhook metrics
+ const { getGlobalWebhookMetrics } = require('../utils/cache');
+ const webhookMetrics = getGlobalWebhookMetrics();
+
+ // Find Sonarr and Radarr metrics from instances
+ const sonarrMetrics = {};
+ const radarrMetrics = {};
+ for (const [url, metrics] of Object.entries(webhookMetrics.instances || {})) {
+ if (url.includes('sonarr')) {
+ sonarrMetrics[url] = metrics;
+ } else if (url.includes('radarr')) {
+ radarrMetrics[url] = metrics;
+ }
+ }
+
+ // Aggregate metrics for each service
+ const aggregateMetrics = (metricsMap) => {
+ const values = Object.values(metricsMap);
+ if (values.length === 0) return null;
+ return {
+ enabled: true,
+ eventsReceived: values.reduce((sum, m) => sum + (m.eventsReceived || 0), 0),
+ pollsSkipped: values.reduce((sum, m) => sum + (m.pollsSkipped || 0), 0),
+ lastEvent: values.reduce((latest, m) => {
+ return m.lastWebhookTimestamp > latest ? m.lastWebhookTimestamp : latest;
+ }, 0)
+ };
+ };
+
res.json({
server: {
uptimeSeconds: Math.floor(uptime),
@@ -796,7 +825,11 @@ router.get('/status', requireAuth, (req, res) => {
lastPoll: getLastPollTimings()
},
cache: cacheStats,
- clients: getActiveClients()
+ clients: getActiveClients(),
+ webhooks: {
+ sonarr: aggregateMetrics(sonarrMetrics),
+ radarr: aggregateMetrics(radarrMetrics)
+ }
});
} catch (err) {
res.status(500).json({ error: 'Failed to get status', details: err.message });