id: TEDY.01.4 template: tool-feature module: tedy state: Proposed traces-from: [] source-refs:
- reference-editor/app/src/app/resources/code-system/containers/concepts
- terminology-server/ts/code-system (concept + entity-version transaction)
- helex-tx/modules/tedy/frontend/src/pages/code-system/CodeSystemConceptsTab.tsx
- helex-tx/modules/tedy/frontend/src/pages/code-system/concepts/presentation.ts
- helex-tx/modules/tedy/frontend/src/pages/code-system/concepts/ConceptPresentationTable.tsx
- helex-tx/modules/tedy/frontend/src/pages/code-system/concepts/ConceptCell.tsx
- helex-tx/modules/tedy/frontend/src/pages/code-system/concepts/ConceptColumnBuilder.tsx
- helex-tx/modules/tedy/frontend/src/pages/code-system/concepts/ConceptEditForm.tsx
- helex-tx/libs/tedy/src/lib/client/conceptClient.ts
- helex-tx/libs/tedy/src/lib/hooks/useConcepts.ts
- helex-tx/libs/tedy/src/lib/utils/conceptDisplay.ts author: TEDY bootstrap created: 2026-08-09 updated: 2026-08-09
TEDY.01.4 – Code System Concept Presentation
Feature grouping
Child of TEDY.01 – Code System (Common Spec). Refines the Concepts tab of TEDY.01.3 – Code System View. Siblings: TEDY.01.1 List, TEDY.01.2 Add.
Description
The Concepts tab renders a Code System’s concepts through a configurable,
definition-driven presentation instead of a fixed code / display / status table.
A Code System carries far more per concept than three columns can show —
designations in many languages and typed property values (some resolved
against other code systems or value sets) — and large systems are hierarchical
(e.g. an ICD-10 edition with tens of thousands of concepts under an is-a tree).
The user composes which fields appear, how they are grouped into columns, and how designations / properties are laid out, using a two-column drag builder. The layout is derived by default from the Code System definition and persisted per Code System. The presentation table itself stays read-only (“light immutable”); editing a concept happens in the selected row’s detail form, which saves the whole concept back through the entity-version transaction.
┌ Concepts ───────────────────────── [ Search ] [ ⚙ Configure ] [ ⛃ ] ┐ ┌ Concept ───────────┐
│ Code │ Display / Designations │ Properties │ │ allergy [active] │
│ allergy │ Allergy │ valueset: …/allergy │ │ Designations +Add│
│ │ en: Allergy │ ui-component: select │ │ en Allergy ★ │
│ │ et: Allergia │ usage: clinical │ │ et Allergia ☆ │
│ │ ru: Аллергия │ careplan-printout: true │ │ Properties +Add ▾ │
│ diagnosis │ Diagnosis │ conceptOrder: 10 │ │ valueset […] │
│ │ en: Diagnosis │ codesystem: …/rhk10 │ │ … │
│ │ … │ … │ │ [ Save ] │
└──────────────────────────────────────────────────────────────────────┘ └────────────────────┘
Glossary Terms
Per TEDY.01 § Glossary, plus:
| Term | Meaning |
|---|---|
| Presentation | The per-Code-System layout config: mode, editable flag, and columns. |
| Column | A first-level group in the presentation; renders one table cell per concept. |
| Element | A second-level item inside a column: code, display, status, designations, properties, or br (line break). |
| Designation block | A single element that renders a concept’s designations, optionally filtered to chosen languages. |
| Property block | A single element that renders a concept’s property values, optionally filtered to chosen properties. |
| Defined property | A CodeSystem.property entry, carrying kind (property | designation), type, showInList, and an optional Coding rule. |
Business Feature Sitemap
flowchart LR
ROOT[TEDY.01] --> VIEW[TEDY.01.3 View]
VIEW --> CT[TEDY.01.4 Concept Presentation]
CT --> TBL[Read-only table\nplain / hierarchical]
CT --> CFG[Configure builder\ndrag columns]
CT --> EDIT[Editable detail\ntransaction save]
The presentation config model
Two levels only: columns (level 1) → elements (level 2). code is pinned as
the first element of the first column and cannot be moved or removed.
type ConceptElement =
| { kind: 'code' } // pinned first; not movable/removable
| { kind: 'display'; bold?: boolean }
| { kind: 'status' }
| { kind: 'designations'; languages?: string[] } // undefined/empty ⇒ all languages
| { kind: 'properties'; names?: string[] } // undefined/empty ⇒ all showInList
| { kind: 'br' }; // explicit line break
interface ConceptColumn {
id: string;
title?: string; // non-localized header override (legacy / fallback)
titles?: Record<string, string>; // localized header per language code, e.g. { en: 'Term', et: 'Termin' }
elements: ConceptElement[];
}
interface ConceptPresentation {
mode: 'plain' | 'hierarchical';
editable: boolean;
columns: ConceptColumn[];
}
designationsandpropertiesare single whole-block elements — the user places the block, then chooses which languages / which properties it includes. Individual designations are never split across columns. A block may share a column with other elements (the default groupsdisplay+designations).- Singleton elements (
code,display,status,designations,properties) may appear at most once across the whole presentation;brmay repeat. - Localized column header — a column may carry a per-language header via
titles(keyed by language code, from the CS’s supported languages). When absent, the header is auto-derived from the column’s elements. Resolution for a display languageL:titles[L]→title(legacy) → any settitlesvalue → the auto-derived label. This is a presentation preference only (client-side; no server field).
Default presentation (derived from the CS definition)
mode=hierarchicalwhenCodeSystem.hierarchyMeaningis set, elseplain.editable=false.columns=[ [code], [display(bold), designations], [properties] ], where thedesignationsblock defaults to all languages and thepropertiesblock defaults to properties withshowInList. A line break is rendered automatically before the designations block (it is not the first text in its column).
Read-only cell rendering rules (per column, per concept)
Each element renders in order into a single cell:
code→concept.code.display→conceptDisplay(concept, language)(bold whenbold).status→ status chip (the concept’s current entity-version status).designations→ the concept’s designations, filtered tolanguagesif set (else all), preferred-language first, each shown aslang + ": " + value, and preceded by a line break unless it is the first text already in the column.properties→ each included property (namesif set, elseshowInList) aslabel: value, one per line;Codingvalues resolve to a display via the propertyrule(value set / code systems); each preceded by a line break unless first in the column.br→ a line break.
Configuration builder
Opened from a Configure button on the concepts toolbar (an AppDrawer, size 880).
Built with @dnd-kit (module-local dependency) as a two-container sortable.
- Left — palette + settings:
modeselect (plain | hierarchical);editablecheckbox; a⋯menu with Clear (empty all but the pinned code column) and Reset to defaults (recompute from the CS definition); and the source elements not yet placed (display,status,designations,properties). - Right — presentation builder: ordered columns, each a droppable group of
sortable elements, with an Add line break affordance and an Add column
button.
displaycarries a Bold toggle;designationsandpropertiescarry an inline picker (languages / property names, “All” when none chosen).codeis rendered pinned in the first column and is not draggable or removable. - Drag palette → column adds; drag element → palette removes; drag within/between columns
reorders (never before the pinned
code). - Rename column — each column header has a rename (✎) control opening a popover with
one input per supported language (seeded from the column’s
titles); the control is highlighted when a custom header is set. Blank inputs fall back to the auto-derived label. - Apply persists the presentation (including per-column
titles) and updates the live table; Cancel discards.
Persistence
Per Code System, in browser localStorage under key
helex.tedy.conceptPresentation.{codeSystemId}. On load the saved config is used;
absent (or on Reset) the default is recomputed from the CS definition. No server-side
presentation store exists.
Editable detail + save
When editable is on, selecting a row opens the editable concept detail form
(otherwise the read-only view is shown):
- Designations — rows of language select · type select · value · preferred star · delete; Add appends a row.
- Property values — one row per value, typed by the defined property:
boolean→ checkbox;integer/decimal→ number input;Coding→TxConceptSelectscoped by the propertyrule.valueSet(falling back to code + code-system inputs); otherwise a text input. Add property appends from the CS’s defined value-properties. - Save builds
{ concept, entityVersion }with the complete designation and property-value lists and POSTs the concept transaction (full replace of the current entity version — terminology-server has no JSON-patch). Version-scoped when a version route is active, else resource-level. The concepts query is invalidated on success.
Data Model
Reuses TEDY.01 § Data Model. Fields consumed here:
CodeSystem.hierarchyMeaning— association type driving the tree (e.g.is-a).CodeSystem.property[](defined properties) —name,type,kind(property|designation),showInList, andrule({ valueSet?, codeSystems? }) for Coding resolution.CodeSystemVersion.supportedLanguages/preferredLanguage— the language set and preferred order.concept → versions[] → { designations[], propertyValues[], associations[] }:Designation:name(value),language,preferred,status,designationType.EntityPropertyValue:value,entityProperty(name),entityPropertyId,entityPropertyType.concept.leaf/concept.childCountgate the tree expander.
API Endpoints
All under /ts/code-systems/{id} (see TEDY.01 § API).
| Purpose | Call |
|---|---|
| List (flat, paged) | GET …/concepts?textContains&codeSystemEntityStatus&codeSystemVersion&displayLanguage&limit&offset&sort |
| Roots (tree) | GET …/concepts?associationRoot={hierarchyMeaning}&sort=code&limit&offset |
| Children (one level, lazy) | `GET …/concepts?associationSource={hierarchyMeaning} |
| Filtered tree | GET …/concepts/tree-search?associationType={hierarchyMeaning}&textContains=… → flat items with parentCode + matched |
| Save (transaction) | POST …/[versions/{version}/]concepts/transaction body { concept, entityVersion } |
| Delete | DELETE …/concepts/{code} |
Envelope: { data, meta }; errors per the TEDY.01 error contract.
Sitemap / Navigation
No new routes. Enhances the existing Concepts tab of TEDY.01.3:
/tedy/code-systems/{id}/concepts (resource-level) and the version-scoped concepts
route when active. The Configure drawer and detail panel are in-page surfaces.
Security / Permissions
- Read: browse the presentation with
CodeSystemread access. - Edit (the
editabletoggle + Save): requires*.CodeSystem.write; the Save action is gated by the same privilege as TEDY.01.2 / the code-system edit flow. - Presentation config is a client-only preference — no permission implications.
Non-Functional Requirements
- Hierarchical mode loads children lazily, one level per expand, so a 30k+ concept system opens without fetching the whole tree.
- The table is never inline-editable; editing is isolated to the detail form to keep large lists responsive.
- i18n: all builder / edit labels in en / et / ru (
tedy.concept.presentation.*,tedy.concept.edit.*); designation language codes render verbatim.
Business Tests
- Default layout — a plain CS opens with columns
code·display(bold) + designations·properties(showInList); designations readlang: value, preferred-language first. - Hierarchical — a CS with
hierarchyMeaningopens as a tree; expanding a node lazily loads its children; leaves show no expander. - Configure round-trip — add / remove / reorder columns and elements, toggle bold, pick designation languages and properties, Apply → the table updates and the config survives reload; Reset restores the derived default; Clear leaves only the pinned code.
- Code pinned —
codecannot be dragged, removed, or displaced from the first cell. - Editable detail — with
editableon, selecting a row shows the edit form; a boolean property renders a checkbox, a Coding property a value-set select; Save posts the transaction and the row reflects the change after refresh. - Localized column header — rename a column with a title per language, Apply → the header shows the title for the active display language and survives reload; switching the display language shows that language’s title (or the auto-derived label if none set).
Source Code References
- Presentation model + persistence:
presentation.ts. - Read-only table (plain + hierarchical):
ConceptPresentationTable.tsx,ConceptCell.tsx. - Builder:
ConceptColumnBuilder.tsx(@dnd-kit). - Editable detail:
ConceptEditForm.tsx. - Tab wiring:
CodeSystemConceptsTab.tsx. - Data layer:
libs/tedyconceptClient.ts(searchConcepts,searchConceptRoots,searchConceptChildren,searchConceptTree,saveConcept,deleteConcept) +useConcepts.ts(useConcepts,useConceptRoots,useSaveConcept).
Differences (live vs source)
- The reference editor’s concept view is a fixed code / display / status table with a
separate edit dialog. TEDY generalises the read layout into a definition-driven,
user-composed presentation while keeping the same terminology-server contracts
(concept list params, hierarchy via
hierarchyMeaning, entity-version transaction). - “Patch” in the original requirement maps to the entity-version transaction (full replace); terminology-server exposes no JSON-patch for concepts.
- Presentation config is a TEDY-only client preference; the reference product has no equivalent per-CS layout store.
Traces
traces-from is empty pending a user story (EMR rules require a story before a solution
spec). Gap: create a thin “configure how a Code System’s concepts are presented” story
and link it here before promotion to Accepted.