Skip to content

refactor(ui): unify the CapabilityStatement implementation shared by HFS and HTS - #845

Merged
smunini merged 6 commits into
mainfrom
feat/808-unify-capability-statement
Sep 2, 2026
Merged

refactor(ui): unify the CapabilityStatement implementation shared by HFS and HTS#845
smunini merged 6 commits into
mainfrom
feat/808-unify-capability-statement

Conversation

@smunini

@smunini smunini commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Closes #808.

Where it landed

helios-ui-chrome — the crate #543 already created. #808 asked the PR to say
which: this stacks on that extraction rather than creating a new minimal crate.

What is shared now

helios_ui_chrome::capability owns the projection and the four cards both
products stack:

  • build_view and the view model (CapabilitySummary, SystemInteraction,
    OperationRow, InteractionTag, ResourceRow), plus
    safe_canonical_href, system_interaction_href,
    resource_definition_href and interaction_tag_class.
  • templates/partials/capability-{summary,interactions,operations,resources}-card.html,
    rendered through a CapabilityCards builder.

The crate stays a leaf — serde_json + url, no axum, no HTTP client, no
FHIR schema pack — because the two questions it cannot answer are supplied by
the caller:

supplied by HFS supplied by HTS
DocsVersion (which release to link into) total match on FhirVersion DocsVersion::from_code(state.fhir_version)
CoreResourceCatalog (does this type have an official page in that release?) the validator's core schema packs the three types a terminology server serves

Keeping FhirVersion out is deliberate: its variants are #[cfg]-gated, so
naming it here would drag a leaf crate into the R4/R4B/R5/R6 feature matrix of
both products for the sake of four documentation roots.

What each page keeps, because the difference is real

Behaviour changes

