feat(test-catalogue): localization and LOINC for panels and sample types - #4080
Merged
Conversation
Eight things, in the new Test Catalogue Management area and around it. Legacy navigation ----------------- Manage Sample Types under the legacy Test Management menu had stopped opening the legacy page. Admin routed /SampleTypeManagement to the new editor, which left the legacy page unreachable while its tile still said Manage Sample Types. The legacy page answers there again and the new editor moved to /SampleTypeEditor. The other legacy tiles were checked; only this one had been taken over. Localization for panels and sample types ---------------------------------------- Both keep their display name in the same generic localization tables a test does, and each already FK-links to its row there, so the editors were missing a section rather than a store. Two endpoints bridge an id to the backing localization id, and the section a test uses is now shared: entity-agnostic already, so it takes the endpoint and the id rather than being duplicated twice. The strings that name what is being translated are entity-specific, so a sample type is no longer told it is editing "this test's name and reporting name". Names loaded from a sample-types configuration file land in those same tables, so what the file configured is what the editor shows. LOINC on sample types --------------------- A sample-types configuration file can carry a loinc column, recorded as a LOINC / SAME_AS terminology mapping — the store the editor reads, so a configured code is visible and editable there. The column is optional: a file without it says nothing about LOINC rather than asking for an existing mapping to be cleared, and a relationship chosen in the editor survives re-import, because the file names which code, not what it means. Panel LOINC in both directions ------------------------------ panel.loinc predates panel_terminology_mapping and FHIR intake still routes electronic orders by the column. Editor to column already worked; column to editor did not, so a code entered on the legacy pages was invisible to the editor and saving there would write its empty set back over it. syncLegacyLoinc closes that leg, and changeset 084 carries existing codes across as SAME_AS once. Keeping the two in step from then on is the service layer's job, not another migration's — there is no migration writing panel.loinc. Documented in docs/panel-loinc-terminology-migration.md. Empty states, per entity ------------------------ With nothing selected, the panels and sample types contexts fell through to the tests branch: a reader on the Panels list was shown the nine test sections, greyed, under "Click a test to edit its sections". Each entity now greys its own sections and says so. Names ----- Test Catalogue Editor, Panel Editor, Sample Type Editor, consistently, including two user-facing strings that still called the Panel Editor "Panel Management". The legacy pages keep their own names — they are a different thing and item 1 is about leaving them alone. Selecting a sample type ----------------------- Clicking a row opens it, as it does for tests and panels, rather than requiring the Edit button. The handler sits on the data cells so the Edit button cannot fire it twice, and the row keeps its tab stop and Enter. The checkbox on a test row -------------------------- It selects a row for the "Edit related" batch action, which needs two or more tests — a real purpose, so it is fixed rather than removed. It was not independently clickable because the onClick that tried to stop propagation on TableSelectRow never reached the DOM: Carbon destructures a fixed set of props there and onClick is not among them. The box did toggle; the navigation took the list away before a second row could be picked. The row-opening click moved to the data cells, leaving the checkbox cell outside it — selection, batch actions and keyboard access unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rename Existing Sample Types opened an empty page, and Rename Existing Result List Options white-screened. Two unrelated causes, both small. The sample type screen had no route. Its tile, its component and its REST controller all existed; nothing in Admin's Switch matched /MasterListsPage/SampleTypeRenameEntry, so the link resolved to the admin shell with nothing inside it. Every other rename tile in that menu had one. The result list screen died on a null option. Its list is built from test_result rows rather than from the dictionary, so it can name a dictionary entry that is no longer there, and getAllSelectListOptions added whatever getDictionaryById returned. Those nulls reached the browser and the first one took the page down, however many valid options followed it. Two showed up on a dev database: a row with a blank value, and one naming a dictionary id with no row behind it. The same class's getTestSelectDictionary already skips ids that do not resolve; this one had been missed. Verified against a deployed build: the endpoint went from 59 entries with two nulls to 57 with none, both screens list and open their items, and a rename saves and can be renamed back. The route test now derives the rename tiles from the menu, so a tile added without a route fails there rather than in someone's browser. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…itor Renaming a result list option replaced its French name with the English text. The option list carries one name per option — whichever locale it was read in — so the screen had nothing else to send, and it sent what it was displaying as every language. The French field had been commented out, which hid the effect without stopping it. EntityNamesProvider now answers for a result select option, the way it already did for panels, sample types, test sections, units and methods, so the screen can read what each language currently says. It prefills a field per language from that and sends back exactly what is in them. A blank field means that language is not being renamed, so it is left as it stands rather than stored empty — otherwise editing one language would still clear the other, just in the opposite direction. An option whose name had never been translated also could not be renamed at all: renameOption built a localization for it and saved it without ever attaching it to the dictionary row, so the row was an orphan and the displayed name never changed. Its French field now starts empty rather than seeded with the English text, so saving cannot invent a translation. Verified against a deployed build, reading the database directly: renaming only the English leaves the French intact, renaming only the French leaves the English intact, and a French name can be added where there was none. Also, the panel entity was still called "Panels" while its two peers read as editors. One key drives the SideNav item, the list heading and both breadcrumb trails, so it now says Panel Editor in all four. The Test Catalogue Editor's own Panels section keeps its name — it lists the panels a test belongs to, and is not the editor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Localization and LOINC for panels and sample types
Eight items in and around the new Test Catalogue Management area. Each was investigated before it was changed; the root causes are below because several were not what they looked like.
1. Legacy Test Management links open legacy pages again
Manage Sample Types had stopped opening the legacy page.
Admin.jsxrouted/MasterListsPage/SampleTypeManagementto the new editor, which left the legacy page unreachable while its tile still said Manage Sample Types.The legacy page answers there again (
exact), and the new editor moved to/SampleTypeEditor/:sampleTypeId?/:section?, withAdminSideNavupdated. I checked every other tile in that menu —PanelManagement,TestSectionManagement,MethodManagement— and only the sample type one had been taken over. A test now pins all of them.2. Localization on the new Panel and Sample Type editors
Both keep their display name in the same generic
localizationtables a test does, and both already FK-link to their row there. So this was a missing section, not a missing store.GET /rest/test-catalog/panels/{id}/localizationandGET /rest/sample-types/{id}/localization, returning the same{fields:[{field, localizationId}]}shape the test endpoint returns.LocalizationSectionwas already entity-agnostic below its copy, so it is shared rather than duplicated: it takes the bridge endpoint and the id.Sample-type names loaded from
configs/configuration/backend/sample-typesland in those same tables, so what the file configured is what the editor shows.3. LOINC on sample type configuration
example-sample-types.csvgains aloinccolumn (aftersortOrder, before thelocalization:*block). A code there is recorded as LOINC / SAME_AS — the store the editor's Terminology section reads — so it is visible and editable.The column is optional and backward compatible: header validation only ever required
descriptionandlocalAbbreviation, so every existing distro file keeps importing. Two deliberate choices:4. Panel LOINC, both directions, plus a migration
panel.loincpredatespanel_terminology_mapping, and FHIR intake still routes electronic orders by the column.panel.loincsaveMappingsForPanel)panel.loinc→ editorsyncLegacyLoinc), wired into the legacy panel create pathWithout the second leg, a code entered on the legacy pages was invisible to the editor — and saving there wrote the editor's empty set back over it.
Changeset
084-panel-loinc-terminology-backfill.xmlcarries existing codes across as SAME_AS, once. It is deliberately one-way: no migration writespanel.loinc, because keeping the two in step afterwards belongs in the service layer. It writesSAME_ASdirectly rather than repeating the test-side backfill'sEQUIVALENT, which needed a second changeset to correct.docs/panel-loinc-terminology-migration.mdcovers how to run it, how to preview what it touches, and why it is safe to re-run.5. Empty-state messaging, per entity
With nothing selected, the panels and sample types contexts fell through to the tests branch: standing on the Panels list you were shown the nine test sections, greyed, under “Click a test to edit its sections”. Each entity now greys its own sections with its own message:
Localization appears among the sections for both new entities.
6. Editor names
Test Catalogue Editor, Panel Editor, Sample Type Editor, consistently across headings, navigation, labels and empty states — including two user-facing strings that still called the Panel Editor “Panel Management”, and stale
defaultMessages.The legacy pages keep their own names (“View Test Catalog” and friends). They are a different thing, and item 1 is about leaving legacy navigation alone. That does leave “Catalog” beside “Catalogue” in the app — happy to rename legacy too if that is preferred.
7. Selecting a sample type opens its editor
Was Edit-button only. The handler sits on the data cells rather than the row, so the Edit button in the last cell cannot fire it twice, and the row keeps its tab stop and Enter/Space.
8. The checkbox on a test row — findings
What it represents. Multi-select feeding the “Edit related” batch action, which opens the combined editor over the selected set and is
disabledunder two selections.Does it have a valid purpose? Yes — so it is fixed, not removed.
Why it was not independently clickable. A previous attempt already passed
onClick={(e) => e.stopPropagation()}toTableSelectRow. That is dead code. Carbon destructures a fixed prop list there:onClickis not among them, so the handler never reaches the DOM and the click bubbled to the row. The box did toggle — the navigation simply took the list away before a second row could be picked, which is why it looked like the checkbox did nothing.Resolution. The row-opening click moved from
TableRowonto the dataTableCells, leaving the checkbox cell outside the clickable area. Selection, batch actions and keyboard access are unchanged, and a regression test asserts a checkbox click neither navigates nor fails to toggle.Verification
37 new tests, every one inversion-verified (reverted the fix, watched the test fail, restored):
ResultValidationServiceTest.testPersistdata_shouldCreateNewNote— a note-id constraint collision that passes in isolation, is unrelated to anything here, and has recurred across unrelated branches this week.Live, against a deployed build — 18 checks, 0 failures, no JS errors:
🤖 Generated with Claude Code