Add recent activity feed and tabbed sidebar layout

New features:
- Recent Activity feed widget shows last 8 actions from audit log
  with relative timestamps, auto-refreshes every 60s
- Right sidebar reorganized: Calendar + Activity always visible,
  Tickets/Archer/Ivanti behind tab switcher to eliminate dead space

Backend:
- New GET /api/recent-activity endpoint (any authenticated user)
  Returns last N audit entries excluding login/logout noise
  Lighter than the full admin audit-logs endpoint

Frontend:
- RecentActivityFeed component with action labels, colored dots,
  timeAgo formatting, and manual refresh button
- SidebarTabs component with Tickets/Archer/Ivanti tabs
- OpenTicketsPanel and IvantiWorkflowPanel support embedded prop
  to render without their own panel wrapper when inside tabs

Layout change:
Before: Calendar | Tickets | Archer | Ivanti (4 stacked panels)
After:  Calendar | Activity | [Tickets | Archer | Ivanti] (tabs)

This keeps the sidebar height proportional to the CVE list area
instead of extending far below the main content.
This commit is contained in:
Jordan Ramos
2026-06-23 12:16:40 -06:00
parent 306950e360
commit f119cca1d7
6 changed files with 274 additions and 27 deletions

View File

@@ -157,6 +157,25 @@ app.use('/api/users', createUsersRouter(requireAuth, requireGroup, logAudit));
// Audit log routes (admin only)
app.use('/api/audit-logs', createAuditLogRouter());
// Recent activity feed (any authenticated user, limited data)
app.get('/api/recent-activity', requireAuth(), async (req, res) => {
try {
const limit = Math.min(15, Math.max(1, parseInt(req.query.limit) || 10));
const { rows } = await pool.query(
`SELECT username, action, entity_type, entity_id, details, created_at
FROM audit_logs
WHERE action NOT IN ('login', 'logout', 'login_failed')
ORDER BY created_at DESC
LIMIT $1`,
[limit]
);
res.json({ activities: rows });
} catch (err) {
console.error('Recent activity error:', err);
res.status(500).json({ error: 'Failed to fetch recent activity' });
}
});
// NVD lookup routes (authenticated users)
app.use('/api/nvd', createNvdLookupRouter());