Files
certifai/src/pages/developer/analytics.rs
Sharang Parnerkar 0deaaca848
Some checks failed
CI / Format (push) Successful in 3s
CI / Clippy (push) Successful in 2m48s
CI / Security Audit (push) Successful in 1m41s
CI / Tests (push) Successful in 4m8s
CI / Deploy (push) Successful in 5s
CI / E2E Tests (push) Failing after 19s
feat: added langflow, langfuse and langgraph integrations (#17)
Co-authored-by: Sharang Parnerkar <parnerkarsharang@gmail.com>
Reviewed-on: #17
2026-02-25 20:08:48 +00:00

174 lines
6.4 KiB
Rust

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::<Signal<Locale>>();
let svc = use_context::<Signal<ServiceUrlsContext>>();
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<AnalyticsMetric> {
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,
},
]
}