Skip to content

Commit c393488

Browse files
committed
feat: Add standard FHIR search parameters to admin UI
Add a search parameters section to the resource search form that allows users to select from the server's declared search parameters for the chosen resource type and provide values. Parameters are extracted from the CapabilityStatement and sent as standard FHIR query parameters alongside any FHIRPath filters.
1 parent a0e42db commit c393488

File tree

16 files changed

+1305
-9
lines changed

16 files changed

+1305
-9
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-02-16
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
## Context
2+
3+
The Pathling admin UI provides a resource search page that currently only
4+
supports FHIRPath filter expressions. The server already fully implements
5+
standard FHIR search parameters (token, string, date, number, quantity,
6+
reference, URI), declares them in the CapabilityStatement, and supports
7+
combining them with FHIRPath filters via AND logic.
8+
9+
The existing UI architecture uses:
10+
11+
- **Radix UI Themes** for all components (Select, TextField, Button, Card,
12+
etc.)
13+
- **TanStack Query** for server state management
14+
- **React Router** for navigation
15+
- A `useServerCapabilities` hook that fetches and parses the
16+
CapabilityStatement, but currently discards search parameter information
17+
18+
## Goals / Non-goals
19+
20+
**Goals:**
21+
22+
- Allow users to search using standard FHIR search parameters through the UI.
23+
- Dynamically populate available search parameters from the server's
24+
CapabilityStatement for the selected resource type.
25+
- Allow combining standard search parameters with FHIRPath filters.
26+
- Display the search parameter type alongside each parameter name for user
27+
guidance.
28+
29+
**Non-goals:**
30+
31+
- Type-specific input widgets (e.g., date pickers for date parameters, coding
32+
system/code split inputs for token parameters). All values will be entered as
33+
free text matching FHIR search value syntax.
34+
- Search parameter modifier support (`:exact`, `:not`, etc.) in the UI.
35+
- OR logic within a single parameter (comma-separated values) — users can type
36+
commas manually but there is no dedicated UI for it.
37+
- Pagination controls — the existing `_count=10` default remains.
38+
39+
## Decisions
40+
41+
### Extract search parameters from CapabilityStatement
42+
43+
The `parseCapabilities` function in `useServerCapabilities.ts` already iterates
44+
over `rest[].resource[]` but currently skips the `searchParam` array. We will
45+
extend `ResourceCapability` to include search parameters and extract them during
46+
parsing.
47+
48+
**Alternative considered**: Fetching search parameters via a separate API call
49+
(e.g., `SearchParameter` resources). Rejected because the CapabilityStatement
50+
already contains everything we need and is already fetched on app load.
51+
52+
### Search parameter form as a section within the existing form
53+
54+
The search parameter inputs will be added as a new section within
55+
`ResourceSearchForm`, positioned between the resource type selector and the
56+
FHIRPath filters section. This keeps both search mechanisms visible and
57+
accessible.
58+
59+
**Alternative considered**: A tabbed interface switching between "Standard
60+
search" and "FHIRPath search" modes. Rejected because the server supports using
61+
both simultaneously, and hiding one behind a tab would obscure this capability.
62+
63+
### Free text input for all parameter types
64+
65+
All search parameter values will use a single `TextField` input regardless of
66+
parameter type (token, date, string, etc.). The parameter type will be displayed
67+
as a badge next to the parameter name for guidance.
68+
69+
**Alternative considered**: Type-specific input widgets (date picker, system/code
70+
split fields, numeric inputs). Rejected as over-engineering for the initial
71+
implementation — users familiar with FHIR search syntax can type the correct
72+
value format directly.
73+
74+
### Parameters sent as standard query parameters
75+
76+
When standard search parameters are provided, they are sent as regular URL query
77+
parameters on the resource type endpoint (e.g.,
78+
`GET /Patient?gender=male&birthdate=gt2000`). If FHIRPath filters are also
79+
provided, the request uses the `_query=fhirPath` named query with both filter
80+
parameters and standard parameters.
81+
82+
The existing `search()` function in `rest.ts` already accepts a generic `params`
83+
record. No changes to the REST client are needed.
84+
85+
### Dynamic parameter list filtered by resource type
86+
87+
When the user changes the selected resource type, the available search
88+
parameters update automatically from the CapabilityStatement data. The parameter
89+
select dropdown only shows parameters for the currently selected resource type.
90+
91+
## Risks / Trade-offs
92+
93+
- **User confusion between search modes**: Users might not understand when to
94+
use standard parameters versus FHIRPath filters. → Mitigation: Clear section
95+
headings and help text explaining the difference.
96+
- **Large parameter lists**: Some resource types have many search parameters
97+
(e.g., Patient has ~30). → Mitigation: Use a Select dropdown for parameter
98+
selection rather than displaying all at once.
99+
- **Value format errors**: Users may enter values in incorrect FHIR search
100+
format. → Mitigation: The server returns descriptive 400 errors which are
101+
already displayed in the UI.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
## Why
2+
3+
The Pathling server already supports standard FHIR search parameters (token,
4+
string, date, number, quantity, reference, URI) alongside FHIRPath filters, but
5+
the admin UI only exposes FHIRPath filter inputs. Users who are familiar with
6+
standard FHIR search syntax have no way to use it through the UI, forcing them
7+
to learn FHIRPath or use external tools.
8+
9+
## What changes
10+
11+
- Add a search parameter input section to the resource search form, allowing
12+
users to select from the server's declared search parameters for the chosen
13+
resource type and provide values.
14+
- Fetch available search parameters from the server's CapabilityStatement
15+
metadata endpoint, filtered by the selected resource type.
16+
- Send standard search parameters as query parameters alongside any FHIRPath
17+
filters (combined with AND logic, matching the server's existing behaviour).
18+
- Update the search form layout to clearly separate standard search parameters
19+
from FHIRPath filters, so users can use either or both.
20+
21+
## Capabilities
22+
23+
### New capabilities
24+
25+
- `search-parameter-form`: UI form controls for selecting and entering values
26+
for standard FHIR search parameters, fetched dynamically from the server's
27+
CapabilityStatement.
28+
29+
### Modified capabilities
30+
31+
_(none)_
32+
33+
## Impact
34+
35+
- **UI components**: `ResourceSearchForm` will be extended with new controls;
36+
new sub-components will be created for search parameter input rows.
37+
- **API layer**: The existing `search()` function in `rest.ts` already supports
38+
generic `params` — no changes needed to the REST client.
39+
- **Types**: `SearchRequest` will be extended to carry standard search
40+
parameters alongside FHIRPath filters.
41+
- **Server capabilities hook**: The existing `useServerCapabilities` hook
42+
already fetches the CapabilityStatement; search parameter data will need to be
43+
extracted from it.
44+
- **Server**: No server changes required — standard search parameters are
45+
already fully implemented and declared in the CapabilityStatement.
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
## ADDED Requirements
2+
3+
### Requirement: Search parameters extracted from CapabilityStatement
4+
5+
The `parseCapabilities` function SHALL extract search parameter definitions from
6+
each resource's `searchParam` array in the CapabilityStatement. Each search
7+
parameter SHALL include its name and type. The `ResourceCapability` interface
8+
SHALL be extended to include a `searchParams` field containing an array of
9+
`{ name: string; type: string }` objects.
10+
11+
#### Scenario: CapabilityStatement contains search parameters for Patient
12+
13+
- **WHEN** the CapabilityStatement declares search parameters `gender` (token),
14+
`birthdate` (date), and `name` (string) for the Patient resource
15+
- **THEN** the parsed `ResourceCapability` for Patient SHALL include a
16+
`searchParams` array containing entries for `gender` with type `token`,
17+
`birthdate` with type `date`, and `name` with type `string`
18+
19+
#### Scenario: CapabilityStatement has resource with no search parameters
20+
21+
- **WHEN** the CapabilityStatement declares a resource type with no
22+
`searchParam` entries
23+
- **THEN** the parsed `ResourceCapability` for that resource SHALL have an
24+
empty `searchParams` array
25+
26+
### Requirement: Search parameter section in search form
27+
28+
The resource search form SHALL include a "Search parameters" section positioned
29+
between the resource type selector and the FHIRPath filters section. This
30+
section SHALL allow users to add rows, where each row consists of a parameter
31+
name dropdown and a value text input.
32+
33+
#### Scenario: Initial form state
34+
35+
- **WHEN** the search form is first rendered
36+
- **THEN** the search parameters section SHALL be displayed with a heading, an
37+
"Add parameter" button, and one empty parameter row
38+
39+
#### Scenario: User adds a search parameter row
40+
41+
- **WHEN** the user clicks the "Add parameter" button
42+
- **THEN** a new parameter row SHALL be appended with an empty parameter
43+
dropdown and an empty value input
44+
45+
#### Scenario: User removes a search parameter row
46+
47+
- **WHEN** the user clicks the remove button on a parameter row and there is
48+
more than one row
49+
- **THEN** that row SHALL be removed from the form
50+
51+
#### Scenario: Last parameter row cannot be removed
52+
53+
- **WHEN** there is only one parameter row
54+
- **THEN** the remove button on that row SHALL be disabled
55+
56+
### Requirement: Parameter dropdown populated by resource type
57+
58+
The parameter name dropdown in each search parameter row SHALL display the
59+
search parameters available for the currently selected resource type, as
60+
extracted from the CapabilityStatement. Each option SHALL show the parameter
61+
name, with the parameter type displayed as a badge next to it.
62+
63+
#### Scenario: Parameter list updates on resource type change
64+
65+
- **WHEN** the user changes the selected resource type from Patient to
66+
Observation
67+
- **THEN** the parameter dropdown options SHALL update to show search parameters
68+
declared for Observation, and any previously selected parameters that are not
69+
valid for Observation SHALL be cleared
70+
71+
#### Scenario: No search parameters available
72+
73+
- **WHEN** the selected resource type has no declared search parameters
74+
- **THEN** the parameter dropdown SHALL be empty and display placeholder text
75+
indicating no parameters are available
76+
77+
### Requirement: Search parameters included in search request
78+
79+
When the user submits the search form, any search parameter rows with both a
80+
selected parameter name and a non-empty value SHALL be included in the search
81+
request as standard FHIR query parameters alongside any FHIRPath filters.
82+
83+
#### Scenario: Search with standard parameters only
84+
85+
- **WHEN** the user selects resource type "Patient", adds parameter "gender"
86+
with value "male", leaves the FHIRPath filter empty, and submits the search
87+
- **THEN** the search request SHALL be sent as
88+
`GET [base]/Patient?gender=male&_count=10`
89+
90+
#### Scenario: Search combining standard parameters and FHIRPath filters
91+
92+
- **WHEN** the user selects resource type "Patient", adds parameter "gender"
93+
with value "male", adds FHIRPath filter `active = true`, and submits the
94+
search
95+
- **THEN** the search request SHALL be sent as
96+
`GET [base]/Patient?_query=fhirPath&filter=active = true&gender=male&_count=10`
97+
98+
#### Scenario: Empty parameter rows are excluded
99+
100+
- **WHEN** the user has a parameter row with no parameter selected or no value
101+
entered, and submits the search
102+
- **THEN** that row SHALL be excluded from the search request
103+
104+
#### Scenario: Multiple values for the same parameter
105+
106+
- **WHEN** the user adds two rows for the same parameter name with different
107+
values
108+
- **THEN** both values SHALL be sent as repeated query parameters (AND logic),
109+
e.g., `date=gt2020-01-01&date=lt2025-01-01`
110+
111+
### Requirement: SearchRequest type extended for standard parameters
112+
113+
The `SearchRequest` interface SHALL be extended to include a `params` field of
114+
type `Record<string, string[]>` to carry standard search parameter name-value
115+
pairs alongside the existing `filters` array.
116+
117+
#### Scenario: SearchRequest with both filters and params
118+
119+
- **WHEN** a search is submitted with FHIRPath filter `active = true` and
120+
search parameter `gender=male`
121+
- **THEN** the `SearchRequest` object SHALL contain
122+
`filters: ["active = true"]` and `params: { gender: ["male"] }`
123+
124+
### Requirement: Help text for search parameters section
125+
126+
The search parameters section SHALL include help text explaining that search
127+
parameters use standard FHIR search syntax and are combined with AND logic.
128+
129+
#### Scenario: Help text is displayed
130+
131+
- **WHEN** the search form is rendered
132+
- **THEN** the search parameters section SHALL display help text below the
133+
parameter rows explaining the AND combination logic and that values use
134+
standard FHIR search syntax
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## 1. Data layer
2+
3+
- [x] 1.1 Extend `ResourceCapability` to include `searchParams: { name: string; type: string }[]` and update `parseCapabilities` to extract search parameters from the CapabilityStatement
4+
- [x] 1.2 Write unit tests for `parseCapabilities` covering resources with search parameters, resources with no search parameters, and missing fields
5+
- [x] 1.3 Extend `SearchRequest` interface to include `params: Record<string, string[]>` for standard search parameters
6+
7+
## 2. Search form UI
8+
9+
- [x] 2.1 Write unit tests for the search parameter row behaviour: adding/removing rows, parameter dropdown population on resource type change, clearing invalid selections on type change, disabled remove button for single row
10+
- [x] 2.2 Add a search parameters section to `ResourceSearchForm` with parameter name dropdown, value text input, add/remove buttons, type badge, and help text
11+
- [x] 2.3 Pass `searchParams` from `ResourceCapability` through the component hierarchy to the search form (from `Resources` page → `ResourceSearchForm`)
12+
13+
## 3. Search execution
14+
15+
- [x] 3.1 Write unit tests for search submission: params included in request, empty rows excluded, multiple values for same parameter sent as repeated params, combination with FHIRPath filters
16+
- [x] 3.2 Update `handleSubmit` in `ResourceSearchForm` to populate `params` on the `SearchRequest` from search parameter rows
17+
- [x] 3.3 Update `useFhirPathSearch` hook to pass `params` through to the `search()` REST function
18+
19+
## 4. End-to-end testing
20+
21+
- [x] 4.1 Add Playwright test for searching with standard search parameters
22+
- [x] 4.2 Add Playwright test for combining standard parameters with FHIRPath filters

0 commit comments

Comments
 (0)