Skip to content

feat(CodeLookup): coding-system filter — ICD-10/SNOMED mode, ICD-11-ready#336

Open
horner wants to merge 3 commits into
mainfrom
codelookup-codetype-filter
Open

feat(CodeLookup): coding-system filter — ICD-10/SNOMED mode, ICD-11-ready#336
horner wants to merge 3 commits into
mainfrom
codelookup-codetype-filter

Conversation

@horner

@horner horner commented Jul 24, 2026

Copy link
Copy Markdown
Member

Adds a coding-system mode to CodeLookup — the programmer can fix it, or let the user decide. Groundwork for #335 (ICD-11): once the shards carry ICD11 rows, the mode is just codetypes: ['ICD11'].

What

  • Engine (engine.ts): SearchOptions.codetypes — query-time filter applied to both label matches and code-prefix matches; shards containing none of the requested systems are skipped entirely.
  • Worker (codify.worker.ts): passes codetypes through.
  • Component (CodeLookup.tsx):
    • searchCodetypes?: string[] — programmer-fixed system (e.g. ['ICD10']); also applies to the → drill-down.
    • codetypeOptions?: CodetypeOption[] — user-facing segmented control (accessible radiogroup) above the search box; the user's pick overrides searchCodetypes.
  • Stories: Conditions Only gets an All | ICD-10 | SNOMED toggle; new Conditions ICD-10 Only story shows the fixed prop.
  • Tests: engine coverage for label/code filtering and the no-matching-system case (27 pass).

Why no ICD-11 option yet

The source dataset (rxdb_utf8.MedicalCodify_search) has no ICD-11 rows — ingesting the WHO ICD-11 MMS linearization is tracked in #335. This PR makes the UI/engine side a one-line change when that lands.

Testing

  • pnpm vitest run src/components/CodeLookup/engine.test.ts — 27/27
  • pnpm typecheck, pnpm lint, pnpm format:fix — clean
  • Verified live in Storybook: "heart failure" → 14 ICD-10-only vs 7 SNOMED-only results; drill-down respects the filter.

Copilot AI review requested due to automatic review settings July 24, 2026 03:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a coding-system (“codetype”) filter to CodeLookup at both the engine and UI levels, enabling ICD-10-only / SNOMED-only (and future ICD-11) modes while keeping drill-down results consistent with the active filter.

Changes:

  • Engine: adds SearchOptions.codetypes and applies it to both label and code-prefix matching, skipping shards with no matching codetypes.
  • Worker + component: plumbs codetypes through the worker and exposes searchCodetypes (fixed) + codetypeOptions (user toggle) in CodeLookup.
  • Stories/tests: updates Storybook stories for conditions and adds engine tests covering codetype filtering and “no matching systems” behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/components/CodeLookup/index.ts Re-exports CodetypeOption from CodeLookup.
src/components/CodeLookup/engine.ts Implements query-time codetype filtering for both label search and code-prefix search; skips non-matching shards.
src/components/CodeLookup/engine.test.ts Adds coverage for codetype filtering across label and code searches, including the “no matching systems” case.
src/components/CodeLookup/codify.worker.ts Passes codetypes through from worker messages into engine search options.
src/components/CodeLookup/CodeLookup.tsx Adds searchCodetypes + codetypeOptions props, renders a segmented-control-style toggle, and applies the active filter to search and drill-down.
src/components/CodeLookup/CodeLookup.stories.tsx Updates Conditions story to include All/ICD-10/SNOMED toggle and adds a fixed ICD-10-only story.
Comments suppressed due to low confidence (2)

src/components/CodeLookup/CodeLookup.tsx:512

  • Using opt.label as the React key can cause duplicate keys if consumers provide repeated labels (or if labels change), which can lead to incorrect button state reuse. Prefer a key that’s guaranteed unique/stable for the option (e.g., label + codetypes, plus index as a tie-breaker).
          <button
            key={opt.label}
            type="button"

src/components/CodeLookup/CodeLookup.tsx:536

  • There’s an extra JSX whitespace node ({' '}) inside the search box container. It’s unnecessary and can introduce subtle layout/spacing differences; it should be removed.
      <div className="relative" ref={anchorRef}>
        {' '}
        <SearchIcon

Comment thread src/components/CodeLookup/CodeLookup.tsx
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 24, 2026

Copy link
Copy Markdown

Deploying ui with  Cloudflare Pages  Cloudflare Pages

Latest commit: 304aed7
Status: ✅  Deploy successful!
Preview URL: https://9fd3707b.ui-6d0.pages.dev
Branch Preview URL: https://codelookup-codetype-filter.ui-6d0.pages.dev

View logs

horner added a commit that referenced this pull request Jul 24, 2026
…d pill

- empty codetypeOptions no longer overrides searchCodetypes (was truthy [])
- clamp active index so a shrunk options list can't lose its selection
- selected pill uses bg-primary-800 (was 600) to pass WCAG AA contrast

