Skip to content

Replace the legacy assessment editor with the QTI editor - #6095

Merged
AlexVelezLl merged 11 commits into
learningequality:unstablefrom
AlexVelezLl:base-qti-migration
Sep 21, 2026
Merged

AlexVelezLl merged 11 commits into
learningequality:unstablefrom
AlexVelezLl:base-qti-migration

Conversation

@AlexVelezLl

@AlexVelezLl AlexVelezLl commented Aug 17, 2026 •

Copy link
Copy Markdown
Member

Stacked on #6073, you can ignore first 3 commits and review the remaining 9. #6073 must be merged first.

Summary

  • Replaces old AssessmentsEditor to the new QTIEditor in the exercise edit modal, and exercise preview panel, and unties everything that still pointed at the old editor — validation, previews, constants, store shapes.
  • Removes all old AssessmentsEditor components, constants, helpers, etc.
  • Adds adapter on AssessmentsTab to convert from the list-shape updates to the updates per assessments shape needed for sync.
  • Fixes bugs that arised when connecting the new QTIEditor and actually saving the results to the backend:
    • HTML-parsed nodes carried the XHTML namespace into the item, which the XSD rejects — buildXmlNode now re-creates them namespace-less.
    • Empty <qti-correct-response/> / <qti-default-value/> are omitted rather than emitted, since the schema requires at least one qti-value.
    • AssessmentItemTypes.QTI was 'qti' where the backend sends 'QTI'.
  • Updates to two different registries for interactions, one for descriptors, the other for Editor, so that headless validation can be done without importing all related vue components and TipTap dependencies (in shared/utils/validation.js, which is imported on every webpack entry).
  • Adds validateQtiItem validates an item from its raw XML without rendering anything, so Studio can decide whether a node is complete headlessly.
  • Updates backend viewset so that we can properly save item that is migrated to QTI on its first raw_data write. The client cannot send type — the change layer only sends fields that changed — so the type has to be inferred from the payload.
  • Adapts images stored in .md format, so that images from the old editor can be seen on the new one.
    • Perseus images carry a size suffix (![alt](<checksum>.jpg =550x364)) that CommonMark has no notion of, so the converter emitted them as literal text. A markdown rule now claims the construct, and TipTapEditor's html path resolves a stored <checksum>.<ext> to a loadable URL on the way in and back on the way out.
  • Adds hints editor section for assessments that already had hints in the past.
Grabacion.de.pantalla.2026-08-18.a.la.s.11.22.41.a.m.mov

References

Stacked on #6073.

Closes #5970.
Closes #5956.
Closes #5934.
Closes #5958.
Closes #5935.
Closes #5959.

Reviewer guidance

  • In unstable, create several exercises, these will we created using the old data format.
  • Checkout to this branch, preview the exercises, make sure everything is still rendered correctly, including hints.
  • Create new items, new questions, make sure everything is still working fine with the new editor.
  • Plublish new exercises, look at the resulting QTI zip file, make sure resulting XML has been properly built.

Known follow-ups, not in this PR

  • Publish omits images from native QTI items: _write_qti_media_files needs a File row linked to the assessment item, and nothing links exercise images (0 of 2,461 File rows in a dev DB have assessment_item set — this predates the new editor). Legacy items were fine because publish read them out of storage by checksum. Migrating an item moves it onto the stricter path.

AI usage

Used Claude (Opus 5) to brainstorm an initial plan and then to implement it. I reviewed the results and iteratively went on building and fixing remaining issues and proper commit history, until we got to a polished version of this PR.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment