Skip to content

Commit 5a86592

Browse files
committed
Add showcase extensions docs and samples
Add a new Showcase Extensions section with five layout writeups (DAG Notebook, Slide Studio, Grid Studio, Form Studio, Image Studio) and accompanying images; add detailed docs for each sample and an overview page. Update guides: clarify ipywidgets/#!pip usage in interactive-widgets.md, expand layouts.md to list and explain the five showcase layouts and link the overview, and clarify auto-install behaviour in python-packages.md. Update sample files: adjust dag-notebook widget verso text, improve Form Studio and Image Studio README instructions, and bump jsuites version in Grid Studio README. Several sample images and assets for the showcase were added as well. Signed-off-by: Torrey Betts <torrey.betts@gmail.com>
1 parent 25b40b7 commit 5a86592

23 files changed

Lines changed: 415 additions & 16 deletions

docs/guides/interactive-widgets.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ This guide covers what makes a widget live, what a saved file holds, what happen
1212
#!pip ipywidgets
1313
```
1414

15+
That first line is for a notebook that has to run anywhere, not for the editor. In VS Code or `verso serve` you can leave it out and run the cell below on its own: the default install policy offers to install whatever a cell imports and cannot find, so the "Package Install Required" dialog appears and approving it installs `ipywidgets` before the import runs.
16+
17+
The command line is where the line earns its place. `verso run` never installs on import, and `verso run --auto-install` does not cover this one either, because that policy installs only the distributions Verso keeps a mapping for and `ipywidgets` installs under the name it is imported by. See [Python Packages](python-packages.md) for the policies and how to change them.
18+
1519
```python
1620
import ipywidgets as widgets
1721

@@ -63,7 +67,7 @@ This surprises people most with `anywidget`, because an `anywidget`'s own JavaSc
6367

6468
## anywidget
6569

66-
`anywidget` widgets work the same as any other, live and static, and need nothing configured:
70+
`anywidget` widgets work the same as any other, live and static, and need nothing configured. The install line follows the same rule as the one at the top of this guide, so the editor does not need it:
6771

6872
```python
6973
#!pip anywidget

docs/guides/layouts.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,22 @@ Because a layout can come from an extension, a notebook that depends on one can
2424

2525
## Showcase layouts
2626

27-
The Verso samples include several showcase layout extensions that demonstrate what an isolated layout can do. Each binds to kernel variables and stays in sync with them:
27+
The Verso samples include five showcase layout extensions, each installable from the marketplace and each turning the notebook into something else:
2828

29-
- **Form Studio** is a drag-and-drop dashboard builder. Input widgets write values back into kernel variables, and charts bound to a data variable (a `DataBlock` from `Datafication.Core` or a `System.Data.DataTable`, such as shared SQL results) update as it changes.
30-
- **Grid Studio** presents an editable, spreadsheet-style grid that is two-way bound to a `DataBlock` variable, with type-aware columns. `DataTable` variables display as read-only grids.
31-
- **Image Studio** is a layered image compositor with a canvas, a layer panel, and a tool palette, persisting its state into the notebook.
29+
- **[DAG Notebook](../showcase/dag-notebook.md)** links cells by the variables they share and re-runs a cell's dependents when it finishes, in dependency order.
30+
- **[Slide Studio](../showcase/slide-studio.md)** is a deck editor with a filmstrip, a split editor and output view, and a full-screen presenter mode.
31+
- **[Grid Studio](../showcase/grid-studio.md)** presents an editable, spreadsheet-style grid that is two-way bound to a `DataBlock` variable, with type-aware columns. `DataTable` variables display as read-only grids.
32+
- **[Form Studio](../showcase/form-studio.md)** is a drag-and-drop dashboard builder. Input widgets write values back into kernel variables, and charts bound to a data variable (a `DataBlock` from `Datafication.Core` or a `System.Data.DataTable`, such as shared SQL results) update as it changes.
33+
- **[Image Studio](../showcase/image-studio.md)** is a layered image compositor with a canvas, a layer panel, and a tool palette, persisting its state into the notebook.
3234

33-
These show the range of the layout system: an isolated layout is a full interactive surface that communicates with your notebook's kernels through a defined bridge, not just a static arrangement of cells.
35+
Between them they show the range of the layout system. The first two are inline layouts, arranging the host's real editable cells; the last three are isolated, meaning a full interactive surface that talks to your notebook's kernels through a defined bridge rather than a static arrangement of cells. [Showcase Extensions](../showcase/overview.md) covers all five, how the two kinds differ, and how to install or build one.
3436

3537
## Authoring your own
3638

3739
If you want to build a layout rather than use one, the [Layout Authoring Guide](../extensions/layouts.md) covers both inline and isolated layouts, cell slotting, event routing, theming, and the isolated-frame contract.
3840

3941
## See also
4042

43+
- [Showcase Extensions](../showcase/overview.md)
4144
- [Managing Extensions](managing-extensions.md)
4245
- [Layout Authoring Guide](../extensions/layouts.md)

docs/guides/python-packages.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ An import of something inside a package you already have is never offered. `from
7777

