fix(configurator): dedupe duplicate options in dropdown/select fields (#1923) - #1932
Open
Lokendra-egov wants to merge 1 commit into
Open
fix(configurator): dedupe duplicate options in dropdown/select fields (#1923)#1932Lokendra-egov wants to merge 1 commit into
Lokendra-egov wants to merge 1 commit into
Conversation
…#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>
Lokendra-egov
requested review from
Hari-egov,
KDwevedi,
pradeepkumarcm-egov,
subhashini-egov and
vinothrallapalli-eGov
as code owners
August 31, 2026 11:17
Contributor
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 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. Comment |
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.
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 calledADMINand three calledKE-ADMIN, every one of them rendered as ticked, with the trigger readingADMINADMINADMINADMINAD….Root cause is two layers deep, and both need closing:
1. Data.
boundaryHierarchyGetListconcatenates the state tenant's hierarchy definitions with every city tenant's, and DIGIT does not require ahierarchyTypeto be unique across tenants. Confirmed against live bomet:ADMINke,ke.mycitynew,ke.bndry,ke.india,ke.etoebeta,ke.etoeroles,ke.hajbvfgKE-ADMINke.india,ke.etoebeta,ke.etoerolesboundaryGetListhas 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_001andWARD_001are each defined under two different city tenants. react-admin's contract is one record perid, so these lists violated it and every consumer inherited the duplicates.2. Rendering. A Radix
Selecttreats twoSelectItems sharing avalueas one selection: all of them render checked, and<SelectValue>prints the label of every match — which is exactly theADMINADMIN…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 controlsDigitFormSelectandReferenceSelectthat back most other pickers.Second defect found while writing the tests
boundaryTypesByHierarchywas last-wins while the option list is first-wins. A sub-tenant's shallower same-namedADMINsilently truncatedke'sCounty → SubCounty → Wardcascade down to justCounty. Now first-wins in bothJurisdictionEditorandLocalityPicker, 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.ts—boundary-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
masterand unrelated (validation.postalCodeDDH 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 onke:ADMIN/INDIA/KE-ADMIN/POC_MZPT_ADMINappear exactly once each. Trigger shows a cleanADMIN.DEMO_CCRS_1923_1788174093976, uuid2b015842-b35c-4d46-b45c-4892911abf10) and verified viaegov-hrms /employees/_searchthat it persisted correctly:EMPLOYED, tenantke, roleGRO, current assignment, and jurisdictionhierarchy: 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
access/v1/roles/_searchreturns 27 unique codes today. The dedupe there is a guard, unverified against real duplicate data.JurisdictionEditor's<Label>s are not wired to their Select triggers, so those comboboxes have no accessible name.perPage: 100while bomet has 302 hierarchy definitions — safe only because the real ones sort before thePW_*Playwright stubs.🤖 Generated with Claude Code