fix(webhooks): Load collapsed by default, add webhook metrics to status panel
All checks were successful
All checks were successful
- Fixed webhooks section to load collapsed (content hidden, toggle arrow reset) - Added webhook metrics card to status panel for admin users: - Shows Sonarr/Radarr enabled/disabled status - Shows events received and polls skipped counts - Updated /api/dashboard/status endpoint to include webhook metrics - Metrics are aggregated from all Sonarr/Radarr instances
This commit is contained in:
@@ -778,9 +778,13 @@ async function toggleStatusPanel() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
panel.style.display = 'block';
|
panel.style.display = 'block';
|
||||||
// Show webhooks section for admin users
|
// Show webhooks section for admin users (collapsed by default)
|
||||||
if (webhooksSection && isAdmin) {
|
if (webhooksSection && isAdmin) {
|
||||||
webhooksSection.style.display = '';
|
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 fetchWebhookStatus();
|
||||||
}
|
}
|
||||||
await refreshStatusPanel();
|
await refreshStatusPanel();
|
||||||
@@ -859,6 +863,26 @@ function renderStatusPanel(data, panel) {
|
|||||||
|
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
|
|
||||||
|
// 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 += `
|
||||||
|
<div class="status-card">
|
||||||
|
<div class="status-card-title">Webhooks</div>
|
||||||
|
<div class="status-row"><span>Sonarr</span><span>${sonarrEnabled} ${wh.sonarr?.enabled ? 'Enabled' : 'Disabled'}</span></div>
|
||||||
|
<div class="status-row"><span>Radarr</span><span>${radarrEnabled} ${wh.radarr?.enabled ? 'Enabled' : 'Disabled'}</span></div>
|
||||||
|
<div class="status-row status-row-sub"><span>Events</span><span>S:${sonarrEvents} R:${radarrEvents}</span></div>
|
||||||
|
<div class="status-row status-row-sub"><span>Polls skipped</span><span>S:${sonarrPolls} R:${radarrPolls}</span></div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
// Poll timings card
|
// Poll timings card
|
||||||
const lp = data.polling.lastPoll;
|
const lp = data.polling.lastPoll;
|
||||||
if (lp) {
|
if (lp) {
|
||||||
|
|||||||
@@ -782,6 +782,35 @@ router.get('/status', requireAuth, (req, res) => {
|
|||||||
const cacheStats = cache.getStats();
|
const cacheStats = cache.getStats();
|
||||||
const uptime = process.uptime();
|
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({
|
res.json({
|
||||||
server: {
|
server: {
|
||||||
uptimeSeconds: Math.floor(uptime),
|
uptimeSeconds: Math.floor(uptime),
|
||||||
@@ -796,7 +825,11 @@ router.get('/status', requireAuth, (req, res) => {
|
|||||||
lastPoll: getLastPollTimings()
|
lastPoll: getLastPollTimings()
|
||||||
},
|
},
|
||||||
cache: cacheStats,
|
cache: cacheStats,
|
||||||
clients: getActiveClients()
|
clients: getActiveClients(),
|
||||||
|
webhooks: {
|
||||||
|
sonarr: aggregateMetrics(sonarrMetrics),
|
||||||
|
radarr: aggregateMetrics(radarrMetrics)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ error: 'Failed to get status', details: err.message });
|
res.status(500).json({ error: 'Failed to get status', details: err.message });
|
||||||
|
|||||||
Reference in New Issue
Block a user