Loom Notebook Editor — Fabric-parity build spec¶
Reference: real Fabric notebook
01_bronze_slot_telemetryincasino-fabric-poc(F64), captured via Playwright 2026-05-26. Screenshots:temp/fabric-notebook-real.png+temp/fabric-notebook-clean.png.
Why this exists¶
The current Loom notebook is a single textarea + a code-only Save/Run. That's NOT what Fabric ships. This doc inventories every visible Fabric notebook UX element and maps each to its Loom build target.
Fabric notebook UX inventory (verified live)¶
Page chrome (top → bottom)¶
| Region | Elements | Source |
|---|---|---|
| Title bar | 01_bronze_slot_telemetry (editable name) · No label chip · Saved status (auto-save indicator) | top-left of page |
| Right-side global | Search bar (centered) · Notifications · Settings · Downloads · Help · Feedback · Account picker | top-right |
| Notebook tab strip | Home (selected) · Edit · AI tools · Run · View | below title bar, left half |
| Notebook right-side actions | Comments · History · Develop (dropdown) · Share | below title bar, right half |
| Home ribbon | Save (disk) · Download · Settings (gear) · Run all ▼ · Connect ▼ · PySpark (Python) ▼ · Environment · Workspace default ▼ · Data Wrangler ▼ · AI assistant icon · AutoML (New AutoML run) · Pipeline (Add to pipeline) · VS Code (Open in VS Code) · Copilot | ribbon strip under tabs |
Status bar (bottom)¶
| Item | What it shows |
|---|---|
| Not connected / Connected · | Spark session status |
| AutoSave: On | Auto-save toggle |
| Copilot completions: On | Inline AI suggestions toggle |
| Selected Cell N of M cells | Cell selection counter (this notebook has 23 cells) |
Left side panel — Explorer¶
| Element | Purpose |
|---|---|
| Header: Explorer + collapse arrow | Panel title |
| Tab: Data items (selected) | Lakehouses + warehouses attached to this notebook |
| Tab: Resources | File attachments (.csv, .py modules) embedded in notebook |
| Tab: Connections | External data source connections (SQL, ADLS, Onelake shortcuts) |
| + Add data items button | Attaches a Lakehouse / Warehouse / KQL DB / Real-Time hub source |
| Search box | Filter the tree |
| Tree: OneLake root → child Lakehouses with star (pin) icon | Browsable per-attached source: when expanded, shows Tables / Files folders |
Cell-level UX¶
Every cell has: 1. Cell-type icon on the left — green code-bracket for code cells, hash # for markdown 2. Collapse arrow at left edge to fold cell 3. Cell body — Monaco editor (code) OR rendered markdown 4. Right-edge toolbar (visible on hover): Ask Copilot, Maximize/Expand, Convert (code↔md), Edit, Lock, More menu (⋯), Delete - Execution count badge [N] shown on code cells after run 5. Between cells on hover: a thin gap shows + Code and + Markdown buttons to insert a new cell at that position 6. Output area below code cells — text, tables (Spark DataFrame.show output), charts (with Chart View toggle) 7. Run cell button (▷) at the top-left of the cell when hovered
Cell types Fabric supports¶
- Code with language taken from the notebook-level default language picker:
- PySpark (Python) — default
- Spark (Scala)
- Spark SQL
- SparkR (R)
- Python (standalone, no Spark — for utility cells)
- T-SQL (when notebook is attached to a Warehouse/SQL endpoint)
- Markdown (rendered as headings/lists/links; toggle to edit mode by clicking)
Connect dropdown options¶
When user clicks Connect ▼ in the ribbon, expected entries: - Attach Lakehouse → opens picker with existing Lakehouses in current Loom workspace + ability to create new - Attach Warehouse / SQL endpoint → similar - Attach KQL Database → picks ADX/Kusto db - Manage connections → opens Connections tab on left panel
Environment / Workspace default dropdown¶
- Sets the runtime: which compute pool + which environment (package versions) runs the notebook.
- For Loom: maps to the existing
/api/loom/compute-targets(Synapse Spark + Databricks clusters).
History pane¶
When user clicks History top-right: - Side drawer or full pane showing past runs with timestamps, duration, status, user, parameters - Each row clickable for details
Loom build plan — what's needed¶
Backend (mostly done — small additions)¶
- ✅
/api/loom/workspaces— done - ✅
/api/loom/compute-targets— done (Synapse Spark + Databricks clusters) - ✅
/api/items/notebook(Cosmos-backed list/create) — done (v3.22) - ✅
/api/items/notebook/[id](read/update/delete with code body) — done (v3.22) - ✅
/api/items/notebook/[id]/run(async dispatch) — done (v3.24) - ✅
/api/items/notebook/[id]/runs/[runId](polling) — done (v3.24) - NEW
/api/items/notebook/[id]/cells— return cells[] (each: id, type, lang, source, outputs[]) - NEW
/api/items/notebook/[id]/cells/[cellId]/run— run a single cell against the same session (Spark Livy session is shared across cells in a notebook run) - NEW
/api/items/notebook/[id]/attached-sources— list Lakehouses/Warehouses/KQL DBs attached to this notebook - NEW
/api/items/notebook/[id]/data-items— append/remove attached source - The Cosmos
statefield expands to:{ cells: [...], defaultLang, attachedSources: [...] }
Frontend — full rebuild¶
Replace single-textarea editor with a cell-based editor:
| Component | Tech | Source |
|---|---|---|
| NotebookEditor root | New React component, replaces current single-textarea | lib/editors/notebook-editor.tsx |
| Cell (Code) | Monaco editor with language from cell.lang, Run button, Output area | new lib/components/notebook/CodeCell.tsx |
| Cell (Markdown) | Two-mode (edit/view) using a Markdown renderer (e.g. react-markdown) | new lib/components/notebook/MarkdownCell.tsx |
| CellAdder between cells | Hover-visible + Code / + Markdown buttons | lib/components/notebook/CellAdder.tsx |
| Cell right-edge toolbar | Convert / Maximize / Copy / Edit / Lock / More / Delete | lib/components/notebook/CellToolbar.tsx |
| NotebookRibbon | Tabs (Home/Edit/AI tools/Run/View) + the Home ribbon contents | lib/components/notebook/NotebookRibbon.tsx |
| LanguagePicker | Dropdown: PySpark/Spark Scala/Spark SQL/SparkR/Python/T-SQL — sets default lang for new cells | lib/components/notebook/LanguagePicker.tsx |
| CompactCompute dropdown | Replaces current "Compute target" — same data but rendered as a Fabric-style chip | lib/components/notebook/ComputeChip.tsx |
| ConnectMenu | Dropdown w/ Attach Lakehouse, Attach Warehouse, Attach KQL DB, Manage connections | lib/components/notebook/ConnectMenu.tsx |
| ExplorerPane (left side) | Data items / Resources / Connections tabs + tree | lib/components/notebook/ExplorerPane.tsx |
| StatusBar | Connection status · AutoSave · Cell N of M | lib/components/notebook/StatusBar.tsx |
| HistoryDrawer | Past runs pane | lib/components/notebook/HistoryDrawer.tsx |
Cell data model (new Cosmos shape)¶
interface NotebookCell {
id: string; // uuid stable across edits
type: 'code' | 'markdown';
lang?: 'pyspark' | 'spark' | 'sparksql' | 'sparkr' | 'python' | 'tsql';
source: string; // raw code / markdown text
outputs?: CellOutput[]; // last-run outputs, persisted with cell
locked?: boolean;
collapsed?: boolean;
}
interface CellOutput {
type: 'text' | 'table' | 'error';
data?: any; // table data / JSON
text?: string;
ename?: string; evalue?: string; traceback?: string[];
}
interface NotebookState {
cells: NotebookCell[];
defaultLang: 'pyspark' | 'spark' | 'sparksql' | 'sparkr' | 'python' | 'tsql';
attachedSources: {
kind: 'lakehouse' | 'warehouse' | 'kql-database';
id: string; // Loom Cosmos id of the source
displayName: string;
isDefault: boolean;
metadata?: any;
}[];
}
Run-all execution model¶
When user clicks Run all: 1. Create one Livy session (or one Databricks job context) 2. For each cell in order: - If markdown — skip - If code — submit statement; await output; persist output to cell; surface inline 3. Track total elapsed + cell-by-cell timings
Per-cell run¶
Per-cell Run cell ▷ button: - Reuses the current session if one exists (Cosmos persists activeSessionId for the notebook) - If no session — creates one, then runs the cell - Output appended to the cell, persisted on next save
Attach Lakehouse flow¶
- User clicks + Add data items in Explorer panel
- Modal: list Loom Cosmos items of
itemType = lakehousein this workspace - Selected → appended to
state.attachedSources[], becomes browsable in tree - First attached lakehouse becomes the "default lakehouse" — Spark session is started with
spark.sql.defaultDatabase = <its name>and OneLake mount points wired up - Tree under a lakehouse:
Tables+Filesfolders, expanded on click —Tableslists Delta tables from the Cosmos metadata + ADLS scan;Filesis the ADLS Gen2 browse (already wired in Lakehouse editor)
Phasing — what fits in one session each¶
This is too big for one session. Phased build:
Session N+1 (~2-3 hrs)¶
- Cell-based editor scaffold (NotebookEditor v2)
- Code cell with Monaco
- Markdown cell with view/edit toggle
-
- Code / + Markdown hover insert
- Cell-level Run button (single cell)
- Language picker in ribbon
- Cosmos state migration (single-source → cells[])
Session N+2 (~2-3 hrs)¶
- ExplorerPane with Data items / Resources / Connections tabs
- ConnectMenu — Attach Lakehouse modal
- Tree under attached lakehouse (Tables + Files)
- StatusBar
- Run-all
- Cosmos state field for attachedSources
Session N+3 (~2 hrs)¶
- HistoryDrawer
- Cell-edge toolbars (Convert / Lock / Delete / Maximize / Copy)
- Outputs: table renderer for Spark DataFrame outputs (HTML schema → DataGrid)
- AI tools tab basic features
- Notebook tab strip (Home/Edit/AI tools/Run/View — each maps to different ribbon)
Session N+4 — polish¶
- Visual parity pixel check vs Fabric
- Loading states, keyboard shortcuts (Ctrl+Enter to run cell, etc.)
- A11y audit
- Re-run UAT harness
Why this isn't done today¶
Honest scope: building this is ~3-4 focused sessions. The single-textarea Loom notebook was always a stub disguised as functional — it persisted code, called Run, but had none of the Fabric-parity UX. The wiring-audit graded it A (renders, calls Spark) but should have been D (single textarea isn't a notebook).
Updating wiring-audit.md to D for notebook until the cell-based rebuild ships.