use dioxus::prelude::*; use dioxus_free_icons::icons::bs_icons::{ BsBarChartLine, BsBoxArrowUpRight, BsGraphUp, BsSpeedometer, }; use dioxus_free_icons::Icon; use crate::i18n::{t, Locale}; use crate::models::{AnalyticsMetric, ServiceUrlsContext}; /// Analytics & Observability page for Langfuse. /// /// Langfuse is configured with Keycloak SSO (shared realm with CERTifAI). /// When users open Langfuse, the existing Keycloak session auto-authenticates /// them transparently. This page shows a metrics bar, connection status, /// and a prominent button to open Langfuse in a new tab. #[component] pub fn AnalyticsPage() -> Element { let locale = use_context::>(); let svc = use_context::>(); let l = *locale.read(); let url = svc.read().langfuse_url.clone(); let connected = !url.is_empty(); let metrics = mock_metrics(l); rsx! { div { class: "analytics-page", // -- Hero section -- div { class: "analytics-hero", div { class: "analytics-hero-row", div { class: "analytics-hero-icon", Icon { icon: BsGraphUp, width: 24, height: 24 } } h2 { class: "analytics-hero-title", {t(l, "developer.analytics_title")} } } p { class: "analytics-hero-desc", {t(l, "developer.analytics_desc")} } // -- Connection status -- if connected { div { class: "agents-status", span { class: "agents-status-dot agents-status-dot--on", } span { {t(l, "developer.analytics_status_connected")} } code { class: "agents-status-url", {url.clone()} } } } else { div { class: "agents-status", span { class: "agents-status-dot agents-status-dot--off", } span { {t(l, "developer.analytics_status_not_connected")} } span { class: "agents-status-hint", {t(l, "developer.analytics_config_hint")} } } } // -- SSO info -- if connected { p { class: "analytics-sso-hint", {t(l, "developer.analytics_sso_hint")} } } } // -- Metrics bar -- div { class: "analytics-stats-bar", for metric in &metrics { div { class: "analytics-stat", span { class: "analytics-stat-value", "{metric.value}" } span { class: "analytics-stat-label", "{metric.label}" } span { class: if metric.change_pct >= 0.0 { "analytics-stat-change analytics-stat-change--up" } else { "analytics-stat-change analytics-stat-change--down" }, "{metric.change_pct:+.1}%" } } } } // -- Open Langfuse button -- if connected { a { class: "analytics-launch-btn", href: "{url}", target: "_blank", rel: "noopener noreferrer", Icon { icon: BsBoxArrowUpRight, width: 16, height: 16 } span { {t(l, "developer.launch_analytics")} } } } // -- Quick actions -- h3 { class: "agents-section-title", {t(l, "developer.analytics_quick_actions")} } div { class: "agents-grid", // Traces a { class: if connected { "agents-card" } else { "agents-card agents-card--disabled" }, href: if connected { format!("{url}/project") } else { "#".to_string() }, target: "_blank", rel: "noopener noreferrer", div { class: "agents-card-icon", Icon { icon: BsBarChartLine, width: 18, height: 18 } } div { class: "agents-card-title", {t(l, "developer.analytics_traces")} } div { class: "agents-card-desc", {t(l, "developer.analytics_traces_desc")} } } // Dashboard a { class: if connected { "agents-card" } else { "agents-card agents-card--disabled" }, href: if connected { format!("{url}/project") } else { "#".to_string() }, target: "_blank", rel: "noopener noreferrer", div { class: "agents-card-icon", Icon { icon: BsSpeedometer, width: 18, height: 18 } } div { class: "agents-card-title", {t(l, "developer.analytics_dashboard")} } div { class: "agents-card-desc", {t(l, "developer.analytics_dashboard_desc")} } } } } } } /// Returns mock analytics metrics for the stats bar. /// /// # Arguments /// /// * `locale` - The current locale for translating metric labels fn mock_metrics(locale: Locale) -> Vec { vec![ AnalyticsMetric { label: t(locale, "developer.total_requests"), value: "12,847".into(), change_pct: 14.2, }, AnalyticsMetric { label: t(locale, "developer.avg_latency"), value: "245ms".into(), change_pct: -8.5, }, AnalyticsMetric { label: t(locale, "developer.tokens_used"), value: "2.4M".into(), change_pct: 22.1, }, AnalyticsMetric { label: t(locale, "developer.error_rate"), value: "0.3%".into(), change_pct: -12.0, }, ] }