(* Server-side React UI components using server-reason-react *)
open Dream
open Lwt.Infix
open Database
(* HTML helpers *)
let html ?(title="Website Monitor") ?(body="") ?(extra_head="") () =
Printf.sprintf {|
%s
%s
%s
|} title extra_head body
(* Dashboard page *)
let serve_dashboard req =
Websites.get_all ()
>>= fun websites ->
let active_websites = List.filter (fun w -> w.active) websites in
let healthy_count =
List.fold_left (fun acc w ->
match w.last_status with
| None -> acc
| Some status ->
if status = w.expected_status then acc + 1 else acc) 0 active_websites
in
let total_active = List.length active_websites in
let websites_cards =
List.map
(fun w ->
let status_icon =
match w.last_status with
| None -> ""
| Some status ->
if status = w.expected_status then
""
else
""
in
let last_checked =
match w.last_checked with
| None -> "Never"
| Some t ->
try
let t' = Ptime.v (Unix.gettimeofday ()) in
let diff = Ptime.diff t' t |> Ptime.Span.to_float_s in
if diff < 60.0 then Printf.sprintf "%.0f seconds ago" diff
else if diff < 3600.0 then Printf.sprintf "%.0f minutes ago" (diff /. 60.0)
else Printf.sprintf "%.1f hours ago" (diff /. 3600.0)
with _ -> "Unknown"
in
Printf.sprintf {|
|}
status_icon
w.name
w.url
(if w.active then "bg-green-100 text-green-800" else "bg-gray-100 text-gray-800")
(if w.active then "Active" else "Inactive")
last_checked
)
websites
|> String.concat "\n"
in
let body = Printf.sprintf {|
Dashboard
Total Websites
%d
Active
%d
Healthy
%d
Unhealthy
%d
Website Status
%s
|} (List.length websites) total_active healthy_count (total_active - healthy_count) websites_cards
in
let html_content = html ~title:"Website Monitor - Dashboard" ~body () in
Lwt.return (Dream.html html_content)
(* Websites management page *)
let serve_websites_page req =
Websites.get_all ()
>>= fun websites ->
let website_rows =
List.map
(fun w ->
let status_badge =
match w.last_status with
| None -> "Unknown"
| Some status ->
if status = w.expected_status then
"OK"
else
Printf.sprintf "%d" status
in
let active_badge =
if w.active then
"Active"
else
"Inactive"
in
Printf.sprintf {|
%s
%s
%s
%s
%s
%d
|}
w.name
w.url
status_badge
active_badge
(match w.last_checked with
| None -> "Never"
| Some t -> Ptime.to_rfc3339 t)
w.check_interval
w.id
w.id
w.id
)
websites
|> String.concat "\n"
in
let body = Printf.sprintf {|
Websites
Name
URL
Status
Active
Last Checked
Interval (s)
Actions
%s
|} website_rows
in
let html_content = html ~title:"Website Monitor - Websites" ~body () in
Lwt.return (Dream.html html_content)
(* Alerts management page *)
let serve_alerts_page req =
Alerts.get_all ()
>>= fun alerts ->
let alert_rows =
List.map
(fun a ->
let type_badge =
match a.alert_type with
| "email" -> "Email"
| "webhook" -> "Webhook"
| _ -> Printf.sprintf "%s" a.alert_type
in
let enabled_badge =
if a.enabled then
"Enabled"
else
"Disabled"
in
Printf.sprintf {|
%Ld
%s
%s
%s
%s
|}
a.website_id
type_badge
enabled_badge
a.config
(Ptime.to_rfc3339 a.created_at)
a.id
a.id
a.id
)
alerts
|> String.concat "\n"
in
let body = Printf.sprintf {|
Alerts
Website ID
Type
Status
Config
Created
Actions
%s
|} alert_rows
in
let html_content = html ~title:"Website Monitor - Alerts" ~body () in
Lwt.return (Dream.html html_content)
(* Settings page *)
let serve_settings_page req =
let body = Printf.sprintf {|
Settings
Monitoring Settings
Email Configuration
System Information
Version
1.0.0
Environment
Production
Scheduler Status
Running
Database
Connected
|}
in
let html_content = html ~title:"Website Monitor - Settings" ~body () in
Lwt.return (Dream.html html_content)