from datetime import datetime from typing import Any, Literal, Optional from pydantic import BaseModel, Field MonitorPolicyMode = Literal["inherit", "include", "exclude"] AvailabilityWindow = Literal["24h", "3d", "7d"] class DashboardScope(BaseModel): city: Optional[str] = None client: Optional[str] = None object_ids: list[int] = Field(default_factory=list) tag_ids: list[int] = Field(default_factory=list) class DashboardCheckDefinitionRead(BaseModel): check_key: str enabled: bool interval_sec_default: int plugin_action: str categories: list[str] timeout_sec: int concurrency: int updated_at: datetime model_config = {"from_attributes": True} class DashboardCheckDefinitionPatchItem(BaseModel): check_key: str enabled: Optional[bool] = None interval_sec_default: Optional[int] = None categories: Optional[list[str]] = None timeout_sec: Optional[int] = None concurrency: Optional[int] = None class DashboardObjectOverrideRead(BaseModel): object_id: int check_key: str enabled_override: Optional[bool] = None interval_sec_override: Optional[int] = None categories_override: Optional[list[str]] = None updated_at: datetime model_config = {"from_attributes": True} class DashboardObjectOverridePatchItem(BaseModel): object_id: int check_key: str enabled_override: Optional[bool] = None interval_sec_override: Optional[int] = None categories_override: Optional[list[str]] = None class DashboardObjectPolicyRead(BaseModel): object_id: int mode: MonitorPolicyMode updated_at: datetime model_config = {"from_attributes": True} class DashboardObjectPolicyPatchItem(BaseModel): object_id: int mode: MonitorPolicyMode class DashboardTagPolicyRead(BaseModel): tag_id: int enabled: bool updated_at: datetime model_config = {"from_attributes": True} class DashboardTagPolicyPatchItem(BaseModel): tag_id: int enabled: bool class DashboardPolicyResponse(BaseModel): object_policies: list[DashboardObjectPolicyRead] tag_policies: list[DashboardTagPolicyRead] class DashboardChecksResponse(BaseModel): checks: list[DashboardCheckDefinitionRead] object_overrides: list[DashboardObjectOverrideRead] class DashboardRunRequest(DashboardScope): force: bool = True class DashboardRunResponse(BaseModel): accepted: bool running: bool detail: str class DashboardMonitorStatus(BaseModel): status: str run_type: Optional[str] = None scope: Optional[dict[str, Any]] = None started_at: Optional[datetime] = None finished_at: Optional[datetime] = None last_success_at: Optional[datetime] = None last_error: Optional[str] = None last_counts: Optional[dict[str, Any]] = None model_config = {"from_attributes": True} class DashboardObjectCheckSummary(BaseModel): status_counts: dict[str, int] last_checked_at: Optional[datetime] = None max_age_sec: Optional[int] = None class DashboardObjectSummary(BaseModel): object_id: int object_name: str city: Optional[str] = None client: Optional[str] = None allowed: bool monitor_mode: MonitorPolicyMode inclusion_reason: str device_count: int checks: dict[str, DashboardObjectCheckSummary] health_score: Optional[float] = None has_baseline: bool = False recovered_count: int = 0 class DashboardHomeSummaryResponse(BaseModel): generated_at: datetime scope: DashboardScope totals: dict[str, int] checks_meta: list[DashboardCheckDefinitionRead] objects: list[DashboardObjectSummary] problem_objects: list[DashboardObjectSummary] included_count: int excluded_count: int included_objects: list[DashboardObjectSummary] excluded_objects: list[DashboardObjectSummary] class DashboardDeviceNOCItem(BaseModel): device_id: int object_id: int rack_id: Optional[int] = None rack_name: Optional[str] = None ip: str hostname: Optional[str] = None category: str role: Optional[str] = None status: Optional[str] = None monitor_enabled: bool last_seen: Optional[datetime] = None last_ping_ms: Optional[int] = None ping_status: str ping_checked_at: Optional[datetime] = None ping_age_sec: Optional[int] = None ping_fresh: bool disk_status: Optional[str] = None disk_max_pct: Optional[float] = None has_problem: bool baseline_status: Optional[str] = None baseline_suppressed: bool = False recovered: bool = False class DashboardBaselineItem(BaseModel): device_id: int baseline_status: str saved_at: datetime class DashboardBaselineResponse(BaseModel): object_id: int count: int items: list[DashboardBaselineItem] class DashboardObjectSummaryResponse(BaseModel): generated_at: datetime scope: DashboardScope object: DashboardObjectSummary totals: dict[str, int] checks_meta: list[DashboardCheckDefinitionRead] top_problem_devices: list[DashboardDeviceNOCItem] class DashboardObjectDevicesResponse(BaseModel): generated_at: datetime scope: DashboardScope object_id: int devices: list[DashboardDeviceNOCItem] class DashboardAvailabilityPoint(BaseModel): bucket_start: datetime bucket_end: datetime availability_pct: Optional[float] = None samples: int online: int offline: int class DashboardAvailabilityInterval(BaseModel): status: str started_at: datetime ended_at: datetime duration_sec: int class DashboardDeviceAvailability(BaseModel): device_id: int ip: str hostname: Optional[str] = None availability_pct: Optional[float] = None samples: int online: int offline: int last_checked_at: Optional[datetime] = None last_status: Optional[str] = None last_ping_ms: Optional[int] = None series: list[DashboardAvailabilityPoint] intervals: list[DashboardAvailabilityInterval] class DashboardObjectAvailabilityResponse(BaseModel): generated_at: datetime object_id: int window: AvailabilityWindow start_at: datetime end_at: datetime bucket_sec: int overall_availability_pct: Optional[float] = None overall_series: list[DashboardAvailabilityPoint] devices: list[DashboardDeviceAvailability] insufficient_data: bool