Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

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()
    }
}