fix(a11y): label 19 form fields, scope 19 tables, honour reduced motion, delete an unreachable settings dialog - #469
Merged
Conversation
…on, and delete an unreachable settings dialog Five gates, 52 findings, all real. hydra-gates 48c88ba, measured against origin/development (3a542f2). gate-32 semantic-controls 1 -> PASS gate-39 button-name 3 -> PASS gate-40 form-label-association 19 -> PASS gate-43 table-headers 19 -> PASS gate-45 prefers-reduced-motion 10 -> PASS gate-43 — every data table now names its columns `scope="col"` on 18 header rows across 12 components. The one finding that was not a missing `scope=` was `src/navigation/Configuration.vue`'s `<table>` with no `<th>` at all — see below. gate-40 — 19 controls a screen reader could not name - `src/modals/object/ViewObject.vue`: the four property editors get `:aria-label="getPropertyDisplayName(key)"`, which is exactly the text the Property column shows, so the programmatic name matches the visible one without rendering it twice. The select-all and per-attachment checkboxes get real names. - `src/modals/object/MergeObject.vue`: the custom-value field gets a label. - The other 13 were all in `src/navigation/Configuration.vue`. src/navigation/Configuration.vue is DELETED — it could never run Zero importers anywhere in src/, tests/ or the webpack config. It POSTs to `/index.php/apps/OPENCATALOGI/configuration` — a different app's endpoint — and translates with `t('forms', …)`, a third app's namespace. Its `<table>` is nested inside a `<p>`, which is invalid HTML. It is an OpenCatalogi leftover duplicating the settings surface `SoftwareCatalogSettings.vue` owns, and softwarecatalog's own settings are written by SettingsController. Nothing is left unguarded and no capability is lost: 13 gate-40 findings and 1 gate-43 finding disappear because the code that produced them is gone. gate-45 — reduced motion, per selector A `@media (prefers-reduced-motion: reduce)` block in each of the 10 style blocks, neutralising only the selectors that declare transition/animation. No global reset; nothing else changes appearance. gate-39 / gate-32 The three ObjectModal pencil buttons say what they do ("Change catalogue", "Change register", "Change schema"). The clickable errors tile in ArchiMateImportExport is now a real `<button type="button">`, disabled when the error count is zero, so it is keyboard-reachable exactly when it does something — plus the UA button chrome is neutralised so it renders identically to its sibling tiles. Also fixed while here: four Dutch UI strings in the Dashboard statistics tables ("Aantal"/"Beheren" -> "Count"/"Manage"). Ordinary words, not VNG standardised terms; this codebase is English. Can-fail proof: reverting all 19 files to origin/development puts every count back exactly — 1, 3, 19, 19, 10. vitest 215/215, stylelint clean, check:manifest Ajv PASS (0 errors). No other gate count moved.
Contributor
Quality Report — ConductionNL/softwarecatalog @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 128/128 | |||
| npm | ✅ | ✅ 718/718 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-09 15:28 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five gates, 52 findings, all real. hydra-gates
48c88ba1e0d049f8f38538c33e790d3e603c55d0, measured againstorigin/development(3a542f28).src/navigation/Configuration.vueis deleted — it could never runThis one file held 13 of gate-40's 19 findings and 1 of gate-43's 19. Before touching it, four independent things say it is unreachable:
src/,tests/, or the webpack config./index.php/apps/**opencatalogi**/configuration— a different app's endpoint.t('forms', …)— a third app's namespace.<table>is nested inside a<p>, which is invalid HTML the parser would unwind.It is an OpenCatalogi leftover duplicating the surface
SoftwareCatalogSettings.vueowns, and softwarecatalog's own settings are read and written bySettingsController. Nothing is left unguarded and no capability is lost — the standing lesson from #456 (deleting the dead code would have removed the guards) does not apply here, because this file contains no guard and is not the sole writer of anything.Fourteen findings go away because the code that produced them is gone, not because a checker was talked out of them.
gate-43 — every data table names its columns
scope="col"on 18 header rows across 12 components. Two empty action headers get a.hidden-visuallyname (a Nextcloud core class,core/css/global.css— not invented here).gate-40 — 19 controls a screen reader could not name
ViewObject.vue— the four property editors take:aria-label="getPropertyDisplayName(key)", which is exactly the text the Property column already shows. The programmatic name matches the visible one without rendering the label twice. The select-all and per-attachment checkboxes get real names (Select all attachments,Select <filename>).MergeObject.vue— the custom-value field gets a label.gate-45 — reduced motion, per selector
A
@media (prefers-reduced-motion: reduce)block inside each of the 10 style blocks, neutralising only the selectors that actually declaretransition/animation. No global reset — nothing else changes appearance for anyone.gate-39 / gate-32
The three
ObjectModalpencil buttons now say what they do ("Change catalogue", "Change register", "Change schema"), not what they look like.The clickable errors tile in
ArchiMateImportExportis now a real<button type="button">,:disabledwhen the error count is zero — so it is keyboard-reachable exactly when it does something, which arole/tabindex/@keydowntriple on a<div>would not have got right. The UA button chrome is neutralised in CSS so it renders identically to its sibling tiles.Also fixed while here
Four Dutch UI strings in the Dashboard statistics tables —
Aantal/Beheren→Count/Manage. Ordinary words, no VNG standardised term involved, no test asserts on them; this codebase is English.Can-fail proof
Reverting all 19 files to
origin/developmentand re-running the suite puts every count back exactly:Other measurements
vitest— 215/215 across 19 files.stylelint— clean (only the two pre-existing rule-deprecation notices).check:manifest— Ajv PASS (0 errors).