Skip to content

Add the QTI associate interaction plugin - #6113

Open
rtibblesbot wants to merge 5 commits into
learningequality:unstablefrom
rtibblesbot:issue-6101-e6feda
Open

Add the QTI associate interaction plugin#6113
rtibblesbot wants to merge 5 commits into
learningequality:unstablefrom
rtibblesbot:issue-6101-e6feda

Conversation

@rtibblesbot

@rtibblesbot rtibblesbot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

"Connect pairs" questions could not be authored: an item whose body is <qti-associate-interaction> had no plugin, so its header read "Unknown type" and its body was uneditable. This adds the plugin end to end — the flat choice pool parses into correct pairs plus distractors, serializes back to a cardinality="multiple" base-type="pair" declaration, validates, and renders in an editor.

References

Fixes #6101.

Reviewer guidance

JS tests pass on CI. Beyond those, on the QTI demo page (/channels/<id>/#/qti-demo, question 7):

  1. Edit the item, add a pair, and type into both cards — the header stays "Connect pairs" and the correct-response <qti-value> gains a matching space-separated id couple.
  2. Clear the question, blank one card of a pair, and give a pair the same text on both sides — three distinct messages appear, one per rule.
  3. Close the editor and reopen it — pair order and within-pair order survive the round trip.
  4. Narrow the window below the small breakpoint — each pair stacks with its number and delete control on one row.

Worth questioning:

  • buildXML collapses two choices with equal text into one pool entry and bumps its match-max, so an author who deliberately wants two visually identical options gets one. Blank content is exempt, otherwise a freshly added pair could not round-trip.
  • A distractor is derived from match-max minus the choice's appearances in the correct response, so hand-written XML with a match-max larger than intended silently gains distractors on import.

Screenshots

State Screenshot
Edit mode Edit
View mode, answers hidden View
View mode, answers shown View with answers
Validation Validation
Small screen Mobile

axe-core (WCAG 2 AA) on the demo page reports one violation: colour contrast on AddListItemButton's label. It reproduces on the unchanged ordering editor, which uses the same shared component.

AI usage

Used Claude Code to implement the plugin test-first against a written plan, following the ordering interaction as the reference. Verified with the Jest suite, pre-commit, manual QA on the QTI demo page, and an axe-core audit.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?
  • Ran pre-flight CI checks (lint, format, tests) and verified all pass
  • Rebased onto the target branch and resolved any conflicts
  • Reorganized commit history into clean, logical commits
  • Audited the diff to ensure only issue-relevant files are changed
  • Built PR body from the repository's PR template with evidence blocks
@rtibblesbot

🟡 Waiting for feedback

Last updated: 2026-08-31 22:21 UTC

@rtibblesbot
rtibblesbot force-pushed the issue-6101-e6feda branch 2 times, most recently from e4e54df to 6e5a1f4 Compare August 31, 2026 16:43
rtibblesbot and others added 4 commits August 31, 2026 09:53
Splits the single flat pool of <qti-simple-associable-choice> elements into
authoring state: `pairs` from the correct response, `distractors` from the
match-max capacity the correct response does not consume. buildXML re-merges
them, normalizing ids so equal content shares one pool entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Registering the descriptor does not populate QUESTION_TYPE_LABELS, so
QTIItemEditor gets an explicit ASSOCIATE entry — without it every associate
item's view-mode header reads "Unknown type".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rtibblesbot
rtibblesbot marked this pull request as ready for review August 31, 2026 16:54

@AlexVelezLl AlexVelezLl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rtibblesbot, from the screenshots, I can see that the padding of the chips is not the same as in the specs, and the colors of the pair rows are not the same as in the specs. Take a closer look at the images in the issue and check that everything is correctly aligned.

@rtibblesbot

Copy link
Copy Markdown
Contributor Author

@AlexVelezLl Fixed, and I swept every element in the editor against the six mockups rather than only the two you named — eight divergences, all changed:

  • Pair rowsgrey.v_100grey.v_50 with a fineLine border; cards now sit on surface instead of inheriting the row tint.
  • Pair cards — 40px tall with an 8px text inset; were 50px at the editor's default 24px inset.
  • Chipspadding: 4px 12px with an 8px gap before the delete control; were 0 4px 0 12px, so the × sat flush against the border. Dropping the editor's paragraph margins takes them from 50px to 34px.
  • Chip fill — a chip inverts against its container: tinted in the distractor pool, white in the shuffled pool. Both were white.
  • Shuffled pool boxgrey.v_100grey.v_50.
  • Correct-answer chip bordergreen.v_500green.v_600, matching the mockup and the choice/ordering editors.
  • Pair validation message — aligned to the row's left edge; it was indented under the cards.
  • CopyMatching pairs, Distractors (optional), Response pool (shuffled), Add distractor and both sublabels, verbatim from the mockups. The branch shipped the plan's provisional wording (Correct pairs, Additional options, Options (shuffled), Add option) — which is also why the labels in the PR body's screenshots don't match what the branch renders. The four below are current.

Two mockup details I left out, both more than styling — say the word and I'll add them:

  • the SAVE button on the new-distractor editor (the sibling editors commit on type and close via the minimize control)
  • the Answer placeholder in an empty pair card (TipTapEditor has no placeholder prop)
State Screenshot
Edit Edit
View, answers shown View
Validation Validation
Small screen Mobile

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

Pair rows, cards, chips and pool boxes took colours, padding and copy that
diverge from the issue's mockups. Measured against them:

- pair rows: grey.v_50 with a fineLine border, cards on surface, 40px tall
- chips: 12px each side, 8px before the delete control, tinted only in the
  distractor pool, where they sit on the surface rather than the tint
- pair validation message: aligned to the row's left edge, not indented
  under the cards
- correct-answer chip border: green.v_600, as the sibling editors use
- section and button copy taken verbatim from the mockups

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

[QTI] Implement Associate Interaction editor

2 participants