Files
astrolabe/docs/spec/03-editor-and-drafts.md

95 lines
12 KiB
Markdown

# 03 · Spec Editor & Draft/Published Workflow
The center pane is where the user reads and edits the active snippet's Vega-Lite specification. It is a code editor for JSON paired with a Draft/Published workflow: edits are made against a working draft that auto-saves silently, drive the _Live Preview_ automatically, and become the snippet's stable version only when explicitly published. The pane is empty when no snippet is selected; it loads the active snippet's spec when one is chosen in the _Snippet Library_.
## A. The Spec Editor
The editor presents the active snippet's spec as formatted JSON with full code-editing affordances tuned for Vega-Lite.
- The editor displays the spec as indented, readable JSON with syntax highlighting.
- As the user types, the spec is validated against the Vega-Lite schema; problems are surfaced as inline indicators at the offending locations (e.g. squiggles/markers), without blocking continued editing.
- The editor offers schema-driven autocomplete/suggestions while typing (property names and allowed values from the Vega-Lite schema).
- Pasting content reformats the spec automatically so it stays consistently indented; while typing, the editor maintains consistent indentation as new lines are entered (auto-indent). A format-on-demand action reflows the whole spec to the same compact, readable style.
- The editor's appearance and behavior — font size, editor theme, minimap visibility, word wrap, line numbers, and tab size — are configurable and read from _Settings_; this section does not redefine their defaults.
- The editor always edits a single active snippet. Selecting a different snippet in the _Snippet Library_, or toggling the Draft/Published view, replaces the editor content with the corresponding spec.
### Scaffolding assistance
Beyond the schema's own suggestions, the editor scaffolds common Vega-Lite structures as ready-to-fill skeletons, seeded from the data actually in scope at the cursor. An inserted skeleton arrives with editable placeholders (Tab moves between them), pre-filled with type-appropriate values where the data allows and descriptive names otherwise. Scaffolding acts on the draft only — the published view is a read-only reference and offers none of it.
- **Data transforms.** With the cursor in a view, inline actions above the code offer the pipeline: _Add transform_ when the view has none, the common steps (filter, aggregate, calculate, bin, timeUnit) on an existing `transform` array. Inside a `transform[]` element slot, typing offers the full step catalog as completions, each seeded with a matching column (a numeric field for aggregate, a temporal one for timeUnit). A step added on a composition parent notes that it applies to every child view below it.
- **Parameters.** The same affordance for `params`, split by where Vega-Lite allows each family: **variable** widgets (slider, dropdown — an input control bound to a name the spec can reference) are offered at the spec's top level, the only place they are legal; **selection** parameters (point, interval — interaction on the chart's marks) on the unit view the cursor is in; in a single-view spec, where the top level is the unit, both appear together. Inside a `params[]` element slot, completions offer the catalog — both families in the top-level array, selections only in a nested view's. Defaults are data-seeded where possible: a slider's min/max/step from the numeric field's actual range, a point selection's field from a categorical column.
## B. Auto-Save of the Draft
Edits persist automatically so the user never loses work and never needs an explicit "save" action for ordinary editing.
- A short moment after the user stops typing, the current editor content is parsed and stored as the snippet's working draft, silently and with no notification.
- Auto-save only commits when the editor content is valid JSON; if the content is momentarily unparseable, the save is skipped and retried after the next pause in typing, so a half-typed spec never overwrites the stored draft.
- Auto-save writes the **draft** only. It never alters the published version (see _D. Draft vs Published_).
- Auto-save is distinct from Publish: auto-save preserves in-progress work; Publish promotes that work to stable.
## C. Auto-Render to Preview
Edits flow to the _Live Preview_ automatically, so the user sees results without invoking a render.
- A brief moment after the user stops typing, the current spec is sent to the _Live Preview_ for rendering.
- The delay before rendering is a configurable debounce (see _Settings_ / _Live Preview_), letting the user trade responsiveness against churn while typing heavy specs.
- Rendering also occurs immediately when a snippet is first loaded into the editor or the Draft/Published view is switched.
- Rendering specifics (dataset reference resolution, fit modes) belong to _Live Preview_; the editor's role is to supply the current spec text on each settle.
## D. Draft vs Published Workflow
Every snippet carries two versions of its spec: a **published** (stable) version and a **working draft**. This separation is the central editing model. A view toggle in the pane header switches which version the editor shows.
- The header offers a Draft/Published toggle; the currently active view is visually indicated.
- **Draft view** shows the working draft and is the editable surface — all typing, auto-save, and auto-render act on the draft.
- **Published view** shows the last published version, for reference; the published version is never modified by ordinary editing.
- Editing the draft never touches the published version until the user publishes.
- The _Snippet Library_ status indicator reflects whether a snippet currently has unpublished draft changes (draft differs from published); this section only produces that difference, it does not render the indicator.
### Publish
- A **Publish** action promotes the current draft to become the published version (the two are made identical).
- Publish is also triggered by the keyboard shortcut Cmd/Ctrl+S.
- If the snippet's name is **app-picked** (never explicitly renamed by the user — the timestamp default, a builder-generated name, or an earlier derived one), publish re-derives it from the now-published content: the spec's `title` verbatim when present (string, line array, or `{ text }` forms), else a mark + encodings description in the Chart Builder's naming dialect (e.g. "Bar chart of count by Ship Mode"), else the existing name stands. A name the user has set is never rewritten (see _Snippet Library → Naming & Tags_).
- The snippet's dataset references track the draft continuously (recomputed on auto-save, extract, and revert), so publish needs no special reference handling — promoting the draft simply carries the already-current references onto the published version (see _Datasets_ for reference linking).
- A success toast confirms the snippet was published.
- Publish is unavailable when no snippet is active.
### Revert
- A **Revert** action discards all draft changes and restores the draft to match the last published version.
- Revert requires explicit confirmation before discarding, warning that the action cannot be undone.
- On confirmation, the editor reloads with the published spec and a toast confirms the draft was reverted.
- Revert is unavailable when no snippet is active.
## E. Error Surface
When the spec cannot be parsed or cannot be rendered, the problem is shown clearly while keeping the user in place to fix it.
- When the spec is invalid JSON, or is valid JSON but fails to render as Vega-Lite (including an unresolved dataset reference or a malformed Vega expression), a clear, readable error message appears in the **preview pane, in place of the chart** — a spec either renders or shows its error, never both.
- The message is plainly legible (monospaced, distinct from normal content) and leads with the location or the problem, then the detail — for example `Line 14 · Unexpected end of input` or `Dataset "sales" not found · create it from Datasets`.
- In the **editor**, the offending spot is marked with an inline squiggle — a JSON syntax error where it occurs, a malformed expression on its own string — so the cause is locatable without leaving the code.
- The editor remains fully usable while an error is shown, so the user can edit to fix it; the error clears automatically once a subsequent edit renders successfully.
## F. Extract Inline Data to a Dataset
When a snippet's spec embeds its data inline, the user can lift that data out into a reusable, named dataset and have the spec reference it instead. This keeps specs lean and lets the same data serve multiple snippets (see _Datasets_).
- When the active snippet's draft spec contains inline data, an **Extract to Dataset** action is available in the pane header; it is hidden when the spec has no inline data.
- Choosing it opens a modal that shows a read-only preview of the inline data and asks the user for a dataset name (required).
- The user enters a name and confirms creation. Names must be non-empty and unique; if the name is blank or already in use, the modal shows an inline error and the action does not proceed.
- On success, the system: saves the inline data as a new dataset (preserving its detected format), rewrites the snippet's draft spec so the inline data is replaced by a reference to the dataset by name, links the dataset to the snippet **immediately** (the link appears without waiting for a publish, since references track the draft), and reloads the editor to show the rewritten spec. Reverting the draft before publishing removes the link again.
- A toast confirms the dataset was created, and the modal closes.
- The user can cancel the modal at any time, leaving the spec unchanged.
- Dataset-side specifics (formats, storage, the bidirectional snippet↔dataset link) are described in _Datasets_.
## G. Spec ↔ Config Actions
Three editor actions make the injected chart theme portable (see _Live Preview → Chart theme_). Their visible home is a **Config** menu in the editor toolbar (a value-select disclosure listing the actions with a one-line description each), disabled when no snippet is active or the read-only published view is shown; the editor's right-click context menu and F1 command palette offer the same actions as expert accelerators. All replace the document as a single undoable edit (⌘/Ctrl+Z restores), reformatted in the app's JSON style, and all refuse with a clear toast when the document is not a valid JSON object.
- **Merge Chart Theme into Spec** — bakes the currently selected chart theme into the spec's own `config` block, deep-merging under any existing `config` so the spec's own keys win and the rendered result is unchanged. Use it before publishing a spec somewhere the app's theme won't follow. When the selected theme injects nothing (Stock Vega-Lite), the action explains there is nothing to merge.
- **Extract Config from Spec** — removes the spec's `config` block and copies it to the clipboard, for cleaning baked-in styling out of a pasted spec. The clipboard copy happens **before** the removal; if the copy fails, the spec is left unchanged so the config is never lost. A spec with no config block reports that and changes nothing.
- **Extract Config to New Theme** — removes the spec's `config` block and saves it as a new custom chart theme (see _Live Preview → Theme Builder_), named after the snippet and auto-suffixed if taken, then selects that theme as the active chart theme so the styling keeps applying to this chart from the injected side. The success toast names the created theme and points at Edit themes… for renaming or refining. A spec with no config block reports that and changes nothing. (If a non-stock theme was active before, any of its keys the extracted config didn't cover stop applying — the new theme replaces it wholesale.)