Aman-Mittal opened a new pull request, #618:
URL: https://github.com/apache/fineract-backoffice-ui/pull/618
Fixes #611, fixes #612, fixes #613 — plus one defect the new contrast check
found on the way.
## #611 — a failed load rendered as "No records found."
Two screens threw *while mapping a successful response*. RxJS does not route
that to `error`, so both components' `error:` callbacks never ran and the
failure reached the operator as an ordinary empty state.
| Screen | Cause |
|---|---|
| `/system/entity-mapping` | `JSON.parse` on a body `HttpClient` had already
deserialised → `"[object Object]" is not valid JSON` |
| `/system/report-mailing-jobs` | paged envelope assigned into an
array-typed signal → `t is not iterable` in a downstream `computed` |
Entity mapping is the worse of the two: the sandbox endpoint returns **five
real rows**, and every one was hidden behind "No records found." The generated
client types that response `string` because the spec does, but the request asks
for `application/json` and the endpoint sends an array.
Report mailing jobs is a shape mismatch — the endpoint returns `{
totalFilteredRecords, pageItems }` while the generated type says `Array`.
`loadRunHistory()` in the same file already guarded exactly this; `load()`
never got the same treatment.
Both now normalise through a helper that accepts the array, the JSON string
and the envelope, and throws on anything else, so the caller can render
`app-load-error` with a retry. That component's own doc comment already
described this failure mode; it just was not reachable, because it hangs off
the `error:` path.
The same bare `JSON.parse(raw)` appears at six more call sites listed in
#611. None threw during the sweep, so they are left alone rather than changed
speculatively.
## #612 — idle logout explained nothing
`IdleService` sends `reason=inactivity`. `login.component.ts` compared only
against `session-expired`. So the **common** path — a 15-minute timer during
normal work — dropped the user at a silent login screen, while the rarer 401
path was explained. I hit this by accident mid-session before finding it in the
code.
Both reasons now live in `core/auth/logout-reason.ts` with a message apiece,
and the screen reads that map rather than testing one value, so adding a reason
without copy is a type error. `SESSION_EXPIRED_REASON` is re-exported so
existing importers keep working.
## #613 — primary buttons back under AA
`--ion-color-primary` was pointed at `--primary-strong` (#2471a3, 5.30:1) by
the #587 fix, then back at `--primary-color` (#3498db, **3.15:1**) by a later
commit on the same branch. Ionic pins `--ion-color-primary-contrast` to white;
`primary-strong` is the primary token held to a contrast floor by
`REQUIRES_WHITE_TEXT`, and `primary-color` is *deliberately* exempt because its
label is derived per-colour. Pairing a hardcoded white with the exempt token is
the defect. Restored, along with the `--ion-color-tertiary` block deleted
beside it, which two progressive-loan badges still use.
**Branded deployments were never affected** — `BrandingService` derives a
matching label, which is why a pale accent legitimately gets black text. That
behaviour is preserved: the service now emits the fill next to the companions
derived from the same hex, so a deployment overrides the new default instead of
inheriting it. Without that, a branded pale accent would have kept the default
dark fill and turned its label black.
Two latent traps surfaced while measuring:
- `var(--primary-dark, #1b4f72)` **never reached its accessible fallback** —
`--primary-dark` is defined as `#2980b9`, which is 4.30:1, under AA. Restoring
that line verbatim would have shipped another failure.
- Routing `-shade` through `--primary-text` would have put white on
`#5dade2` in dark mode, since that token flips light.
Both are literals now, with the reasoning in the stylesheet.
## Found by the new check: dark-mode secondary at 1.15:1
`--secondary-color` turns near-white (`#ecf0f1`) under
`[data-theme='dark']`, and `--ion-color-secondary-contrast` stays white — so
every `color="secondary"` button rendered a white label on near-white. Verified
on the deployed build: the Submit control on Survey Responses measures
**1.15:1**, an effectively invisible label. Same defect class as #613, so it is
fixed here rather than the check being weakened to let it through.
## The regression guard
`scripts/check-theme-contrast.mjs` (wired into `package.json` and CI, beside
`check:responsive`) asserts that every Ionic slot pinning a literal contrast
clears 4.5:1, in both themes. It resolves `var()` to the token's real value
rather than its fallback, which is what makes the `--primary-dark` trap visible.
Run against the pre-fix stylesheet it reports all seven failures rather than
crashing:
```
--ion-color-primary (light): #3498db on #ffffff is 3.15:1, below the 4.5:1
AA floor.
--ion-color-primary (dark): #3498db on #ffffff is 3.15:1, below the 4.5:1 AA
floor.
--ion-color-secondary (dark): #ecf0f1 on #ffffff is 1.15:1, below the 4.5:1
AA floor.
--ion-color-tertiary (light): --ion-color-tertiary is not declared
--ion-color-tertiary (dark): --ion-color-tertiary is not declared
--ion-color-primary-shade (light): #2e86c1 is 3.97:1 against the button
label, below the 4.5:1 AA floor.
--ion-color-primary-shade (dark): #2e86c1 is 3.97:1 against the button
label, below the 4.5:1 AA floor.
```
This is the check whose absence let #587's fix be reverted and shipped.
## Tests
**Unit — 1562 passing, up from 1535.** New coverage: both
payload-normalising helpers across array / JSON-string / envelope / null /
unreadable shapes; the failure and recovery transitions on both screens; the
reason→message mapping including an unknown reason; the branding fill emitted
beside its derived label, and the pale-accent pairing.
**e2e — 37 passing** across four mocked specs. Two are new:
- `e2e/list-load-failure.spec.ts` — rows render when the endpoint returns
its real shape; a 200 carrying an unreadable payload shows the error state and
*not* "No records found."; retry recovers.
- `e2e/logout-reason-notice.spec.ts` — each reason gets its own wording, and
an absent or unrecognised reason shows nothing rather than a blank notice.
`e2e/branded-deployment.spec.ts` and `e2e/deployment-customization.spec.ts`
are updated where they asserted the pre-#613 contract, and otherwise pass
unchanged — including the pale-accent test, which is what caught my first
attempt at this fix.
Also green: `npm run build`, `lint`, `format:check`, `typecheck:e2e`,
`test:scripts`, `test:eslint-rules` and all 12 `check:*` scripts.
**One pre-existing failure, unrelated:** `accessibility.spec.ts:344` fails
identically on unmodified `main` and on this branch. I verified it against a
clean checkout rather than assume; it is not touched here.
--
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]