All on the HTS page, which is the one that had been missing the improvements:

  • Resource types and operation definitions are now links into the release the
    binary was built for, and interaction verbs carry the semantic tag palette
    (tag--member / tag--config / tag--excluded / tag--muted).
  • "Base URL" now shows implementation.url, which is what the label
    promises, rather than the statement's own url canonical — that identifies
    the document, not the endpoint. HTS emits no implementation.url, so the
    row renders an em-dash; the canonical is still in the raw fold.
  • Absent summary fields render an em-dash rather than a blank cell, on both
    pages.
  • rest[] is flattened across every server component instead of reading
    rest[0] (HFS's old reading). rest is 0..*; mode: "client" components
    are excluded, since they describe what the server calls, not what it serves.

No new Fluent keys — the cap-* catalog was already shared.

Acceptance criteria

  • One parser produces the view model both pages render.
  • The version-correct documentation links work on both pages.
  • Interaction verbs are colour-coded identically on both.
  • The HTS Terminology capabilities card still renders.
  • HTS still degrades per-card when one upstream fetch fails.
  • The raw-statement block handles a 400 KB+ statement without wedging the
    page, and states plainly when it truncates. (Unchanged on both sides:
    HFS never inlines it, HTS caps it and says so. The HTS test that fires a
    bulky statement at the page still passes.)
  • Existing tests pass or moved. crates/ui/src/capability.rs's
    projection tests moved to crates/ui-chrome/src/capability.rs and grew
    card-rendering coverage; what stays in crates/ui is what only HFS can
    assert (the FhirVersionDocsVersion mapping, the core-pack
    catalog's per-release answers, CreateTargets).
    crates/hts-ui/tests/capability.rs keeps its page-level tests and its
    CSS-class guard now scans the shared partials too.

Verification

cargo test -p helios-ui-chrome -p helios-ui -p helios-hts-ui
cargo build --workspace
cargo clippy -p helios-ui-chrome -p helios-ui -p helios-hts-ui --all-targets
cargo check -p helios-hts-ui --no-default-features --features R5

All green. Two flakes surfaced in crates/ui/tests/bulk_export_http.rs
(a_retry_that_loses_its_cas_retries_transient_cleanup_until_404, then
a_poll_version_bump_does_not_discard_a_concurrent_second_start) — different
test each run, both pass on rerun, and neither touches this code.

Not run: the Playwright e2e suite. The specs that pin this page's structure
(design-system.spec.ts asserts section.card > .card__body > .kv-grid >
seven .detail__field; capability-statement.spec.ts asserts the filter's
hidden version input, the resource links and the JSON fragment tree) all
target markup this PR preserves, and the shared crate has unit tests pinning
that shape — but they are worth a run before merge.

https://claude.ai/code/session_01Kos63w6bGcUoLtCxWGDaZY

… and HTS

HFS and HTS each parsed and rendered the same `/metadata` document with
their own code: two `CapabilityView` structs in two crates, two parsers,
two templates. Every improvement had to be made twice and never was —
version-correct specification links (#797) and the interaction colour
coding landed on HFS only, and the HTS page rendered bare `<span
class="tag">` chips and no links at all.

The projection and the four common cards now live once, in
`helios_ui_chrome::capability` (#543's crate, as #808 asked the PR to say):

- `build_view` + the view model + `safe_canonical_href`,
  `system_interaction_href`, `resource_definition_href` and
  `interaction_tag_class`, as pure functions over `serde_json::Value`.
- `templates/partials/capability-{summary,interactions,operations,
  resources}-card.html`, rendered through `CapabilityCards`.

The crate stays a leaf: `serde_json` + `url`, no axum, no HTTP client, no
FHIR schema pack. The two questions it cannot answer are supplied by the
caller — `DocsVersion` (the release to link into, so this crate is not
dragged into the R4/R4B/R5/R6 feature matrix) and `CoreResourceCatalog`
(whether a type has an official page in that release; HFS answers from the
validator's core packs, HTS from the three types a terminology server
serves).

What each page keeps, because the difference is real and not drift:

- Fetching. HFS self-calls over loopback; HTS proxies two upstreams.
- Degradation. HFS still degrades the whole page to one warning; HTS still
  degrades card by card, now by handing the shared cards the
  `hts-degraded-reason-*` sentence as a notice — so per-card degradation
  costs no duplicated card headings.
- The raw fold. HFS's paginated JSON-fragment tree (#798) and HTS's
  byte-capped inline `<pre>` both keep a 400 KB+ statement off the page by
  different means; neither is the other's markup.
- The Terminology capabilities card, which only HTS can have.

Behaviour changes, all on the HTS page:

- Resource types and operation definitions are now links into the release
  the binary was built for; interaction verbs carry the semantic tag
  palette.
- "Base URL" now shows `implementation.url` rather than the statement's own
  `url` canonical, which is what the label promises. HTS emits no
  `implementation.url`, so it renders an em-dash; the canonical is still in
  the raw fold.
- Absent summary fields render an em-dash on both pages.
- `rest[]` is flattened across every server component instead of reading
  `rest[0]` (HFS) — client-mode components are excluded.

Refs #808

Claude-Session: https://claude.ai/code/session_01Kos63w6bGcUoLtCxWGDaZY
@codecov

codecov Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.67705% with 32 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/hts-ui/src/capability.rs 75.23% 26 Missing ⚠️
crates/ui-chrome/src/capability.rs 99.57% 3 Missing ⚠️
crates/ui/src/lib.rs 95.58% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

smunini and others added 5 commits September 1, 2026 18:29
Generalizes HFS's #798 bounded JSON-fragment engine (json_view +
capability_json) from crates/ui into helios-ui-chrome behind a
FragmentEndpoint, so HTS's raw fold now pages through the same
htmx-lazy, syntax-highlighted tree HFS renders instead of a
byte-capped <pre>. HTS gets its own /json-fragment route and ?raw=1
no-JS fallback to match.

Also fixes two review findings on the original unification:
- Terminology Capabilities now wraps its fields in card__body/kv-grid
  like Server Summary, instead of sitting flush against the card edge.
- HTS's page was missing the capability-json.js/json-view.js script
  includes that drive the fold's toggle behavior, so opening it fell
  back to a "Load JSON" link instead of expanding immediately like
  HFS. Added regression tests in tests/chrome_parity.rs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ent' into feat/808-unify-capability-statement

# Conflicts:
#	crates/hts-ui/tests/chrome_parity.rs
crates/ui/templates/** and crates/ui-chrome/templates/** were already
pinned to `text eol=lf` (#671 — Askama output is asserted against LF
string literals in tests) but crates/hts-ui/templates/** was never
covered, so this Windows checkout had every HTS template on disk in
CRLF. It went unnoticed until the newly-merged chevron-left.svg
byte-comparison test exposed it. Add the missing gitattributes rule
and re-checkout the tree so it takes effect locally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…lity-statement

# Conflicts:
#	crates/ui/src/lib.rs
@eterceros
eterceros marked this pull request as ready for review September 2, 2026 01:42
@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@eterceros eterceros assigned smunini and eterceros and unassigned eterceros and smunini Sep 2, 2026
@eterceros
eterceros self-requested a review September 2, 2026 09:03
@smunini
smunini merged commit e788a1c into main Sep 2, 2026
59 of 60 checks passed
@smunini
smunini deleted the feat/808-unify-capability-statement branch September 2, 2026 12:05
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.

Unify the Capability Statement implementation shared by hfs and hts

2 participants