feat(library): document-style File menu for the saved-query Library (#29)#31
Merged
BorisTyshkevich merged 3 commits intoJun 24, 2026
Merged
Conversation
) Reframes the saved-query collection as a named, savable document — "the Library" — with a header File ▾ menu, an editable name, and an unsaved-changes dot, replacing the Export/Import row hidden at the bottom of the Saved panel. State (src/state.js): - libraryName (persisted, key asb:libraryName) + libraryDirty (session-only). - ops renameLibrary / newLibrary / replaceLibrary / appendLibrary / markLibrarySaved; the existing saved-query mutators now mark the Library dirty. New/Replace prune now-dangling tab→saved links; Replace adopts the loaded file's base name and keeps original ids (lossless). Serializers (src/core/saved-io.js): - buildMarkdownDoc / buildSqlDoc — one-way "share" exports (### + fenced sql; /* name + description */ comment + ;-delimited sql). JSON stays canonical. UI: - New src/ui/file-menu.js: the header File ▾ menu (New / Save JSON / Replace… / Append… / Download Markdown / Download SQL + "N in Library" footer), the inline-editable library title with a dirty dot, and Replace/New confirm dialogs. JSON is the only importable format; imported SQL is never run. - app.js mounts the controls in the header and exposes the download / saveStr / FileReader / library-title seams; the obsolete exportSaved/importSavedFile actions are removed. saved-history.js drops savedActions() and relabels the tab "Library". Tests stay at the per-file 100% statements/lines gate (branches ≥90, functions ≥95); adds tests/unit/file-menu.test.js. README documents the Library menu. Builds on the descriptions pre-phase (#29 phase 1, PR #30). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AX4YR7RHKj7JfmS2AqnRrm
…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
…ds (PR #31 review P2) A Replace-loaded JSON containing repeated `id` values previously preserved every duplicate id in savedQueries. The sidebar addresses rows by id (find/filter), so deleting one row removed all duplicates and rename/favorite could affect the wrong row. Now mint a fresh id for any missing OR already-seen id (unique ids preserved), matching the mergeSaved-based Append path which never left duplicate ids behind. Test covers duplicate + missing ids and the mint-collision retry loop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QGBS74oUsXarGkCRQKEFLu
6518b75
into
feat/saved-query-descriptions
1 check passed
BorisTyshkevich
added a commit
that referenced
this pull request
Jun 24, 2026
chore(library): land File menu (#31) onto main — stacked-merge catch-up
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #29. Stacked on #30 (the descriptions pre-phase) — review/merge that first; this PR's base is
feat/saved-query-descriptions, so its own diff is just the File-menu work.What & why
Reframes the saved-query collection as a named, savable document — "the Library" — with a header File ▾ menu, an editable name, and an unsaved-changes • dot, replacing the Export/Import buttons hidden at the bottom of the Saved panel.
Changes
State (
src/state.js)libraryName(persisted,asb:libraryName) +libraryDirty(session-only).renameLibrary/newLibrary/replaceLibrary/appendLibrary/markLibrarySaved. The existing saved-query mutators now mark the Library dirty. New/Replace prune now-danglingtab.savedIdlinks; Replace adopts the loaded file's base name and keeps original ids (lossless).Serializers (
src/core/saved-io.js) — export-onlybuildMarkdownDoc(### name+ optional description paragraph + fenced```sql; 4-backtick fence when the body contains a triple backtick).buildSqlDoc(/* name + description */comment + statement,;-delimited;*/defanged).UI
src/ui/file-menu.js: the header File ▾ dropdown (New Library · Save JSON.json· Replace… / Append… · Download Markdown.md/ Download SQL.sql· N in Library footer), the inline-editable library title + dirty dot, and Replace/New confirm dialogs.app.jsmounts the controls in the header and exposes thedownloadFile/saveStr/FileReader/ library-title seams; the obsoleteexportSaved/importSavedFileactions are removed.saved-history.jsdropssavedActions()and relabels the sidebar tab Library · N.Decisions (per issue #29 + the design owner)
File ▾(the design'sISSUE-library-redesign.mdsayingLibrary ▾is an obsolete doc).Tests
Per-file 100% statements/lines held (branches ≥90 —
file-menu.jsat 95.5%; functions ≥95). Newtests/unit/file-menu.test.jscovers menu structure, Save JSON filename + dirty-clear, Replace confirm/empty paths, Append merge counts, invalid/read-error toasts, New confirm, dialog dismissal, and inline rename.npm test→ 715 passing;npm run buildclean. README documents the Library menu.🤖 Generated with Claude Code