7878
Under `auto`, a name Verso only guessed at is reported rather than installed. Guessing means falling back to using the import name as the distribution name, and that is precisely the case worth being careful about: a typo like `import pandsa` produces a plausible package name that somebody may well have published. Recognized names install silently; guesses are named in the output so you can install them deliberately.
7979

80+
Recognized means the mapping described above knows the name. That covers the packages whose distribution differs from their import, and not the many that install under the name they are imported by, so `import pandas` and `import ipywidgets` are both guesses under this policy. Name those in a `#!pip` line or a declared dependency instead. `prompt` has no such division: it offers everything a cell imports and cannot find, which is why a package that `auto` refuses installs perfectly well in the editor.
81+
8082
The command line never installs anything unless asked. `verso run` uses `off`, and `verso run --auto-install` selects `auto`.
8183

8284
## Declaring dependencies
79.9 KB
Loading

docs/showcase/dag-notebook.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# DAG Notebook
2+
3+
Change a number near the top of a notebook and you have a small chore ahead of you: find every cell below that depended on it and run them, in the right order, without missing one. DAG Notebook removes the chore. It reads the notebook, works out which cells feed which, and when a cell finishes running it runs that cell's dependents for you, in dependency order.
4+
5+
DAG is short for **directed acyclic graph**, which is the shape those dependencies make. Each edge points one way, from the cell that produces a variable to a cell that reads it, and no path leads back to where it started. That second property is what makes the graph safe to run automatically: a notebook whose cells form a loop has no correct order to run them in, so the layout detects loops and refuses to cascade through them.
6+
7+
It looks almost exactly like the notebook layout, which is the point. This is an inline layout, so the cells are the real, editable cells, and the visual base is a faithful match of the built-in one. Everything the layout adds reads as an addition rather than as a different product.
8+
9+
![A notebook where each cell carries a row of chips naming the variables it reads from and feeds to other cells](dag-notebook.png)
10+
11+
The quiet claim it makes is a large one: **a layout extension can change execution semantics, not just presentation.** Reactive execution is usually a property of the notebook tool you chose. Here it arrives as a package, and nothing in the host changes to accommodate it.
12+
13+
## What you see
14+
15+
Each linked cell gets a row of chips above it. `↑ 2 unitPrice` means this cell reads `unitPrice` from cell 2. `↓ 4 revenue` means cell 4 reads `revenue` from this one. `↻ threshold` marks a variable that follows a control rather than a computation. Chips are numbered by document position and tracked by cell identity, so they survive reordering, and clicking one scrolls to the cell at the other end of the link.
16+
17+
A cell whose inputs ran more recently than it did draws a dashed border until it catches up. The mark appears the moment a producer starts running and clears when the cell re-runs, so with the cascade turned off the notebook still tells you what is out of date and simply waits for you.
18+
19+
The layout's own header carries a **Run DAG** button, which runs the whole notebook in dependency order rather than document order, and an **Auto-run dependents** toggle. The host's own Run All is untouched and keeps its normal document-order behaviour. Both coexist on purpose.
20+
21+
## How the graph is built
22+
23+
On every render the layout scans each code cell for the variables it defines, meaning assignments, functions, and type declarations, and the names it references, including names inside interpolated strings. A variable with exactly one defining cell links that producer to every cell that reads it. The scan covers C#, Python, and F#, and it is a lightweight heuristic pass rather than a proof, which the layout is careful to describe as a strong hint.
24+
25+
Two of the ways a cell writes a variable are not assignments at all. `#!bind` shares a widget's trait as a notebook variable, and `Variables.Get("name")` and `Variables.Set("name", ...)` reach the shared store by a name that lives inside a string. Both are read from the source before comments and string literals are stripped, and that single decision is what lets a Python control link to a C# cell instead of the graph stopping at each language boundary.
26+
27+
Ambiguity is surfaced rather than guessed at. A variable assigned in more than one cell produces a warning chip on every writer and no edges at all, so nothing is auto-run on a link the scan is not sure about. Cells that form a cycle are flagged and their cycle edges excluded, which means a cascade cannot loop.
28+
29+
## How the cascade runs
30+
31+
The layout declares the notebook events capability and relays the host's cell execution events into its own interaction handler. When a cell completes successfully and auto-run is on, the layout executes that cell's transitive dependents one at a time, in topological order, through the standard notebook operations. The trigger is a completed run, not a keystroke.
32+
33+
A batch run is not double-executed. The cascade waits a beat before starting, and any cell beginning to run inside that window cancels the pending trigger, so the host's document-order Run All completes on its own terms.
34+
35+
A failure stops the cascade. Cells after the failed one never run and keep their stale marker, and the failed cell gets an error border.
36+
37+
## A control at the top of the graph
38+
39+
`dag-notebook-widget.verso` is the second sample and the shorter one. A Python cell builds an `ipywidgets` slider, one `#!bind` line shares its value as a notebook variable, and two C# cells read that variable. Run **Run DAG** once, then drag the slider and let go: the two C# cells re-run on their own, in order, with nothing clicked.
40+
41+
This works because a variable bound to a widget trait changes when the control moves, with no cell having run at all. The layout watches the shared store for exactly those variables, treats the cell that bound one as its producer, and cascades from there. Moving a slider and finishing a run are the same event as far as the graph is concerned.
42+
43+
The link runs in both directions. Writing the variable from a cell with `Variables.Set("threshold", 80L)` moves the slider on the page, and readings are taken afresh whenever a cell completes, so a cell writing the variable it reads settles after one pass instead of looping.
44+
45+
A drag is coalesced into one run rather than one per step. The sample slider is declared with `continuous_update=False`, which holds its value until the handle is released, but even with continuous updates the cascade runs once per gesture, because a change arriving inside the coalescing window replaces the one before it.
46+
47+
Widgets are live in the editor, whether it is served by `verso serve` or opened in VS Code. A notebook run from the command line has no view to talk to, so there the slider draws from its saved state and the C# cells read whatever value that state holds. See [Interactive Widgets](../guides/interactive-widgets.md) for what makes a widget live and what `#!bind` does.
48+
49+
## Trying it
50+
51+
Open `dag-notebook.verso` from the sample folder. It declares `Verso.Showcase.DagNotebook` as a required extension and pins the layout, so it opens straight into it. The notebook seeds a small pricing model: two base inputs feed revenue, revenue feeds profit, and a summary cell reads all three.
52+
53+
Run everything once with **Run DAG**, then change `unitPrice` in the second cell and run just that cell. Revenue, profit, and the summary re-run on their own, in order. Turn **Auto-run dependents** off and repeat: the downstream cells mark themselves stale and wait. The last two cells both assign `counter` on purpose, so you can see the multi-writer warning chips and the fact that an ambiguous name is left out of the cascade.
54+
55+
The auto-run toggle round-trips through the layout's metadata block, so a notebook saved with it off stays off.
56+
57+
## Notes
58+
59+
A control that drives a cell which writes the same variable back is a loop the scan cannot see, because the write happens at run time rather than in the source. Taking a fresh reading of every bound variable each time a cell completes is what settles it after one pass instead.
60+
61+
The sample bundles no third-party libraries. The stylesheet and the script are part of the sample.
62+
63+
## See also
64+
65+
- [Showcase Extensions](overview.md)
66+
- [Interactive Widgets](../guides/interactive-widgets.md)
67+
- [Layout Authoring Guide](../extensions/layouts.md)
68+
- [Source on GitHub](https://github.com/DataficationSDK/Verso/tree/main/samples/showcase/dag-notebook)

docs/showcase/dag-notebook.png

102 KB
Loading
38.8 KB
Loading

docs/showcase/form-studio.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Form Studio
2+
3+
Form Studio turns a notebook into a small app you can drive. Drag sliders, dropdowns, toggles, text fields, labels, and charts onto a canvas; bind each input to a kernel variable by name; then move a slider and watch the notebook's own code recompute and the charts redraw. The same file is both an editable document and a dashboard, and switching between them is a layout change.
4+
5+
![The Form Studio canvas in Edit mode: a widget palette on the left, a slider and dropdown above two charts, and a properties panel showing the selected slider bound to the kernel variable minUnits](form-studio.png)
6+
7+
It is an isolated layout, so the canvas runs inside the host's sandboxed frame. It pairs kernel data with [Chart.js](https://www.chartjs.org) for the charts, and a chart can plot a `DataBlock` from [Datafication.Core](https://www.nuget.org/packages/Datafication.Core) or a `System.Data.DataTable`, which is what a SQL cell shares to the variable store.
8+
9+
## What it shows
10+
11+
**A dashboard you build by dragging.** Drop widgets onto a canvas, then move and resize them in Edit mode and use them in Preview mode. The canvas you build is the layout's document, saved with the notebook.
12+
13+
**Inputs that write kernel variables.** Each input binds to a variable by name and writes it on change through the layout interaction handler. With auto-run on, the layout re-runs the notebook so downstream cells recompute, then pushes the fresh data back to the charts.
14+
15+
**Charts bound to kernel data.** A chart widget reads a `DataBlock` or a `DataTable` and plots it. Switch the chart type between bar, line, pie, doughnut, and scatter, pick the X and Y columns, and recolor the series. Those visual controls update instantly inside the frame with no kernel round trip, because they change how the data is drawn rather than what the data is.
16+
17+
**A third-party chart library inside a sandboxed frame.** The renderer is a single self-contained module, and Chart.js is vendored and injected at runtime with no network access inside the frame.
18+
19+
**Theme tracking, including on canvas.** The chrome is themed through the host's `--verso-*` CSS variables. Chart.js paints to a canvas, where CSS variables cannot reach, so the sample reads the tokens into the chart options and repaints the charts when the active theme changes. It is a small piece of work and a good illustration of where the CSS-variable approach needs a hand.
20+
21+
## How it works
22+
23+
| Piece | Responsibility |
24+
|---|---|
25+
| `FormStudioLayout.cs` | The layout engine, lifecycle handler, and interaction handler. Seeds the frame, writes input values to kernel variables, re-runs the notebook, and pushes chart data back. |
26+
| `FormDocument.cs` | The persisted canvas: every widget plus the auto-run flag, kept as the frame's own JSON and parsed for the parts the C# side acts on. |
27+
| `DataBlockReader.cs` | Reads a chart source into a serializable shape: a `DataBlock` entirely by reflection, a `DataTable` through its typed API. |
28+
| `assets/form.js` | The frame renderer: palette, drag-and-drop canvas, properties panel, chart wiring, and the bridge. |
29+
| `RendererScript.cs` | Assembles the single renderer module from the embedded assets at runtime. |
30+
31+
The flow starts with the host mounting the frame and installing the bridge. The renderer injects the chart library, registers a message handler, and announces itself as ready. The host returns the saved canvas and the list of variables that could serve as chart sources, and the frame draws the dashboard.
32+
33+
From there, moving an input sends its new value, and the interaction handler writes it to the bound kernel variable. Running cells raises the variable-store change event, at which point the lifecycle handler re-reads each chart's bound source and pushes it into the frame, where the matching chart updates. Structural changes, meaning adding, moving, or configuring a widget, send the whole document, which the host persists through layout metadata so the dashboard is restored when the notebook is reopened.
34+
35+
## The recompute loop
36+
37+
The notebook's compute cell reads the dashboard's inputs with `Variables.Get<T>("name")` and rebuilds the `DataBlock` the chart plots. Reading through the shared store means the cell always sees the live value the dashboard wrote, and `Get<T>` returns a sensible default before any widget is bound, so the same cell still runs correctly on its own in the notebook layout. That property is worth designing for: a dashboard that breaks the notebook underneath it is a worse dashboard.
38+
39+
Auto-run uses the host's execute-all operation and is debounced, so dragging a slider triggers one recompute rather than dozens. Turn auto-run off to recompute only with the **Run** button.
40+
41+
## Reflection, not a project reference
42+
43+
The extension references `Verso.Abstractions` and nothing else. It reads a `DataBlock` by reflection against whichever Core assembly the kernel loaded with `#r "nuget: ..."`, so the charts work regardless of how that assembly arrived. A `DataTable` is a type from the base class library and is read through its strongly-typed API with no reflection needed.
44+
45+
Form Studio only reads its chart sources. Its inputs write plain scalar variables, so there is no write-back of structured data here; that story belongs to [Grid Studio](grid-studio.md).
46+
47+
## Trying it
48+
49+
Open `form-studio.verso` from the sample folder. It declares `Verso.Showcase.FormStudio` as a required extension, so the host installs it from NuGet on open, and it carries a dashboard already built: a slider bound to `minUnits`, a dropdown bound to `region`, and two charts reading `chartData`.
50+
51+
Run the cells to build the `sales` and `chartData` DataBlocks, then click **Preview** and move the slider or change the region. The compute cell re-runs against the value you set and the charts redraw.
52+
53+
![The same dashboard in Preview mode, with the palette and properties panel gone and only the controls and charts left](form-studio-preview.png)
54+
55+
To build one from nothing, click **Edit** and drag widgets from the palette. Select a widget to bind it: an input takes the name of the kernel variable it writes, and a chart takes the name of the variable it reads, plus which column goes on each axis. Deleting the four widgets that ship with the sample and rebuilding them is a quick way to see the whole loop from the other side.
56+
57+
## Licensing
58+
59+
The sample is MIT. It bundles one MIT-licensed library verbatim, with its license text beside it: [Chart.js](https://github.com/chartjs/Chart.js) 4.4.6, the auto-registering UMD build.
60+
61+
## See also
62+
63+
- [Showcase Extensions](overview.md)
64+
- [Grid Studio](grid-studio.md)
65+
- [Layout Authoring Guide](../extensions/layouts.md)
66+
- [Source on GitHub](https://github.com/DataficationSDK/Verso/tree/main/samples/showcase/form-studio)

docs/showcase/form-studio.png

65.8 KB
Loading

0 commit comments

Comments
 (0)