diff --git a/crates/dashboard/src/lib.rs b/crates/dashboard/src/lib.rs index 26c2033..581381b 100644 --- a/crates/dashboard/src/lib.rs +++ b/crates/dashboard/src/lib.rs @@ -1,5 +1,6 @@ mod server; mod store; +mod live_explorer; pub mod swactor; pub mod view; @@ -143,6 +144,7 @@ impl DashboardHandle { /// is called. pub fn start_dashboard(config: DashboardConfig) -> DashboardHandle { let views = Arc::new(ViewRegistry::new()); + views.register(Arc::new(live_explorer::LiveDatastreamExplorer)); views.register(swactor::worker_view()); let store = Arc::new(DashboardStore::new( config.raw_frame_history, diff --git a/crates/dashboard/src/live_explorer.rs b/crates/dashboard/src/live_explorer.rs new file mode 100644 index 0000000..6395ae4 --- /dev/null +++ b/crates/dashboard/src/live_explorer.rs @@ -0,0 +1,37 @@ +use datastream::frame::{Frame, StreamId}; +use serde_json::{Value, json}; + +use crate::FrameEvent; +use crate::view::DashboardView; + +const LIVE_EXPLORER_HTML: &str = include_str!("live_explorer_page.html"); + +#[derive(Default)] +pub struct LiveDatastreamExplorer; + +impl DashboardView for LiveDatastreamExplorer { + fn id(&self) -> &'static str { + "datastream/live" + } + + fn title(&self) -> &'static str { + "Datastream live explorer" + } + + fn channels(&self) -> &'static [&'static str] { + &[] + } + + fn ingest(&self, _stream: &StreamId, _frame: &Frame, _event: &FrameEvent) {} + + fn snapshot_json(&self) -> Value { + json!({ + "description": "Universal live explorer over /events and /api/frames", + "page": "/view/datastream/live" + }) + } + + fn html(&self) -> Option<&'static str> { + Some(LIVE_EXPLORER_HTML) + } +} diff --git a/crates/dashboard/src/live_explorer_page.html b/crates/dashboard/src/live_explorer_page.html new file mode 100644 index 0000000..cbaa376 --- /dev/null +++ b/crates/dashboard/src/live_explorer_page.html @@ -0,0 +1,500 @@ + + + + + +Datastream live explorer + + + +
+
+

Datastream live explorer

+
Auto-connected. Streams/channels are stable DOM rows; incoming frames update only affected counters and the selected channel ring.
+
+ starting +
+ +
+ + + + + + + + + +
+ +
+
frames
0
+
streams
0
+
channels
0
+
json
0
+
scope
all
+
+ +
+
+
+
Streams
+
streamretained frameschannels
+
+ + +
+ +
+ + + + diff --git a/crates/mvp-system/src/bin/local_e2e_cluster.rs b/crates/mvp-system/src/bin/local_e2e_cluster.rs index 40aa0a9..6ba5f3b 100644 --- a/crates/mvp-system/src/bin/local_e2e_cluster.rs +++ b/crates/mvp-system/src/bin/local_e2e_cluster.rs @@ -78,7 +78,7 @@ impl MvpDashboard { .map_err(|e| format!("invalid MVP_DASHBOARD_PORT: {e}"))?; config.port = port; } - let url = format!("http://127.0.0.1:{}/view/mvp/cluster", config.port); + let url = format!("http://127.0.0.1:{}/view/datastream/live", config.port); let handle = dashboard::start_dashboard(config.clone()); handle.register_view(Arc::new(MvpClusterDashboardView::new())); handle.start_http_standalone();