Aman-Mittal opened a new pull request, #568:
URL: https://github.com/apache/fineract-backoffice-ui/pull/568

   ## What and why
   
   Continues ADR 0005 from #566: migrates 47 list screens onto 
`app-button`/`app-icon`/`app-spinner`, clears the suppressions entries that 
were actually fixable, and adds the regression cover the migration needed — 
because the existing suite did not provide any.
   
   Closes #567. Addresses the collapse asked for in #514.
   
   ## 1. Lint baseline: 634 → 577, across 365 → 358 files
   
   **`unicorn/number-literal-case` was unsatisfiable.** Configured to demand 
uppercase hex while Prettier rewrites hex to lowercase and `format:check` gates 
CI — so those three entries could not be fixed by anyone. I only noticed 
because my `0xff` → `0xFF` fix silently reverted when I ran Prettier. Aligned 
the rule to lowercase; entries clear with no source change, and it still 
catches `0Xff` and `1E3`.
   
   Then seven mechanical ones: `isNaN` → `Number.isNaN`, a dead `import {} from 
'@angular/router'`, a truthiness ternary, positional child traversal, three 
object-literal defaults hoisted.
   
   **The 14 `unicorn/no-array-sort` entries are deliberately untouched.** The 
rule wants `Array#toSorted`; the project targets ES2022 and browserslist 
resolves **Chrome 109**, one below where `toSorted` shipped. Raising the lib 
would compile code that throws on a supported browser. `role-form.component.ts` 
already documents this.
   
   ## 2. `app-button` can navigate
   
   17 of the migrated call sites put `[routerLink]` on an `ion-button`; without 
this none of them could move.
   
   **My first implementation was wrong and the commit says so.** I bound 
`[routerLink]` internally — the directive instantiates whether or not commands 
are given and injects `ActivatedRoute`, so *every* button would have needed a 
router in its injector. It broke seven unrelated `EntityDatatablesComponent` 
tests, correctly. The router is now injected optionally and reached only when 
`link` is set, with a second suite that renders with no router at all so the 
property fails loudly if traded away.
   
   What that gives up against `routerLink` is href middle-click — which these 
call sites never had: `ion-button` renders an `<a>` only for `href`, so a 
`routerLink` on one already produced a `<button>` with a click handler and no 
href.
   
   ## 3. 47 screens migrated: vendor baseline 290 → 243
   
   Each file now imports no Ionic at all, so those 47 entries are **gone rather 
than reduced**.
   
   Scope was chosen by what the primitives already express, not by file count. 
Held back deliberately:
   
   - **16 files** whose icons use `slot`, `class`, `color` or their own aria — 
`app-icon` does not model these yet.
   - **Every file where an attribute would move** from `ion-button` onto the 
`app-button` host (`data-testid`, `title`, `id`), because e2e selectors say 
`ion-button[data-testid=…]` and **I cannot run e2e here**.
   - **`layout/` and `shared/`**, whose icons appear in the axe baseline in 
`e2e/accessibility.spec.ts`; making them `aria-hidden` would leave those 
entries stale with no way to confirm locally.
   
   ## 4. Regression cover — the part the suite was missing
   
   Of the 47 migrated components, 36 have a sibling spec and **almost none of 
those specs assert anything about a button**; only two test files in all of 
`src/app/features` mention `ion-button` or `app-button`. A full-suite pass 
proved the components still *construct*, not that their behaviour survived.
   
   - **`scripts/check-ui-primitives.mjs`** — every `<app-button>` declares 
`type`, and every one can be named. `type` is a required signal input, so a 
missing one throws NG0950 only when that screen renders, which for most list 
screens means in front of a user rather than in CI. Wired into `ci.yml`. 
Verified against broken probes: missing `type` caught, no-text-no-label caught, 
labelled icon-only allowed.
   - **`ClientNotesListComponent`** had no spec at all; it now asserts 
navigation commands, accessible name, click handler, icon, and the 
`*appHasPermission` guard — the dropped guard being the failure with real 
consequences. It reads button inputs rather than the DOM, because Ionic lifts 
`aria-label` into its shadow root and the DOM behaviour belongs to the 
primitive's own spec.
   
   **Five mutations of the migrated template were each confirmed to fail it**: 
removing the label, the click handler, the permission guard, the navigation, 
and the icon.
   
   ## 5. `aria-allowed-attr` baseline (#514)
   
   Four entries across two baselines read as four problems; they are one Ionic 
defect whose axe fingerprint moves with the host's state classes. Collected 
behind one constant with one comment. No entry added or removed. The upstream 
report #514 also asks for is **not** done here — that is filing in another 
project's tracker.
   
   ## Verification
   
   - **1512 unit tests across 246 files pass.**
   - `npm run lint` clean; `lint:prune` a no-op, so the baseline is exact 
rather than padded.
   - `test:eslint-rules`, `test:scripts`, `check:ui-primitives`, 
`check:a11y-names`, `check:icons`, `check:responsive`, `i18n:check`, 
`check:nav-ids`, `check:route-permissions`, `typecheck:e2e` all pass. Prettier 
clean on every changed file.
   - Negative checks throughout: the five template mutations above, and the 
three probes against the new static check.
   
   **Not run: e2e.** It needs browsers and a backend. This is the main residual 
risk on a 47-file template refactor, and it is why files whose attributes would 
move, and the axe-scanned shell, were held back rather than migrated. A 
reviewer running the e2e suites is the check I could not perform.
   
   ## Screenshots
   
   Not applicable. `app-button` renders the same `ion-button` with the same 
vendor inputs the call sites passed before — `color`/`fill` are now derived 
from `intent`/`emphasis` rather than written inline. No visual change intended.
   
   ## AI assistance (optional)
   
   - Tool / model: Claude Opus 5, via Claude Code.
   - Harness / workflow: assisted investigation, a scripted template migration, 
and drafting. The Prettier conflict was reproduced directly; the browserslist 
floor was read from `npx browserslist`; the migration was applied by script and 
then verified by lint, the static checks, the full unit suite, and the mutation 
probes above.
   
   ## Checklist
   
   - [x] I did not hand-edit generated files under `src/app/api/`.
   - [x] New component or service code uses the adapter boundary in 
`src/app/core/adapters/` instead of direct browser globals or imperative 
third-party APIs. — The migration moves 47 files off the vendor entirely.
   - [x] User-facing strings use translation keys. — No strings added; 
`[attr.aria-label]="… | translate"` became `[label]="… | translate"`.
   - [x] I added or updated tests appropriate to this change, or explained why 
tests were not needed.
   - [x] UI workflow changes include suitable e2e coverage, including 
real-backend testing where relevant. — Existing e2e is unchanged and still 
applies; files whose selectors would have moved were deliberately excluded, as 
described above. I could not run the suites locally.
   - [x] Commits are signed — see [Commit 
Signing](CONTRIBUTING.md#commit-signing) in CONTRIBUTING.md.
   - [x] I followed the [AI-assisted contributions 
guidance](CONTRIBUTING.md#ai-assisted-contributions).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to