Add analysis-keyed mutations (edit, merge, delete) - #286
Open
alex-rawlings-yyc wants to merge 14 commits into
Open
Add analysis-keyed mutations (edit, merge, delete)#286alex-rawlings-yyc wants to merge 14 commits into
alex-rawlings-yyc wants to merge 14 commits into
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
alex-rawlings-yyc
force-pushed
the
analysis-catalog-mutations
branch
2 times, most recently
from
September 1, 2026 22:47
2dc45e8 to
621ba4b
Compare
The catalog's rows are shared TokenAnalysis payloads with no token in context, so the existing tokenRef-keyed reducers cannot serve them: those fork a shared payload to keep an edit local to one token, which is the opposite of what editing a catalog row means. Add a second reducer family keyed by analysisId — writeAnalysisGloss, writeAnalysisMorphemes, writeAnalysisMorphemeGloss, deleteAnalysis, and mergeAnalysisInto — that never forks. The key alone determines the blast radius, so neither family needs a scope flag. Each write re-converges onto a content-identical sibling as the per-token path does. Add selectAnalysisDeletionOutcome, which reports whether deleting a row leaves its tokens blank or falling back to a surviving homograph, so the confirmation can name the concrete consequence. It rebuilds the pool with the payload dropped outright rather than discounting a single approval, which would leave a multi-token payload competing to replace itself. Add selectAnalysisMergePeers to offer merge targets from the row's own pool bucket, so merging is confined to genuine homographs.
Reconcile the filter selections against the facets each render, so a selection cannot outlive the choice it names: an edit beside the panel that empties a facet no longer strands the listing behind a control that is off screen. Distinguish a placeholder label from a real value reading the same, the platform combo box resolving a selection by its label alone. Carry an unchanged morpheme across a re-split whole, keeping the id its references depend on along with its gloss and lexicon refs. Count the deletion preview's usages off the approved-token index the catalog row counts by, as its own doc already promised.
Merge peers came off the suggestion pool, which admits approved analyses alone, so an imported homograph was listed as a catalog row that could neither be merged into nor merged away. Index every payload by surface form instead, matching what mergeAnalysisInto already accepts.
Commit the reconciled set back over the reader's choices, so a value dropped from a facet is gone rather than merely unused. Held, it returned the moment its facet did: an edit that withdrew the last row carrying a chosen value, undone, left the listing narrowed by a filter the reader had watched release, with the restored row the only one it kept.
The catalog listed what the draft records without offering any way to correct it, while the reducers that would do so had no caller. A row is a shared analysis with no token in context, so editing one is an edit to every token linked to it — the correction a mis-split word repeated a hundred times needs. Expanding a row now reveals its gloss, its morpheme breakdown and each morpheme's gloss, and the controls for merging or deleting it. Fields commit on blur and Enter and revert on Escape, so an edit is not written across every token of an analysis mid-word. Deleting is confirmed by a modal naming the concrete consequence — how many uses go blank, or which surviving homograph they fall back to. Delete ships before undo, so that copy is the only guard, and a confirmation that promised a fallback that does not exist would be worse than none. Merging is offered only to a row with pool peers, since there is otherwise nothing to reassign its tokens to, and preselects no target: it moves every use of one analysis onto another and drops the source. An edit that makes a row identical to a sibling collapses the two, which leaves the edited row gone from the listing and another's count grown. A banner above the list now names where the edit went and what the survivor counts, and the listing scrolls to it, so the pair reads as the convergence it is rather than as lost work. Nothing the write reports says a collapse happened, so the dispatch hook reads the store either side of it and follows the old links to see where they now point. Merge peers are bucketed by the normalized surface form the pool buckets by; grouping by the raw text would offer the control to homographs differing only in case and then open an empty picker. The platform-bible-react stub's Input dropped onBlur, which left every commit-on-blur field silently uncommitted in tests.
readEditOutcome treated any link surviving on the edited record's tokens as the survivor of a collapse. A token may hold several links at once — the one-per-token invariant covers only approved ones — so emptying a record whose token kept an unrelated suggested or candidate link reported a merge into a record that had gained nothing. Identify the survivor instead by a link naming a record its token was not already linked to, which only a collapse produces. Register the catalog row editor's drafts with the pending-edit tracker, as the interlinear view's inputs already do. The gloss fields commit on blur, so this only lights the unsaved indicator while typing; the breakdown editor commits on Enter or Save alone, and its draft was discarded by a project switch with no confirmation. Compare the draft as forms rather than as text so the whole word pre-filled for an unsegmented breakdown does not register as unsaved work.
readEditOutcome inferred a merge from links the edited record's tokens had moved onto. A record no token links to moves none, so collapsing one left exactly the state its removal would leave and was reported as a removal — the row vanished with no notice, for the unused records a Paratext 9 import lands by the hundred. Record the survivor in the reducer that collapses the record, where the payload deciding merge-from-removal is still in hand, and read it back through transient state that never reaches storage. Compare useAnalysisMergePeers shallowly. Its selector filters per row and so allocates a fresh array on every call, re-rendering every row holding peers on every store change. Cover the analysis-keyed hooks directly rather than through the panel, where their write outcomes were asserted only as the absence of a notice element — three distinct paths sharing one negative DOM fact.
Three ways the catalog dropped work or the thread of it. A merge notice names the row an edit collapsed onto and scrolls to it, but the reveal only fires for a row the window has mounted. An unlinked record inherits no usages to carry its survivor up the listing, so the survivor stays where its gloss sorts it — past the first chunk, and the notice pointed at nothing on screen. Let a caller name a row the window must cover, applied over the count so a new listing still resets. The breakdown editor held its draft itself, and the breakdown commits on neither blur nor unmount, so collapsing the row or a query that stopped listing it took a typed re-segmentation with it. Hold the drafts in the panel, which outlives all three routes, and report them from there — the editor unmounts while the draft it was reporting for is still owed. Clearing the breakdown drops every morpheme gloss on the record, for every token it holds, and nothing forks a copy first. Confirm it, as the token editor confirms its own reset.
The breakdown editor commits on neither blur nor unmount, so a re-segmentation survives a row collapsing or a query that stops listing it. Closing the panel ended that silently: the draft went with the unmounted panel, and the unsaved marker cleared with it. Gate the close control on the predicate the unsaved marker already reported, and offer discard alone — saving would commit an edit that drops the old morphemes' glosses for every token the record holds. The question is mounted on the draft still standing as well as on the ask, so saving or canceling it from the row beneath withdraws the question instead of asking about work that is no longer unsaved.
Both breakdown editors now name the forms whose glosses a re-split would drop and confirm first, matching the prompt each already showed for clearing a breakdown outright. The token editor skips the prompt for a shared payload, which the write forks rather than re-segmenting in place.
alex-rawlings-yyc
force-pushed
the
analysis-catalog-mutations
branch
from
September 2, 2026 19:57
02b4532 to
af36923
Compare
An imported analysis no longer offers editors or merge/delete, and a breakdown draft whose row an edit elsewhere removed is now reported.
alex-rawlings-yyc
marked this pull request as ready for review
September 2, 2026 21:23
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.
This change is