dataview — Iceberg / warehouse browsing — guide
Class:
guide· audience: a techie wiring one of the three dataview components into a host, or driving one from a test. The what is indataview-design.md. This file is the workflow.
f0 — picking the right component (the whole workflow)
Three questions decide which of the three components you want:
- Do you need to scrub a single table's history (time-travel)? →
facett-icebergview::IcebergView(f1). - Do you need several tables/graphs visible at once, as a dashboard? →
facett-warehousedeck::WarehouseDeck(f2). - Do you need a simple "pick one table from a list, see its rows or an auto-chart" browser? →
facett-table::warehouse::WarehouseTableView(f3).
All three are Facets: build one, Box::new(it) into a FacetDeck, and you get the palette picker and headless testability for free — the same pattern as grid-guide.md f0.
f1 — driving IcebergView
Build it from a host-read scan per snapshot (order doesn't matter — it sorts newest-first for you):
use facett_icebergview::{IcebergView, Snapshot, SnapshotMeta};
let view = IcebergView::new(
"🧊 Tables",
"Person",
vec![
Snapshot::new(SnapshotMeta::new(100, 1_000, 2), batches_v1),
Snapshot::new(SnapshotMeta::new(200, 2_000, 3), batches_v2),
],
).with_page_size(500);
Time-travel and paging, both as direct calls and as headless Msgs:
view.select_snapshot(100); // by stable Iceberg snapshot id
view.set_page(1);
view.current_id(); // Some(100)
view.snapshot_metas(); // newest-first, for a custom picker UI
// Headless, through the Elm seam:
use facett_core::harness;
use facett_icebergview::Msg;
let state = harness::snapshot(&mut view, [Msg::SelectSnapshot(200), Msg::NextPage]);
assert_eq!(state.current, Some(200));
When new snapshots accrue (a live feed), call set_snapshots again with the full updated list — it re-sorts, re-selects the newest, and rebuilds the grid. Read view.state_json() for the exact keys a headless assertion or a mega-matrix run should check: table, snapshots, current, total_rows, page, page_size, page_count, columns, visible_rows.
f2 — building a WarehouseDeck wall
Start from the registry so table→view-kind mapping is one line per table:
use facett_warehousedeck::{WarehouseDeck, WarehouseRegistry, PaneData, GraphSpec, ChartSpec};
let registry = WarehouseRegistry::default_nordisk();
let mut deck = WarehouseDeck::new("🏢 Warehouse").with_cols(3);
// For each table your host scanned, look up its kind and add the matching pane:
match registry.kind_for("bench_runs") {
Some(_) => { deck.add_for("bench runs", "bench_runs", PaneData::Grid(scanned_batches)); }
None => {}
}
// Join-derived panes (a call graph from two tables) are added directly, no registry lookup:
deck.add_for("call graph", "call_edges", PaneData::Graph(GraphSpec::new(nodes, edges)));
Drive the layout / focus from a toolbar or headlessly — both routes go through the same Msgs:
use facett_core::harness;
use facett_warehousedeck::{Msg, DeckLayout};
deck.set_layout(DeckLayout::Focus); // direct call
harness::drive(&mut deck, [Msg::DrillInto("call graph".into())]); // headless
assert_eq!(deck.selected(), Some("call graph"));
Reading deck.state_json()["deck"]["trace"]["ran"] after a headless render is the way to assert every expected pane actually drew (each entry is deck.wall:<pane title>), which is the strongest signal for "the dashboard came up correctly" in a test.
f3 — driving WarehouseTableView
use facett_table::warehouse::{WarehouseTableView, PreviewTable};
let view = WarehouseTableView::new("Warehouse")
.with_table("bench_runs", PreviewTable::new(
vec!["bench".into(), "ms".into()],
vec![vec!["xml_parse".into(), "12.4".into()], vec!["json_parse".into(), "8.1".into()]],
))
.with_table("repos", PreviewTable::new(
vec!["name".into(), "lang".into()],
vec![vec!["nornir".into(), "rust".into()]],
));
WarehouseTableView::local() / ::remote() seed two demo tables with no host attached — reach for these when you just need something on screen (a smoke test, a storybook) rather than hand-rolling PreviewTables.
Selecting a table and turning on the auto-chart, both directly and headlessly:
view.select("bench_runs"); // direct call, by stable name
use facett_core::harness;
use facett_table::warehouse::Msg;
harness::drive(&mut view, [Msg::SetChart(true)]); // defaults value/label columns for you
A live feed that grows a table each tick calls set_table(name, updated_preview) — it replaces an existing table's rows in place (selection preserved) or appends a new one. state_json() exposes tables, selected, chart (on/value_col/ label_col), and preview (loaded, columns, rows as a count, numeric_columns) for whatever's currently selected.