Repository navigation
New: Add migration scripts (fixes #544) - #616
Conversation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Really thorough piece of work — I verified this fairly hard and the data accuracy is excellent. All 19 updatePlugin framework versions match the real tags, all 70 theme variable names/defaults match the schema at their target version, every _.set() path exists, and the v9.8.2 '' → no-repeat/cover/center top conversion is exactly right (and necessary — '' leaves the enum there).
I ran the suite (76/76 pass) and also pushed a synthetic v3.1.0 course through all 19 steps end-to-end; the output validates cleanly against the real v9.39.0 schemas.
One issue worth fixing, in the v9.6.13 > v9.6.15 step — inline suggestions below.
_xlarge is written empty rather than carrying _large over
To be clear up front: this is a pre-existing pattern in the ecosystem, not something introduced here. adapt-contrib-boxMenu has had exactly the same bug in a released migration since v6.3.9 — I've since raised adaptlearning/adapt-contrib-boxMenu#244 and adaptlearning/adapt-contrib-boxMenu#245 for it. So this is copying established precedent; the precedent just turns out to be wrong.
The step adds the new _xlarge breakpoint as '' / 0. That's not just a missed nicety — it's actively worse than leaving the key absent, because themeView.js resolves breakpoints with nullish coalescing:
// js/themeView.js:61 and :82
const backgroundImage = backgroundImages[`_${device.screenSize}`] ?? backgroundImages._small;
const minimumHeight = minimumHeights[`_${device.screenSize}`] ?? minimumHeights._small;'' and 0 aren't nullish, so writing them suppresses the _small fallback that currently works. xlarge is live at 1280px in the default config, so this fires on any ordinary desktop monitor.
End-to-end on a v9.6.13 course with real assets, migrated to v9.39.0:
| as submitted | carrying _large over |
|
|---|---|---|
page _backgroundImage |
_xlarge="" → renders "" |
_xlarge="ph.jpg" → renders "ph.jpg" |
page _minimumHeights |
_xlarge=0 → renders 0px |
_xlarge=500 → renders 500px |
block _backgroundImage |
_xlarge="" → renders "" |
_xlarge="bg.jpg" → renders "bg.jpg" |
block _minimumHeights |
_xlarge=0 → renders 0px |
_xlarge=400 → renders 400px |
So an AAT course with a background image or minimum height loses it on screens ≥1280px after migrating. Silent, no error raised.
Worth noting the current tests can't catch this — they assert _xlarge is a string/number, and every fixture uses empty strings. Strengthening the four checkContent blocks to also assert a populated _large was carried over, plus a testSuccessWhere with real values, does catch it — I checked that such a test fails against the code as it stands, so it isn't a vacuous assertion. Happy to send that across separately if useful; it's a bit long to put in a suggestion block.
One caveat on that, learned from boxMenu: asserting a value isn't automatically enough. boxMenu's check did assert a value — _xlarge === '' — and that simply locked the bug in. The assertion needs to encode the intended rendering outcome, not whatever the mutate step happened to write.
Not suggesting a change for _responsiveClasses._xlarge (line 170)
That one is not affected — it has no ?? _small fallback, it indexes directly (themeView.js:94), so '' and undefined are both a no-op addClass. Copying _large there would be a behaviour change rather than a fix (xl screens currently get no responsive class at all), and could plausibly break a course whose large-screen class hides or reflows something meant to appear at xl. Left it alone deliberately.
Two smaller points, neither blocking
-
v9.10.0 isn't mentioned anywhere. It changed ~20 theme variable defaults from hex to
""(4f4acbf, fixes #464). Thev9.8.2 > v9.16.1step spans it but only addsloading/loading-inverted. I think omitting it is right — you can't distinguish "author accepted#4D4D4D" from "author chose#4D4D4D", so clearing would be destructive — but it'd be worth a line either way so it's clear it was considered. -
Version claims are slightly stale. The description says "up to the current v9.40.0", but the last step targets v9.39.0 and master is now v9.41.0. Neither needs a migration (v9.40.0 is LESS-only; v9.41.0 widens the
backgroundSizeenum), so it's just a rebase and a wording tweak — but worth confirming the finalupdatePluginis meant to sit at v9.39.0.
Nothing else from me — the rest stood up to everything I threw at it.
Posted via collaboration with Claude Code
| mutateContent('adapt-contrib-vanilla - add _vanilla._backgroundImage._xlarge to article, block and contentObject', async (content) => { | ||
| [...articles, ...blocks, ...contentObjects].forEach(item => { | ||
| if (!_.has(item, '_vanilla._backgroundImage') || _.has(item, '_vanilla._backgroundImage._xlarge')) return; | ||
| item._vanilla._backgroundImage._xlarge = ''; |
There was a problem hiding this comment.
Carry _large over so existing backgrounds survive at the new breakpoint. Writing '' here suppresses the ?? _small fallback in themeView.js:61, so the background disappears entirely at ≥1280px.
| item._vanilla._backgroundImage._xlarge = ''; | |
| // carry _large over so existing backgrounds survive at the new xlarge breakpoint | |
| item._vanilla._backgroundImage._xlarge = item._vanilla._backgroundImage._large ?? ''; |
| mutateContent('adapt-contrib-vanilla - add _vanilla._minimumHeights._xlarge to block', async (content) => { | ||
| blocks.forEach(block => { | ||
| if (!_.has(block, '_vanilla._minimumHeights') || _.has(block, '_vanilla._minimumHeights._xlarge')) return; | ||
| block._vanilla._minimumHeights._xlarge = 0; |
There was a problem hiding this comment.
Same here — 0 isn't nullish, so it suppresses the ?? _small fallback in themeView.js:82 and the minimum height is lost at ≥1280px.
| block._vanilla._minimumHeights._xlarge = 0; | |
| // carry _large over so existing minimum heights survive at the new xlarge breakpoint | |
| block._vanilla._minimumHeights._xlarge = block._vanilla._minimumHeights._large ?? 0; |
| mutateContent('adapt-contrib-vanilla - add _vanilla._pageHeader._backgroundImage._xlarge to contentObject', async (content) => { | ||
| contentObjects.forEach(contentObject => { | ||
| if (!_.has(contentObject, '_vanilla._pageHeader._backgroundImage') || _.has(contentObject, '_vanilla._pageHeader._backgroundImage._xlarge')) return; | ||
| contentObject._vanilla._pageHeader._backgroundImage._xlarge = ''; |
There was a problem hiding this comment.
Same issue for the page header background.
| contentObject._vanilla._pageHeader._backgroundImage._xlarge = ''; | |
| // carry _large over so existing backgrounds survive at the new xlarge breakpoint | |
| contentObject._vanilla._pageHeader._backgroundImage._xlarge = contentObject._vanilla._pageHeader._backgroundImage._large ?? ''; |
| mutateContent('adapt-contrib-vanilla - add _vanilla._pageHeader._minimumHeights._xlarge to contentObject', async (content) => { | ||
| contentObjects.forEach(contentObject => { | ||
| if (!_.has(contentObject, '_vanilla._pageHeader._minimumHeights') || _.has(contentObject, '_vanilla._pageHeader._minimumHeights._xlarge')) return; | ||
| contentObject._vanilla._pageHeader._minimumHeights._xlarge = 0; |
There was a problem hiding this comment.
And the page header minimum height.
| contentObject._vanilla._pageHeader._minimumHeights._xlarge = 0; | |
| // carry _large over so existing minimum heights survive at the new xlarge breakpoint | |
| contentObject._vanilla._pageHeader._minimumHeights._xlarge = contentObject._vanilla._pageHeader._minimumHeights._large ?? 0; |
Update the v9.6.13→v9.6.15 migration to stop writing `_xlarge: ''` for `_vanilla._backgroundImage` and `_vanilla._pageHeader._backgroundImage`. The checks now assert those fields remain unset, preserving the theme’s nullish fallback to `_small` at large breakpoints and matching schema behavior for freshly authored courses.
|
Confirmed on the mechanism, but I've fixed it differently and taken only half the suggestions. You're right that const backgroundImage = backgroundImages[`_${device.screenSize}`] ?? backgroundImages._small;So the Two things pushed me away from So the migration now leaves I've kept The two I also ran the full v3.1.0 to v9.39.0 chain against a real 59-item course. No |
|
@joe-replin I would push back on f93f816 "_vanilla._backgroundImage._xlarge should be left unset so the _small fallback applies". In my experience, when a |
Update the v9.6.13→v9.6.15 migration to copy `_large` background image values into `_xlarge` for article/block/contentObject and page header background images when `_large` is set. This preserves existing desktop visuals after introducing the new breakpoint, while leaving `_xlarge` unset when `_large` is empty so `_small` fallback behavior still works. Validation checks were updated to match this rule, and a success case was added for authored background-image carryover.
|
You're right, and I've changed it to your suggestion. I missed the breakpoint shift. Confirmed in config.schema.json: the One refinement I've kept from my side: the carry-over is conditional on if (!item._vanilla._backgroundImage._large) return;
item._vanilla._backgroundImage._xlarge = item._vanilla._backgroundImage._large;Where
Tests are at 77 passing. I added a fixture with real image values because the existing ones all had an empty |
|
Agreed on the background images — the conditional carry-over is the right call, and you're right that my One thing left:
Your new fixture already contains that exact case: { _id: 'b-100', _type: 'block', _vanilla: { _backgroundImage: { _large: 'desktop.jpg', _medium: '', _small: '' }, _minimumHeights: { _large: 400, _medium: 0, _small: 0 } } }It passes because the check only asserts Same rule as the images would do it: if (!block._vanilla._minimumHeights._large) return;
block._vanilla._minimumHeights._xlarge = block._vanilla._minimumHeights._large;Plus No argument on Minor, separate: the mutations skip items that already have Posted via collaboration with Claude Code |
Updates the v9.6.13 -> v9.6.15 migration so `_minimumHeights._xlarge` is only added when `_large` is set, and it inherits `_large` instead of defaulting to `0`. Validation now uses a shared `_xlarge` resolution rule (presence/absence based on `_large`) to preserve fallback behavior and idempotency when custom `_xlarge` values already exist. Test fixtures were expanded to cover page header minimum heights and pre-existing `_xlarge` values that differ from `_large`.
|
Both fixed in 47731d5.
78 tests passing. Reverting either |
Both points hold, and I've applied your fix in [6214226].
|
kirsty-hames
left a comment
There was a problem hiding this comment.
Looks good to me and Claude thanks 👍
|
🎉 This PR is included in version 9.42.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
Adds
adapt-migrationscontent-migration scripts covering every schema change to adapt-contrib-vanilla from v3.1.0 up to the current v9.40.0, so course content authored against older theme versions can be automatically upgraded.Fixes #544
migrations/v5.js
_vanilla._backgroundImage,_backgroundStylesand block_minimumHeights/_isDividerBlockto articles, blocks and contentObjects; adds_pageHeader._backgroundImage/_backgroundStyles/_minimumHeightsto contentObjects._vanilla._responsiveClassesto articles, blocks and contentObjects.migrations/v7.js
_vanilla._componentVerticalAlignment(default'top') to blocks.migrations/v8.js
_vanilla._paddingTop/_paddingBottom(default'standard') to blocks._vanilla._textAlignment(_title/_body/_instruction) to articles, blocks and components, and_pageHeader._textAlignmentto contentObjects.migrations/v9.js
_vanilla._componentHorizontalAlignment(default'left') to blocks._vanilla._favIcon._srcto course._xlargebreakpoint entries to existing_backgroundImage,_responsiveClassesand_minimumHeightsobjects (article/block/contentObject/pageHeader)._backgroundStylesvalues to their new non-empty defaults ('no-repeat'/'cover'/'center top') and narrows the valid enum accordingly.loading/loading-invertedtheme variables.menu-header-subtitle-colortheme variable._pageHeader._textAlignment._subtitleto contentObjects._vanilla._articleHeader(background image/styles/minimum heights) to articles and_vanilla._blockHeaderto blocks, plusnotify-title-colortheme variable._pageHeader._graphic(_src/alt) to contentObjects.drawer-item-selected-underline,body-background-color,shadow-opacity, pull-quote and tooltip theme variables._vanilla._favIcon._svgand_appleTouchto course.Each version step includes
whereFromPlugin/whereContentgating, idempotentmutateContentsteps (skips fields already present),checkContentvalidation, andtestSuccessWhere/testStopWhereunit tests.🤖 Generated with Claude Code