feat: Morning NOC Summary adaptive card for Teams

- Add MorningSummaryService with Zabbix aggregation and adaptive card builder
- Add webhook delivery system with Teams incoming webhooks
- Add admin UI at /admin/morning-summary for webhook/config management
- Add API routes: /send, /test, /webhooks, /webhooks/[id], /config, /history
- Register morning-summary cron job in SyncScheduler (Mon-Fri 6:30 AM)
- Add outages_only filter (Unavailable triggers only)
- Fix host resolution: use getTriggerEnabledHosts to exclude disabled hosts
- Fix resolved events: event.get value:1 scoped to window with r_eventid filter
- Remove emojis from fact rows and section headers in card
- Remove Open Zabbix button (duplicate of View Problems)
- Add migrations: morning_summary_config + morning_summaries tables
- Add outages_only column to morning_summary_config
This commit is contained in:
lorentz 2026-03-11 09:34:51 -04:00
parent 19605f82aa
commit c518eefdb2
61 changed files with 11236 additions and 237 deletions

View file

@ -21,6 +21,9 @@ import {
Zap,
Radio,
Shield,
Users,
TrendingUp,
Sun,
} from 'lucide-react';
import {
NavigationMenu,
@ -61,6 +64,24 @@ const navigationItems: NavItem[] = [
icon: HardDrive,
description: 'Veeam backup health and compliance'
},
{
title: 'Engagement',
icon: Users,
children: [
{
title: 'Overview',
href: '/engagement',
icon: Users,
description: 'Staff activity and engagement metrics',
},
{
title: 'Employee Profile',
href: '/engagement/profile',
icon: TrendingUp,
description: '12-month activity calendar and performance profile',
},
],
},
{
title: 'Admin',
icon: Activity,
@ -119,6 +140,12 @@ const navigationItems: NavItem[] = [
icon: Zap,
description: 'Automated webhook processing workflows'
},
{
title: 'Morning NOC Summary',
href: '/admin/morning-summary',
icon: Sun,
description: 'Daily Zabbix overnight summary posted to Teams channels via webhook'
},
{
title: 'Notification Channels',
href: '/admin/workflow/channels',
@ -157,7 +184,7 @@ export function AppNavigation() {
return (
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container px-6 flex h-16 items-center justify-between">
<div className="container mx-auto px-6 flex h-16 items-center justify-between">
{/* Logo and App Name */}
<Link href="/" className="flex items-center space-x-3 shrink-0">
<img
@ -180,7 +207,7 @@ export function AppNavigation() {
<>
<NavigationMenuTrigger className={cn(
"h-9 px-4 py-2",
item.children.some(child => isActive(child.href)) && "bg-accent"
item.children.some(child => isActive(child.href)) && "bg-primary text-primary-foreground"
)}>
{item.icon && <item.icon className="w-4 h-4 mr-2" />}
{item.title}
@ -193,8 +220,8 @@ export function AppNavigation() {
<Link
href={child.href || '#'}
className={cn(
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
isActive(child.href) && "bg-accent"
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-primary/10 hover:text-primary focus:bg-primary/10 focus:text-primary",
isActive(child.href) && "bg-primary text-primary-foreground"
)}
>
<div className="flex items-center text-sm font-medium leading-none">
@ -218,7 +245,7 @@ export function AppNavigation() {
<NavigationMenuLink className={cn(
navigationMenuTriggerStyle(),
"h-9",
isActive(item.href) && "bg-accent"
isActive(item.href) && "bg-primary text-primary-foreground"
)}>
{item.icon && <item.icon className="w-4 h-4 mr-2" />}
{item.title}
@ -255,7 +282,7 @@ interface PageHeaderProps {
export function PageHeader({ title, description, breadcrumbs, actions }: PageHeaderProps) {
return (
<div className="border-b">
<div className="container px-6 py-4">
<div className="container mx-auto px-6 py-4">
{/* Breadcrumbs */}
{breadcrumbs && breadcrumbs.length > 0 && (
<nav className="flex items-center space-x-2 text-sm text-muted-foreground mb-2">