Addresses PR #336 review (Copilot) and test:storybook a11y failure.
Copilot AI review requested due to automatic review settings July 24, 2026 05:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/components/CodeLookup/CodeLookup.tsx Outdated
Comment thread src/components/CodeLookup/CodeLookup.tsx Outdated
horner added a commit that referenced this pull request Jul 24, 2026
- arrow/Home/End keys move selection with roving tabIndex (only the checked
  radio is tabbable), matching the ARIA radiogroup pattern
- key by index instead of consumer-provided label (may be non-unique/locale-
  dependent)

Addresses PR #336 review (Copilot).
Copilot AI review requested due to automatic review settings July 24, 2026 06:06
horner added a commit that referenced this pull request Jul 24, 2026
…d pill

- empty codetypeOptions no longer overrides searchCodetypes (was truthy [])
- clamp active index so a shrunk options list can't lose its selection
- selected pill uses bg-primary-800 (was 600) to pass WCAG AA contrast

Addresses PR #336 review (Copilot) and test:storybook a11y failure.
horner added a commit that referenced this pull request Jul 24, 2026
- arrow/Home/End keys move selection with roving tabIndex (only the checked
  radio is tabbable), matching the ARIA radiogroup pattern
- key by index instead of consumer-provided label (may be non-unique/locale-
  dependent)

Addresses PR #336 review (Copilot).
@horner
horner force-pushed the codelookup-codetype-filter branch from 1ec7175 to 1cc31fb Compare July 24, 2026 06:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/components/CodeLookup/CodeLookup.tsx:268

  • activeCodetypes can legitimately be an empty array (e.g. searchCodetypes={[]} or an option with codetypes: []). Because [] is truthy, codetypesKey becomes '', keyToDomains('') yields [], and the engine treats that as a real filter that matches no codetypes (empty allowed set), returning no results and also breaking drill-down (codetypesRef.current becomes []). Normalize empty arrays to undefined so they behave like “no filter / all systems”.
    const activeCodetypes = hasCodetypeOptions
      ? codetypeOptions![activeCodetypeIdx]?.codetypes
      : searchCodetypes;
    const codetypesKey = activeCodetypes ? activeCodetypes.join(',') : null;
    /** active codetypes for the stable openDrill callback */

s: CodifyShard,
opts?: SearchOptions
): Set<number> | null {
if (!opts?.codetypes) return null;
Copilot AI review requested due to automatic review settings July 24, 2026 06:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/components/CodeLookup/engine.ts:463

  • SearchOptions.codetypes treats an empty array as a hard filter to “no codetypes” (allowed set becomes empty, and the shard gets skipped). That makes codetypes: [] behave very differently from boostCodetypes: [] (which is effectively a no-op) and is easy to hit accidentally via array-to-key encoding. Consider treating an empty codetypes list as “no filter” (same as undefined) to avoid surprising “no results” behavior.
/** Shard-local codetype indices allowed by opts.codetypes (null = no filter;
 * an empty set means the shard has none of the requested systems). */
function allowedCodetypes(
  s: CodifyShard,
  opts?: SearchOptions
): Set<number> | null {
  if (!opts?.codetypes) return null;
  return new Set(
    opts.codetypes.map((ct) => s.codetypes.indexOf(ct)).filter((i) => i >= 0)
  );

Comment on lines +264 to +268
const activeCodetypes = hasCodetypeOptions
? codetypeOptions![activeCodetypeIdx]?.codetypes
: searchCodetypes;
const codetypesKey = activeCodetypes ? activeCodetypes.join(',') : null;
/** active codetypes for the stable openDrill callback */
horner added 3 commits July 24, 2026 02:28
…eady (#335)

- engine SearchOptions.codetypes filters label + code matches at query time
- searchCodetypes prop: programmer-fixed system; applies to drill-down too
- codetypeOptions prop: user-facing segmented control (radiogroup)
- ConditionsOnly story: All | ICD-10 | SNOMED toggle; new ICD-10-only story
…d pill

- empty codetypeOptions no longer overrides searchCodetypes (was truthy [])
- clamp active index so a shrunk options list can't lose its selection
- selected pill uses bg-primary-800 (was 600) to pass WCAG AA contrast

Addresses PR #336 review (Copilot) and test:storybook a11y failure.
- arrow/Home/End keys move selection with roving tabIndex (only the checked
  radio is tabbable), matching the ARIA radiogroup pattern
- key by index instead of consumer-provided label (may be non-unique/locale-
  dependent)

Addresses PR #336 review (Copilot).
Copilot AI review requested due to automatic review settings July 24, 2026 06:28
@horner
horner force-pushed the codelookup-codetype-filter branch from 1cc31fb to 304aed7 Compare July 24, 2026 06:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment on lines +563 to +567
'rounded-full border px-2.5 py-0.5 text-xs transition-colors',
'focus:ring-ring focus:ring-2 focus:outline-none',
i === activeCodetypeIdx
? 'border-primary-800 bg-primary-800 dark:border-primary-400 dark:bg-primary-400 dark:text-primary-950 text-white'
: 'border-border text-muted-foreground hover:text-foreground'
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.

2 participants