Note order, insertion and Sweep Empty
Contributor notes for three Note Tray behaviours that share one data path: reordering notes, inserting a note at a position, and the reviewed Sweep Empty batch delete. The user-facing description is the Japanese manual's ノート and 検索 pages.
Reordering
One pointer gesture serves both surfaces; see ui-components → Ghost reorder for its lifecycle and cancel rules.
| Surface | Wiring |
|---|---|
| Note Tray tabs | packages/ (useDraftBarReorder); DraftBar spreads tabProps and renders composeSequence. Native HTML5 tab drag is gone. |
| Pile cards | tauri-: handle-only grip in the card header, CSS order for the live preview, optimistic order until the next refresh. |
| Provider glue | hooks/, utils/ (participants, commit, Move earlier / Move later, New note before / after, Arrange toggle). |
Rules:
One commit per valid changed drop. The commit writes the visible permutation of the participants that share the source's group; non-participants keep their slots (the tray store's optimistic order preserves this).
Pile Manual sort (
pileView.sort.field: "manual", validated inapp-defaults) follows the workspace note order, the same order the tabs use. The first changed drop while sorted by Created or Updated writes the visible permutation and switches the sort to Manual.canonical-notessubscribeIndexmarks every row of an order publication withorder: true(NoteIndexChange.order); the shared index (workspace-note-index.ts) re-slots notes only for a flagged batch. An unflagged multi-row metadata batch never reorders.
Insert at a position
New note before / after, and Arrange mode's insertion buttons, call useNoteInsertPlacement (services/). The note is created normally (instantly, with a pending number) and a placement intent waits for its permanent number, then writes the order. Statuses: waiting, placing, failed (anchor-missing or write-failed), dismissed. A failed placement leaves the note and its text intact and offers Retry placement or Keep note here. Intents are in memory only: a reload loses them and the note keeps its default position. With numberOrder: "desc" the visual before/after is mapped to the canonical side (canonicalInsertSide).
Pending number identity
packages/ documents the bounded geometry policy in its header (also summarised in ui-components). Provider-side helpers live in lib/ (noteNumberLabel, noteIdentityName, unnumberedNoteIds). A locally durable, canonical-pending note renders the centered glyph in the slot, with an accessible name such as "New note, followed by its status" and data-number-pending. The word "Unnumbered" is no longer rendered; the status bar says "New note — getting its number".
Sweep Empty
| Piece | File |
|---|---|
| Plan, protection, recheck, run, retry | tauri- |
| Review / result state | hooks/ |
| Inline review and result panel | components/ |
| Single body-empty rule | isNoteBodyEmpty in lib/ (also drives the Pile is:empty filter) |
| Selection follow-up | hooks/, driven by the notes:swept app event |
Contract:
Scope is the Pile's settled visible results: the current search results, or the whole Pile when there is no query. The button is disabled while the search or IME composition is unsettled. The plan never broadens afterwards.
Frozen plan. Review freezes, per target, the UUID, path, version, location revision, workspace, key generation and one operation id.
Protected (kept, with the reason shown):
creating(no acknowledged create or no permanent number),unsaved,conflict(including held uploads) andunavailable. A locally durable note whose upload is merely queued is sweepable; the canonical outbox orders the delete after the upload.Recheck. Every target is re-read and rechecked immediately before its delete, and the canonical
deleteByIdguard rechecks it again. Anything edited, moved or newly protected since review is kept.Outcomes per target:
deleted,kept,failed,uncertain,cancelled. Retry reruns onlyfailedanduncertaintargets with the same operation ids; an uncertain target is reconciled by re-reading it, never deleted twice. A workspace or key change cancels the rest of the batch.Each completed delete calls
announceClearedSlot(marks the slot deleted, evicts the cache, broadcasts the deletion) and thenotes:sweptevent releases retained tabs and moves a swept selection to the next surviving note, else the previous one, else a genuinely empty tray with no replacement note.broadcastSweptNotesalso relays akind: "swept"frame (chunked at 200 ids) over the note restore/delete relay, and popout trays replay it asnotes:swept.Escape closes the review or result step only, never the Pile, and focus returns to the Sweep Empty button.