facett-demo/src/sdp_tab.rs
//! **The `SDP` tab** — the Spark Declarative Pipelines editor ([`facett_sdp`])
//! mounted as a first-class demo surface. An SDP pipeline is a set of **flows**,
//! each a named Spark-SQL query over its upstream deps; the editor lets a user edit
//! the SQL + name/deps, add/remove flows, flip to a dependency-DAG preview, and see
//! the static (non-SQL) validation verdict.
//!
//! [`SdpEditor`] mirrors the [`Facet`] shape (title / ui / state_json) but lives in
//! a leaf crate that doesn't depend on `facett-core`, so this thin wrapper adopts it
//! into the deck's `Facet` trait (exactly the pattern `vg_lab_tab` uses for
//! `GraphNav`). Seeded with a realistic **medallion** pipeline (bronze → silver →
//! gold) so the tab shows a real multi-flow DAG with no host.
use facett::Facet;
use facett::core::FacetCaps;
use facett_sdp::{Flow, SdpEditor};
/// The stable tab title (the deck/discovery-contract key + the legend key).
pub const TITLE: &str = "SDP";
/// The SDP editor tab: a real [`SdpEditor`] seeded with a medallion pipeline.
pub struct SdpTab {
editor: SdpEditor,
}
impl Default for SdpTab {
fn default() -> Self {
Self::new()
}
}
impl SdpTab {
/// Build the tab over a realistic bronze → silver → gold SDP pipeline.
pub fn new() -> Self {
let editor = SdpEditor::new(TITLE).with_flows([
Flow::new(
"bronze_events",
std::iter::empty::<String>(),
"SELECT * FROM cloud_files('/mnt/lake/raw/events', 'json')",
),
Flow::new(
"silver_events",
["bronze_events"],
"SELECT id, ts, user_id, kind\nFROM bronze_events\nWHERE kind IS NOT NULL",
),
Flow::new(
"silver_users",
std::iter::empty::<String>(),
"SELECT id, region, tier FROM raw.users",
),
Flow::new(
"gold_activity",
["silver_events", "silver_users"],
"SELECT u.region, e.kind, count(*) AS n\n\
FROM silver_events e JOIN silver_users u ON e.user_id = u.id\n\
GROUP BY u.region, e.kind",
),
]);
Self { editor }
}
/// An empty editor (0 flows) — the mega-matrix's `DataState::Empty` cell.
pub fn empty() -> Self {
Self { editor: SdpEditor::new(TITLE) }
}
/// The number of flows currently modelled (tests + observability).
pub fn flow_count(&self) -> usize {
self.editor.len()
}
/// The editor (for deeper assertions).
pub fn editor(&self) -> &SdpEditor {
&self.editor
}
}
impl Facet for SdpTab {
fn title(&self) -> &str {
self.editor.title()
}
fn caps(&self) -> FacetCaps {
FacetCaps::NONE.themeable()
}
fn kind(&self) -> &'static str {
"sdp"
}
fn ui(&mut self, ui: &mut egui::Ui) {
self.editor.ui(ui);
}
fn state_json(&self) -> serde_json::Value {
self.editor.state_json()
}
}