Repository navigation
Upgrade kolibri-format to 3.0.1 - #6358
LianaHarris360 wants to merge 3 commits into
Conversation
🟡 Waiting for changesOutcome: reviewed Last updated: 2026-11-03 03:05 UTC |
There was a problem hiding this comment.
PR #6358: the config migration is complete. Every .eslintrc.js setting carries over. The lockfile resolves only eslint 9.39.5. The code changes are behaviour-neutral.
CI pending. Manual QA covered sign-up, password reset, account settings, the storage request, channel defaults, the edit modal tabs, Community Library countries (en/ar), admin users, thumbnail generation and offline sync. No regressions. Every axe violation found is in unchanged Vuetify markup. Thumbnail upload and save went untested because the QA stack's storage was unreachable.
- suggestion: 10 renamed
import-x/*disables are now unused, plus a stale comment (inline). - suggestion: deferred-rule comments cite #6328, which this PR closes (inline).
- suggestion: with the root
eslintdependency removed, editor integration may break (inline). - nitpick:
ContentDefaults.vueimport path (inline).
Next step: Needs a full code review by a human engineer, then manual QA once that reviewer sets Needs QA.
- User-visible files changed:
contentcuration/contentcuration/frontend/accounts/pages/Create.vue,contentcuration/contentcuration/frontend/accounts/router.js,contentcuration/contentcuration/frontend/administration/pages/Users/UserPrivilegeModal.vue,contentcuration/contentcuration/frontend/channelEdit/components/edit/EditView.vue,contentcuration/contentcuration/frontend/channelEdit/views/files/thumbnails/ThumbnailGenerator.vue…. - Decide whether dropping the root
eslintdevDependency and raising thenodeengine to>=20.19.0 <21are acceptable for contributors' tooling. - Confirm the rules deferred in
eslint.config.mjsare tracked by an open follow-up issue before #6328 closes.
QA captures (50)
Sign up for a new account — submit with required fields empty to trigger onValidationFailed (all errors shown, scroll to top), pick a country from the CountryField list (full English country names, search works), then submit valid data and reach the activation-sent page
| Step | Screenshot |
|---|---|
| Activation sent page | ![]() |
| Activation sent | ![]() |
| Country chips selected | ![]() |
| Country list open | ![]() |
| Country search united | ![]() |
| Empty submit errors | ![]() |
| Signup form initial | ![]() |
Switch the UI language to Spanish, French, Arabic and Portuguese and open the sign-up or storage-request country field — country names render in that language, not as codes or blanks
| Step | Screenshot |
|---|---|
| Country list ar | ![]() |
| Country list es | ![]() |
| Country search ar | ![]() |
| Country search es es | ![]() |
| Country search fr fr | ![]() |
| Country search fr | ![]() |
| Country search pt br | ![]() |
| Country selected ar | ![]() |
Request a password reset from the sign-in page and open the reset-password route — ForgotPassword, instructions-sent and ResetPassword pages load without a missing-chunk or blank-route error
| Step | Screenshot |
|---|---|
| Forgot password | ![]() |
| Instructions sent | ![]() |
| Reset expired | ![]() |
| Reset password failed | ![]() |
| Reset password | ![]() |
In Settings > Account, change the full name and then the password — each formMixin onSubmit fires, shows its success snackbar, and the new name persists after reload
| Step | Screenshot |
|---|---|
| Change password validation | ![]() |
| Full name persisted after reload | ![]() |
| Full name saved snackbar | ![]() |
| Password updated snackbar | ![]() |
4-change-password.webm
4-full-name-edit.webm
In Settings > Storage, submit the request-more-space form empty to see the error banner and scroll, then fill it including country selection and submit — the POST payload carries the countries and the success state shows
| Step | Screenshot |
|---|---|
| Empty submit error banner | ![]() |
| Filled countries | ![]() |
| Submitted success | ![]() |
5-request-form-flow.webm
Open a channel's edit-details modal and change the content defaults (license, copyright holder, auto-derive checkboxes), save, reopen — ContentDefaults renders its translated labels and the values persist
| Step | Screenshot |
|---|---|
| Content defaults ar license menu | ![]() |
| Content defaults edited | ![]() |
| Content defaults initial | ![]() |
| Content defaults reopened | ![]() |
| License menu open | ![]() |
In a channel editor, open an exercise and a document in the edit modal and switch between Details, Questions and Related tabs, including tab-bar scroll arrows in a narrow window — AssessmentTab and RelatedResourcesTab load and the Tabs prev/next arrows work
| Step | Screenshot |
|---|---|
| Document related tab | ![]() |
| Exercise details tab | ![]() |
| Exercise questions tab | ![]() |
| Exercise related tab | ![]() |
| Narrow tabs after next | ![]() |
| Narrow tabs next arrow | ![]() |
| Rtl narrow tabs scrolled | ![]() |
7-tab-arrows.webm
Submit a channel to the Community Library choosing countries, then view it on the channel card, the channel details panel and the community-library list country filter — country names display and filtering by country returns the channel
| Step | Screenshot |
|---|---|
| Admin review panel | ![]() |
| Ar details countries | ![]() |
| Ar filter kenya | ![]() |
| Community library card | ![]() |
| Countries search | ![]() |
| Country filter options | ![]() |
| Details panel countries | ![]() |
Written by rtibblesbot, an LLM-based coding agent.
6b8a3e3 to
199d0ed
Compare
There was a problem hiding this comment.
PR #6358: all 4 prior findings are resolved. No new findings. CI is still pending.
Prior-finding status
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/utils/comparisonKey.js — unused renamed disable directives, stale comment
RESOLVED — eslint.config.mjs — deferred-rule comments cite #6328, which this PR closes
RESOLVED — package.json:133 — dropping root eslint devDependency breaks editors / pnpm exec eslint
RESOLVED — contentcuration/contentcuration/frontend/shared/views/form/ContentDefaults.vue — relative '../../mixins' import
Next step: Needs a full code review by a human engineer, then manual QA once that reviewer sets Needs QA.
- User-visible files changed:
contentcuration/contentcuration/frontend/accounts/pages/Create.vue,contentcuration/contentcuration/frontend/accounts/router.js,contentcuration/contentcuration/frontend/administration/pages/Users/UserPrivilegeModal.vue,contentcuration/contentcuration/frontend/channelEdit/components/edit/EditView.vue,contentcuration/contentcuration/frontend/channelEdit/views/files/thumbnails/ThumbnailGenerator.vue…. - Confirm the ESLint rules switched off in
eslint.config.mjs(tracked by #6359) are acceptable to defer, since other repos will copy this flat-config setup.
QA captures (50)
Create a new account with the country picker — country list loads with English names, search and select a country, submit an invalid form to see all field errors and the scroll to top, then submit a valid form
| Step | Screenshot |
|---|---|
| Countries selected | ![]() |
| Country list open | ![]() |
| Create form initial | ![]() |
| Invalid submit errors | ![]() |
| Valid form filled | ![]() |
| Valid submit activation sent | ![]() |
1-invalid-submit-scroll-top.webm
Request more storage from Settings > Storage — country field lists and accepts countries, an empty submit shows the error banner and scrolls to it, a valid submit sends the request
| Step | Screenshot |
|---|---|
| Country chips selected | ![]() |
| Empty submit error banner | ![]() |
| Valid submit sent | ![]() |
Filter the admin Users table by country, then open a user and change their privileges in the privilege modal — country options populate, the filter narrows rows, the modal submit applies the change
| Step | Screenshot |
|---|---|
| Filter afghanistan one row | ![]() |
| Filter kenya zero | ![]() |
| Location options | ![]() |
| Privilege modal wrong email | ![]() |
| User c now admin | ![]() |
3-add-admin-privileges.webm
Browse the Community Library list in Channels and filter by country — country options populate with names, a selection updates the URL and list, and channel cards and the details panel show country names
| Step | Screenshot |
|---|---|
| Country dropdown open | ![]() |
| Details panel countries | ![]() |
| Filtered kenya | ![]() |
| Rtl arabic filtered | ![]() |
Switch the UI language to Spanish and then Arabic, then open a country picker (Settings > Storage or the admin Users filter) — strings translate, country names follow the locale, Arabic renders RTL
| Step | Screenshot |
|---|---|
| Ar admin users location filter | ![]() |
| Ar country picker rtl | ![]() |
| Change language dialog | ![]() |
| Es country picker search | ![]() |
Open an exercise in channel edit and move between the Details, Questions and Related tabs — each tab renders, adding a question and a related resource saves
| Step | Screenshot |
|---|---|
| Details tab | ![]() |
| New question editing | ![]() |
| Next step picker | ![]() |
| Question added | ![]() |
| Questions tab | ![]() |
| Related step added | ![]() |
| Related tab | ![]() |
Create a new channel and set its content defaults (author, license, copyright holder, thumbnail options), save, then reopen the channel settings — the defaults form renders and the values persist
| Step | Screenshot |
|---|---|
| Create attempt top | ![]() |
| New channel defaults filled | ![]() |
| Reopened defaults persisted | ![]() |
Use Forgot password to request a reset email, then open a reset-password link with an invalid token — the instructions-sent page shows, and the reset route renders the expired-link page rather than a blank route
| Step | Screenshot |
|---|---|
| Forgot password empty submit | ![]() |
| Instructions sent | ![]() |
| Reset link expired ar | ![]() |
| Reset link expired | ![]() |
| Reset password forbidden | ![]() |
| Reset password form | ![]() |
8-forgot-to-expired-flow.webm
Change full name and password from Settings > Account — each form validates, submits, and shows its success message
| Step | Screenshot |
|---|---|
| Full name saved | ![]() |
| Full name validation | ![]() |
| Password empty validation | ![]() |
| Password mismatch | ![]() |
| Password saved | ![]() |
In channel edit, take the browser offline and back online — the offline indicator appears and clears, and an edit made while offline syncs after reconnecting
| Step | Screenshot |
|---|---|
| Back online edit modal | ![]() |
| Back online empty channel | ![]() |
| Offline indicator | ![]() |
| Offline new folder modal | ![]() |
Written by rtibblesbot, an LLM-based coding agent.
199d0ed to
c586b97
Compare
Replace .eslintrc.js with eslint.config.mjs. Bump kolibri-i18n to 1.0.1, which drops the ESLint 8 copy of kolibri-format that read the old file. Co-Authored-By: Claude Opus 5 <[email protected]>
Co-Authored-By: Claude Opus 5 <[email protected]>
Co-Authored-By: Claude Opus 5 <[email protected]>
c586b97 to
33996a5
Compare
There was a problem hiding this comment.
PR #6358: 4 of 4 prior findings resolved; 2 new blocking findings (inline).
- CI failing:
Lintingfails on the gapMatch files fromunstable. - The PR head moved after these passes ran. The newest commits are unreviewed.
- Manual QA: create-account, storage request, account forms, password reset, content defaults, exercise edit tabs, admin users and offline sync all work in en/es/ar. Not exercised: HTML5 thumbnail capture (no object storage) and Community Library country display (no submissions).
Prior-finding status
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/utils/comparisonKey.js — renamed disable directives unused, stale comment
RESOLVED — eslint.config.mjs — deferred-rule comments cite #6328
RESOLVED — package.json:133 — dropping root eslint devDependency
RESOLVED — contentcuration/contentcuration/frontend/shared/views/form/ContentDefaults.vue — relative '../../mixins' import
Next step: Needs a full code review by a human engineer, then manual QA once that reviewer sets Needs QA.
- User-visible files changed:
contentcuration/contentcuration/frontend/accounts/pages/Create.vue,contentcuration/contentcuration/frontend/accounts/router.js,contentcuration/contentcuration/frontend/administration/pages/Users/UserPrivilegeModal.vue,contentcuration/contentcuration/frontend/channelEdit/components/edit/EditView.vue,contentcuration/contentcuration/frontend/channelEdit/views/files/thumbnails/ThumbnailGenerator.vue…. - Check that
.git-blame-ignore-revslists the reformat commit's hash as it lands onunstableand that the merge strategy keeps that commit. - Check the dependency and lint-tooling upgrade (
eslint.config.mjs,pnpm-lock.yaml) before other repos copy the flat-config pattern. - With working object storage, generate an HTML5 thumbnail and check that the
html2canvasESM import captures a preview.
QA captures (49)
Create a new account at /accounts/#/create — country field lists, searches and selects countries (multi-select chips), validation errors appear together on a bad submit, a valid submit reaches the activation-sent page with no console errors
| Step | Screenshot |
|---|---|
| Activation sent | ![]() |
| Bad submit errors lower | ![]() |
| Bad submit errors | ![]() |
| Country chips selected | ![]() |
| Create form initial | ![]() |
1-bad-submit-validation.webm
1-country-search-select.webm
1-valid-submit-activation-sent.webm
Switch the UI language to Spanish and then Arabic from the language switcher, reload, then open the create-account and storage-request country fields — strings translate, country names render in the chosen locale, RTL layout applies, no i18n or missing-locale console errors
| Step | Screenshot |
|---|---|
| Ar create country list | ![]() |
| Ar storage country list | ![]() |
| Es create country list | ![]() |
| Es storage country list | ![]() |
Request more storage from Settings > Storage — fill the form including the country field, check validation scrolls to the error banner, submit, confirm the request POST and the success state
| Step | Screenshot |
|---|---|
| Request submitted | ![]() |
| Validation error banner | ![]() |
3-request-storage-flow.webm
Change full name and change password from Settings > Account — each form validates, submits, shows its success snackbar and the new name persists after reload
| Step | Screenshot |
|---|---|
| Full name empty validation | ![]() |
| Full name saved snackbar | ![]() |
| Password validation | ![]() |
Go through forgot password: submit an email on the forgot-password page, reach the instructions-sent page, then open a reset-password link with an invalid token — the reset page route loads and lands on the link-expired page without a chunk or import error
| Step | Screenshot |
|---|---|
| Forgot password page | ![]() |
| Instructions sent | ![]() |
| Reset link expired | ![]() |
| Reset password invalid session | ![]() |
5-forgot-password-flow.webm
Create a new channel and then edit its settings — set content defaults (license, copyright holder, author, provider, aggregator, the boolean defaults), save, reopen the modal and confirm the license names render translated and the values persist through /api/sync/
| Step | Screenshot |
|---|---|
| Ar license menu | ![]() |
| Defaults filled before create | ![]() |
| Edit special permissions | ![]() |
| License menu open | ![]() |
| Reopened values persisted | ![]() |
Open an exercise in the edit modal and switch between the Details, Questions and Related tabs — the Assessment and Related resources tabs render, adding a question and a related resource saves, no console errors
| Step | Screenshot |
|---|---|
| Details tab | ![]() |
| Question added | ![]() |
| Questions tab empty | ![]() |
| Related added | ![]() |
| Related tab empty | ![]() |
7-add-question.webm
7-add-related.webm
Open an HTML5 resource in the edit modal and generate its thumbnail — the screenshot iframe loads the htmlScreenshot bundle from zipcontent, a thumbnail preview appears, no html2canvas error in console (stop at the upload if storage is unavailable)
| Step | Screenshot |
|---|---|
| Generate stuck zip missing from storage | ![]() |
| Html5 edit modal thumbnail before | ![]() |
| Html5 upload failed no storage | ![]() |
Browse the Community Library list as a user and as an admin open a submission review side panel — country filters list and filter channels, channel cards and the details panel show country names, the review panel shows the submission countries
| Step | Screenshot |
|---|---|
| Community library empty | ![]() |
As an admin, filter the Users table by country and open the user privilege modal to toggle a privilege — filter results update, the modal submits and the row reflects the change
| Step | Screenshot |
|---|---|
| Filtered kenya | ![]() |
| Privilege modal mismatch | ![]() |
| Row after add admin | ![]() |
10-filter-and-privilege.webm
In the channel editor, emulate going offline and back online — the offline indicator appears and clears, edits made offline sync once online
| Step | Screenshot |
|---|---|
| Offline close modal page not found | ![]() |
| Offline edit title | ![]() |
| Offline indicator | ![]() |
| Offline new folder failed load | ![]() |
| Online indicator cleared | ![]() |
11-offline-edit-online-sync.webm
Written by rtibblesbot, an LLM-based coding agent.
rtibblesbot
left a comment
There was a problem hiding this comment.
PR #6358: all 6 prior findings resolved; no new findings.
- CI passing.
- Manual QA did not run.
Prior-finding status
RESOLVED — .git-blame-ignore-revs:7 — wrong reformat commit hash
RESOLVED — eslint.config.mjs:82 — Linting job fails on gapMatch/* files from unstable
RESOLVED — contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/utils/comparisonKey.js — unused renamed disable directives, stale comment
RESOLVED — eslint.config.mjs — deferred-rule comments cite #6328
RESOLVED — package.json:133 — dropping root eslint devDependency
RESOLVED — contentcuration/contentcuration/frontend/shared/views/form/ContentDefaults.vue — relative '../../mixins' import
Next step: Needs a full code review by a human engineer, then manual QA once that reviewer sets Needs QA.
- User-visible files changed:
contentcuration/contentcuration/frontend/accounts/pages/Create.vue,contentcuration/contentcuration/frontend/accounts/router.js,contentcuration/contentcuration/frontend/administration/pages/Users/UserPrivilegeModal.vue,contentcuration/contentcuration/frontend/channelEdit/components/edit/EditView.vue,contentcuration/contentcuration/frontend/channelEdit/views/files/thumbnails/ThumbnailGenerator.vue…. - Confirm the
pnpm-lock.yamldependency bumps that came with kolibri-format 3.0.1 are acceptable for the frontend build. - Confirm the ESLint rules left disabled in
eslint.config.mjsare tracked as follow-ups.
Written by rtibblesbot, an LLM-based coding agent.
Superseded by my review of 33996a5: no blocking findings remain.





































































































































Summary
Upgrades
kolibri-formatfrom 1.0.1 to 3.0.1 and replaces.eslintrc.jswitheslint.config.mjs. Version 3.0.1 runs ESLint 9, which reads flat config only. Studio loadedkolibri-format/.eslintrc, which the package stopped shipping in 2.4.0.The new config inherits kolibri-format's and re-applies what
.eslintrc.jscarried. Rules that 3.0.1 adds and that autofix cannot clear stay off.jsdocandvuejs-accessibilityrules by name prefix. A new rule in either plugin then cannot break the build before triage.kolibri-i18nmoves to 1.0.1. Version 1.0.0 pinskolibri-format1.0.1, which reads the deleted.eslintrc. Without the bump,pnpm transfercontextand thei18n-downloadworkflow fail.n/prefer-node-protocoloff for bundled frontend source, because webpack cannot resolve thenode:scheme for the browser. The rule stays on for specs, which run under Node.engines.nodebecomes>=20.19.0 <21. kolibri-format 3.0.1 sets the lower bound. node-sass 9 sets the upper bound.References
Closes #6328
Reviewer guidance
Run
pnpm installwith pnpm, not npm. The install linkskolibri-css-variablesto the Kolibri Design System.I ran these from the committed tree:
pnpm run lint-frontend: 961 files, zero problems.pre-commit run --all-files: passes, and a second run changes no file.pnpm test: 280 suites, 4386 tests, zero failures.pnpm run build: succeeds, with the pre-existing bundle-size warnings only.To check the design-system link, turn
kolibri/vue-no-theme-accessor-in-inline-styleson for one run. It must name real variables such asvar(--tokens-fineLine), not reportThis rule cannot check theme names.To check that the formatting commit is pure, revert the frontend to
unstable, runpnpm run lint-frontend:formatuntil it stops writing, and compare the result against the commit.Notes:
import-x/no-useless-path-segmentswrites double quotes and kolibri-format runs Prettier before ESLint. This tree sits at the fixed point, so CI sees one clean pass.kolibri-buildhas two copies in the pnpm store. Aligning them breaks every Jest suite, because 1.1.4 dropsbabel.config, which Studio'sbabel.config.jsrequires. The copies are development only.copyToken.spec.jsloses oneexpectcall. It had no matcher, so it asserted nothing, and the component has nocopyStatus.AI usage
I used Claude Code to carry out the issue. I reviewed its output and rejected parts of it. A second Claude pass over the whole diff found the
kolibri-i18nbreakage, which I reproduced before fixing. I verified the result withpnpm run lint-frontend,pre-commit run --all-filestwice,pnpm test, andpnpm run build, and I checked that the theming rules read real theme names and that the formatting commit is reproducible from the formatter alone.