Skip to content

feat(library): optional descriptions for saved queries (#29 phase 1)#30

Merged
BorisTyshkevich merged 2 commits into
mainfrom
feat/saved-query-descriptions
Jun 24, 2026
Merged

feat(library): optional descriptions for saved queries (#29 phase 1)#30
BorisTyshkevich merged 2 commits into
mainfrom
feat/saved-query-descriptions

Conversation

@BorisTyshkevich

Copy link
Copy Markdown
Collaborator

What & why

Pre-phase for #29 (document-style "Library" File menu). Adds an optional free-text description to saved queries, surfaced via the two editing screens from the current Altinity Play design.

This ships independently; the File-menu / library-name / dirty-dot work follows in phase 2.

Changes

  • src/core/saved-io.jsdescription round-trips losslessly through the JSON envelope: carried by buildExportDoc, normalized by parseImportDoc (non-strings dropped), and handled by mergeSaved (add / replace-by-id / drop-on-update), mirroring the existing chart/view treatment.
  • src/state.jssaveQuery(state, tab, name, description, …) and renameSaved(state, id, name, description, …) now take a description; renameSaved leaves it untouched when the arg is undefined (name-only rename), sets/clears it otherwise.
  • src/ui/app.js — the editor Save popover gains a "Description — optional" textarea (⌘/Ctrl+Enter commits; plain Enter inserts a newline), prefilled from the linked saved entry.
  • src/ui/saved-history.js — the Saved-panel pencil ("Edit name & description") opens an expanded Name + Description edit form (Name⏎ / Desc⌘⏎ commit, Esc/Cancel revert); read-rows render a 2-line description preview above the SQL preview.
  • src/styles.css — styles for the popover textarea, the edit form, and the row description preview (reuses existing tokens).

Tests

Per-file 100% statements/lines gate held (functions ≥95 / branches ≥90). New/updated coverage in saved-io, state, saved-history, and app specs: description export/import/merge, save/rename set·update·clear·keep-existing, the edit-form commit/cancel paths + double-fire guard, the row description preview, and the popover prefill + ⌘Enter commit.

npm test → 693 passing, all thresholds met. npm run builddist/sql.html builds clean.

Design source: Claude Design project Altinity Play (build 2026-06-24) — SavedItem + EditorToolbar save popover.

🤖 Generated with Claude Code

Saved queries gain an optional free-text `description`, surfaced via the
two editing screens from the current Altinity Play design:

- the editor Save popover gains a "Description — optional" textarea
  (⌘/Ctrl+Enter commits; plain Enter inserts a newline);
- the Saved-panel pencil ("Edit name & description") opens an expanded
  Name + Description edit form, and read-rows render a 2-line description
  preview above the SQL preview.

`description` round-trips losslessly through the JSON envelope
(buildExportDoc / parseImportDoc / mergeSaved, mirroring chart/view).
`saveQuery` and `renameSaved` take a `description` arg; `renameSaved`
leaves it untouched when the arg is undefined (name-only rename). All
layers stay at the per-file 100% statements/lines coverage gate.

Pre-phase for the document-style "Library" File menu (#29 phase 2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AX4YR7RHKj7JfmS2AqnRrm
… review)

- parseImportDoc now trims `description` and drops a whitespace-only one, matching
  saveQuery/renameSaved. Import was the only entry point that passed it through
  verbatim, so a blank/whitespace description leaked into a visible empty .desc
  band and round-tripped on re-export.
- renameSaved coerces with String(description || '') like saveQuery, so a null
  (distinct from undefined) clears the note instead of storing the literal 'null'.

Tests cover both new branches (whitespace-import dropped; null-rename cleared).
Cleanup-only refactors from the review were intentionally skipped to keep the
merge surface small (saved-io.js/state.js are being edited in parallel on
another branch); the pre-existing raw-NUL contentKey separator is left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
BorisTyshkevich added a commit that referenced this pull request Jun 24, 2026
…file-menu + review fixes

Resolves the binary-merge conflict on src/core/saved-io.js and folds in the
PR #30 review fixes plus PR #31 (File menu) review fixes found this pass.

saved-io.js (conflict resolution + fixes):
- Kept PR #31's feature-complete version (buildMarkdownDoc/buildSqlDoc, append).
- Converted the raw NUL byte in contentKey to the '\0' escape, so the file is
  text again — that NUL is what made it binary-to-git and un-3-way-mergeable.
- Re-applied the PR #30 fix: parseImportDoc trims `description` (drops whitespace-
  only), matching saveQuery/renameSaved.
- buildMarkdownDoc collapses whitespace in the `### name` heading so a query name
  with a newline can't break the cookbook structure.

file-menu.js (PR #31 review fixes):
- CRITICAL: the File menu read bare `app.document` (undefined — createApp only
  exposes a local doc), so it threw on first click in production. Use
  `app.document || document`, matching shortcuts.js/results.js. Tests passed only
  because the fake-app supplies document.
- Anchor the dropdown via zoomScale() (divide getBoundingClientRect by the
  html{zoom} scale), like the editor popovers — it mis-anchored ~20% off otherwise.

state.js auto-merged: renameSaved keeps both PR #30's null-safe String(... || '')
and PR #31's libraryDirty flag.

All 715 tests pass; per-file coverage gate holds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
@BorisTyshkevich BorisTyshkevich merged commit 518f06c into main Jun 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant