sillsdev / sillsdev/interlinearizer-extension

Analysis catalog: analysis-keyed mutations (edit, merge, delete)

Open
#194 0 comments 0 reactions 1 assignee View on GitHub

@alex-rawlings-yyc is already working on this.

Since Aug 31, 2026.

  • #286 by @alex-rawlings-yyc — open
enhancement
Dominant language
TypeScript
Stars
2
Forks
0
Avg merge
1d 17h
Merged PRs (30d)
55

Description

Makes the Analysis Catalog (#186) editable. Depends on the read-only panel.

Analysis-keyed reducers — the key is the blast radius

The existing reducers (writeGloss, writeMorphemes, writeMorphemeGloss) take a tokenRef and fork any shared payload, so they are inherently per-token. The catalog has no token in context — a row is the shared analysis — so it needs a second family keyed by analysisId that never forks:

writeAnalysisGloss({ analysisId, value })
writeAnalysisMorphemes({ analysisId, forms })
writeAnalysisMorphemeGloss({ analysisId, morphemeId, value })
deleteAnalysis({ analysisId })
mergeAnalysisInto({ sourceAnalysisId, targetAnalysisId })

Because the key alone determines scope — tokenRef → per-token (forks), analysisId → global (never forks) — no scope flag and no intent-recovery confirmation modal is needed.

Do not collapse the two families into one reducer parameterized by a boolean. That would put the local/global distinction behind a flag, which is exactly the distinction worth keeping structural.

Each new reducer calls mergeIntoIdenticalPayload after its edit, as the per-token reducers do, and returns enough for the UI to report what happened.

Operations

  • Edit gloss and morpheme breakdown. Editing a row's breakdown fixes every usage at once — 100 occurrences of a mis-split word are one row, one edit.
  • Merge into another row, first-class and prominent when the row has pool peers. Most deletions are really re-assignments: merge moves the links instead of stranding them. mergeIntoIdenticalPayload (src/store/analysisSlice.ts) already performs this when an edit makes two payloads identical.
  • Delete, with a ModalShell confirmation stating the concrete outcome rather than a generic "are you sure". Deleting an analysis also removes it from the suggestion pool, so unless a competing homograph survives, all N tokens go genuinely blank rather than falling back to a suggestion. The confirmation must say which case applies.
  • Merge-on-edit must be visible. Editing row A into equality with row B makes A vanish and B's count jump; unexplained that reads as data loss. Surface it ("merged into beginning, now 59 usages") and scroll to the combined row.

Single-row only — no multi-select, no bulk edit.

Behaviors to test

Reducers:

  1. writeAnalysisGloss changes the gloss for every token linked to the payload — no fork.
  2. writeAnalysisMorphemes likewise.
  3. deleteAnalysis removes the payload and every link to it; the affected tokens read as blank.
  4. deleteAnalysis on a payload with a surviving homograph peer leaves the tokens falling back to that peer as a suggestion — the two delete outcomes differ, and the confirmation must be able to tell them apart.
  5. mergeAnalysisInto moves every link to the target and drops the source; the target's usage count becomes the sum.
  6. Editing row A into content-equality with row B collapses A into B via mergeIntoIdenticalPayload, and the surviving row is B.

Panel:

  1. Editing a row's gloss updates the interlinear view for all its tokens in one edit.
  2. Delete opens a ModalShell confirmation naming the concrete outcome — "N tokens will become blank" vs "N tokens will fall back to " — driven by behavior 4.
  3. Canceling the confirmation leaves the analysis untouched.
  4. Merge is offered prominently when the row has pool peers, and not at all when it has none.
  5. After a merge-on-edit the panel announces it and scrolls to the combined row — the row must not simply vanish.

The sharp edge

Delete ships before undo (#184). #186 accepts this explicitly. The confirmation copy is the only guard, so behaviors 4 and 8 are the highest-value tests here — an inaccurate confirmation is worse than none.

Lexicon

No lexicon calls. Lexicon references (glossSenseRef, entryRef, senseRef, allomorphRef, grammarRef) are outbound only: editing or deleting an analysis drops our reference and leaves the lexicon untouched. Nothing here may cascade into the lexicon.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.