Skip to content

fix(configurator): dedupe duplicate options in dropdown/select fields (#1923) - #1932

Open
Lokendra-egov wants to merge 1 commit into
masterfrom
fix/1923-duplicate-dropdown-options
Open

fix(configurator): dedupe duplicate options in dropdown/select fields (#1923)#1932
Lokendra-egov wants to merge 1 commit into
masterfrom
fix/1923-duplicate-dropdown-options

Conversation

@Lokendra-egov

Copy link
Copy Markdown
Collaborator

Fixes #1923

The bug

The employee create/edit form's Jurisdiction → Hierarchy picker listed the same hierarchy over and over — on bomet (ke), seven rows called ADMIN and three called KE-ADMIN, every one of them rendered as ticked, with the trigger reading ADMINADMINADMINADMINAD….

Root cause is two layers deep, and both need closing:

1. Data. boundaryHierarchyGetList concatenates the state tenant's hierarchy definitions with every city tenant's, and DIGIT does not require a hierarchyType to be unique across tenants. Confirmed against live bomet:

hierarchyType count tenants
ADMIN 7 ke, ke.mycitynew, ke.bndry, ke.india, ke.etoebeta, ke.etoeroles, ke.hajbvfg
KE-ADMIN 3 ke.india, ke.etoebeta, ke.etoeroles

boundaryGetList has the same shape and carries a comment asserting "duplicates are avoided because tenants own disjoint boundary code-spaces" — that assumption is false in practice: CITY_001 and WARD_001 are each defined under two different city tenants. react-admin's contract is one record per id, so these lists violated it and every consumer inherited the duplicates.

2. Rendering. A Radix Select treats two SelectItems sharing a value as one selection: all of them render checked, and <SelectValue> prints the label of every match — which is exactly the ADMINADMIN… trigger in the issue screenshot. Option values are business keys (code), not react-admin ids, so fixing the data layer alone would not have covered master-data duplicates.

The fix

  • dedupeById (packages/data-provider/src/providers/dataProvider.ts) enforces one-record-per-id on every list read (fetchAll, plus the MDMS fast path). Keep-first, because aggregating fetchers list the session tenant's records before its sub-tenants' — so the survivor is the definition the operator is actually working in.
  • uniqueBy (src/lib/uniqueBy.ts) collapses choices on the value the control submits, never on the display label — two distinct codes may legitimately share a name (a "Central" ward in two counties), and dropping one would hide a real choice. This is the point the issue asked us to tread carefully on.

Audited and applied across: JurisdictionEditor (hierarchy + every cascade level), LocalityPicker, AssignmentEditor (department, designation), useRolesLookup, DepartmentChipInput, ComplaintHierarchyCascade, OrgChartPage, plus the two shared controls DigitFormSelect and ReferenceSelect that back most other pickers.

Second defect found while writing the tests

boundaryTypesByHierarchy was last-wins while the option list is first-wins. A sub-tenant's shallower same-named ADMIN silently truncated ke's County → SubCounty → Ward cascade down to just County. Now first-wins in both JurisdictionEditor and LocalityPicker, so the levels always belong to the hierarchy whose option the operator picked.

Regression coverage

  • JurisdictionEditor.test.tsx — drives the reported screen with the real bomet data shape. All three cases fail without the fix (5 hierarchy options instead of 2; 3 boundary options instead of 2; cascade truncated to one level).
  • uniqueBy.test.ts — pins keep-first and the label-vs-value distinction.
  • dataProvider.test.tsboundary-hierarchies, boundaries, access-roles, plus a guard asserting that records sharing a name but not a code survive.

Suite: 152/153 and 26/29. The remaining failures are pre-existing on clean master and unrelated (validation.postalCode DDH seed drift; three complaint-type hierarchy tests).

Verified end-to-end against live bomet

Local dev build proxied to bometfeedbackhub.digit.org, logged in as ADMIN on ke:

  • Hierarchy dropdown renders 100 options with zero duplicates; ADMIN / INDIA / KE-ADMIN / POC_MZPT_ADMIN appear exactly once each. Trigger shows a clean ADMIN.
  • Roles (27), Department (33), Designation (50) — all checked, no duplicates.
  • Created a real employee through the form (DEMO_CCRS_1923_1788174093976, uuid 2b015842-b35c-4d46-b45c-4892911abf10) and verified via egov-hrms /employees/_search that it persisted correctly: EMPLOYED, tenant ke, role GRO, current assignment, and jurisdiction hierarchy: ADMIN / boundaryType: Ward / boundary: BOMET_BOMET_CENTRAL_CHESOEN. Reopening the edit screen rehydrates the full cascade — so the deduped option is a working choice, not an inert label.

Not covered — flagging rather than widening scope

  • The roles duplication in the issue's second screenshot could not be reproduced: bomet's access/v1/roles/_search returns 27 unique codes today. The dedupe there is a guard, unverified against real duplicate data.
  • Pre-existing, untouched: JurisdictionEditor's <Label>s are not wired to their Select triggers, so those comboboxes have no accessible name.
  • Pre-existing, untouched: the hierarchy dropdown requests perPage: 100 while bomet has 302 hierarchy definitions — safe only because the real ones sort before the PW_* Playwright stubs.

🤖 Generated with Claude Code

…#1923)

The employee form's Jurisdiction > Hierarchy picker listed the same
hierarchy over and over — on bomet (`ke`), seven rows called "ADMIN" and
three called "KE-ADMIN", every one of them ticked, with the trigger
reading "ADMINADMINADMINADMINAD...".

Root cause is two layers deep:

1. `boundaryHierarchyGetList` concatenates the state tenant's hierarchy
   definitions with every city tenant's, and DIGIT does not require a
   `hierarchyType` to be unique across tenants. Seven `ke.*` tenants each
   define their own "ADMIN". `boundaryGetList` has the same shape and the
   same false assumption ("tenants own disjoint boundary code-spaces") —
   `ke.mycitynew` and `ke.hajbvfg` both seed CITY_001 and WARD_001.
   react-admin's contract is one record per `id`, so these lists violated
   it and every consumer inherited the duplicates.

2. A Radix `Select` treats two `SelectItem`s sharing a `value` as ONE
   selection: both render checked, and `<SelectValue>` concatenates every
   matching label — which is the "ADMINADMIN..." trigger. Option values
   are business keys (`code`), not react-admin ids, so fixing the data
   layer alone would not have covered master-data duplicates.

Both layers are now closed:

- `dedupeById` in the data provider enforces one record per id on every
  list read (`fetchAll`, plus the MDMS fast path). Keep-FIRST, because
  aggregating fetchers list the session tenant's records first — so the
  survivor is the definition the operator is actually working in.
- `uniqueBy` collapses choices on the value the control SUBMITS, applied
  across the audited dropdowns: JurisdictionEditor (hierarchy + each
  cascade level), LocalityPicker, AssignmentEditor (department,
  designation), useRolesLookup, DepartmentChipInput,
  ComplaintHierarchyCascade, OrgChartPage, and the two shared controls
  DigitFormSelect and ReferenceSelect, which back most other pickers.

Never on the display label: two distinct codes may legitimately share a
name (a "Central" ward in two counties) and dropping one would hide a
real choice.

Also makes `boundaryTypesByHierarchy` first-wins in JurisdictionEditor and
LocalityPicker. It was last-wins, so a sub-tenant's shallower same-named
"ADMIN" silently truncated the state tenant's County > SubCounty > Ward
cascade to just County — inconsistent with the option the operator sees.

Regression coverage: JurisdictionEditor.test.tsx drives the reported
screen with the real bomet shape (all three cases fail without the fix),
uniqueBy.test.ts pins keep-first and the label-vs-value distinction, and
dataProvider.test.ts covers boundary-hierarchies, boundaries and
access-roles plus a guard that same-name/different-code records survive.

Verified end-to-end against live bomet data: hierarchy dropdown now
renders 100 options with zero duplicates (ADMIN/INDIA/KE-ADMIN/
POC_MZPT_ADMIN once each), and an employee created through the form
persisted the correct jurisdiction (ADMIN / Ward /
BOMET_BOMET_CENTRAL_CHESOEN).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 38e9754c-2dda-4ac9-a1db-b7d2ce5dc362


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Duplicate records rendered in dropdown/select fields on the configurator

1 participant