Skip to content

fix(ui): keep the draft when autocomplete creates a new page - #101

Merged
sanity merged 4 commits into
mainfrom
fix-68
Oct 14, 2026
Merged

sanity merged 4 commits into
mainfrom
fix-68

Conversation

@sanity

@sanity sanity commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Problem

In the editor, picking "+ Create ..." from the [[ autocomplete called state::create_page, which sets CURRENT_PAGE to the new page. The handler then set EDITING = false ("switch back to the page we were editing") but never restored CURRENT_PAGE, so the user landed on the new empty page and the draft, including the link just inserted, was thrown away (#68).

Approach

  • state::create_page is split into add_page (adds the page and returns Some(id), does not navigate, and changes nothing when it returns None) and create_page (add_page and then open it in the editor). The sidebar's "+ New Page" still uses create_page. For non-owners, create_page is now a no-op. Before, it pointed CURRENT_PAGE at a page that didn't exist, but the button is owner-only anyway.
  • Autocomplete picks go through insert_link_target(LinkTarget, pos), which replaces the u64::MAX sentinel. For New it uses add_page, so CURRENT_PAGE and EDITING never change. The seeding effect from fix(ui): stop the editor re-seeding over an in-progress edit #64 sees the same page identity and a buffer that no longer matches what it seeded, so it leaves the draft alone.
  • The new id comes from add_page's return value. The old next_page_id - 1 was wrong when no page was added.
  • An open [[query before the cursor is checked before creating anything, so a stale cursor can't leave an orphan page. The query span is rejected if it contains ]] or a newline, the same rule update_autocomplete uses.
  • Also fixed while there: the keyboard Enter/Tab path rebuilt the candidate list without excluding the current page, while the dropdown excludes it, so the highlighted row and the inserted link could differ. It now indexes the rendered list, through selected_link_target.
  • AGENTS.md's page-order invariant and the allocation comments now name add_page, which owns id and order allocation.

Testing

  • VirtualDom tests in editor.rs (reseed_tests) mount the real Editor:
    • creating_a_page_from_autocomplete_keeps_the_draft_and_the_link checks that the editor stays on page 1 and stays open, and that the buffer is intro [[<new id>]] and the rest with the retitle kept. The draft also survives a handle_signed_page-shaped replacement of the new page in SITES. There is a positive control showing the seeding effect is live. Mutation-checked: making the create branch move CURRENT_PAGE again makes the test fail.
    • ..._on_a_site_we_do_not_own_changes_nothing checks that no page is added, no link is inserted, and CURRENT_PAGE is unchanged.
    • create_page_still_opens_the_new_page_in_the_editor guards the sidebar path.
  • Unit tests:
    • selected_link_target: maps a row index to a page or to the Create row.
    • splice_link: covers a stale or mid-multibyte cursor, a closed link, and a newline.
  • No event-level test covers the keydown handler, because the harness does not simulate key events. The handler is now a one-line call into the tested selected_link_target, using the same Vec the dropdown iterates.
  • These pass locally: cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test (delta-ui: 248 passed), and the wasm32 check.

Review

Light tier with two lenses (skeptical, code-first). The first pass found nothing blocking. Its should-fix findings were the untested dispatch and keyboard path, the untested delegate-response path, the orphan page on a stale cursor, and the stale AGENTS.md and comments. All are addressed in be9bfd9, and that head has been re-reviewed.

This is a UI-only change, so the contract and delegate WASM are untouched. It needs a Delta UI republish to reach users.

Closes #68

[AI-assisted - Claude]
https://claude.ai/code/session_01GKBuAzByqMPegsXcUYJb7h

The editor's "+ Create" autocomplete called state::create_page, which
moved CURRENT_PAGE to the new empty page; nothing moved it back, so the
editor closed on the wrong page and the draft, including the link being
inserted, was lost.

Split create_page into add_page (adds the page, returns its id, no
navigation) and create_page (add_page + open it). The autocomplete uses
add_page, so CURRENT_PAGE and EDITING never change and the seeding
effect leaves the edited buffer alone. The new id comes from add_page
rather than next_page_id - 1, which was wrong when nothing was added.

Also make the keyboard Enter/Tab path index into the same candidate list
the dropdown renders. It rebuilt the list without excluding the current
page, so the highlighted row and the inserted link could differ.

Closes #68

Claude-Session: https://claude.ai/code/session_01GKBuAzByqMPegsXcUYJb7h
- Replace the u64::MAX "create" sentinel with a LinkTarget enum, and
  route both the mouse and keyboard picks through insert_link_target so
  the tests exercise the real dispatch. The keyboard row -> target
  mapping is now a pure, unit-tested selected_link_target.
- Check for an open [[query before creating anything, so a stale cursor
  cannot leave an orphan page; refuse a span containing ]] or a newline,
  matching update_autocomplete, so a stale cursor cannot overwrite a
  finished link.
- Test: the draft survives the delegate's signed copy of the new page
  landing in SITES, plus the usual positive control.
- Point AGENTS.md's page-order invariant and allocation comments at
  add_page, which now owns id and order allocation.

Claude-Session: https://claude.ai/code/session_01GKBuAzByqMPegsXcUYJb7h
Also tighten selected_link_target's doc to say the Create row is only
reachable when rendered, and rewrap add_page's doc comment.

Claude-Session: https://claude.ai/code/session_01GKBuAzByqMPegsXcUYJb7h
selected_link_target now takes the shown Create row's title (or None)
and only maps the index just past the page rows to it, so a stale
ac_selected cannot create a duplicate from a hidden row. The #68 test
no longer edits the title, so content survival is pinned on its own.

Claude-Session: https://claude.ai/code/session_01GKBuAzByqMPegsXcUYJb7h
@sanity
sanity merged commit 4fa1f4f into main Oct 14, 2026
3 checks passed
@sanity
sanity deleted the fix-68 branch October 14, 2026 11:11
sanity added a commit that referenced this pull request Oct 15, 2026
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.

Autocomplete 'create new page' never restores CURRENT_PAGE, discarding the draft and the inserted link

1 participant