Skip to content

Commit a5a02cb

Browse files
committed
fix: Clear search form when resource type changes
Previously only invalid parameter names were cleared. Now all filter and parameter rows reset to their initial empty state, avoiding confusion from stale search criteria.
1 parent 5c50f69 commit a5a02cb

File tree

8 files changed

+175
-17
lines changed

8 files changed

+175
-17
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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## Context
2+
3+
The `ResourceSearchForm` component maintains local state for the selected
4+
resource type, FHIRPath filter rows, and search parameter rows. When the user
5+
changes the resource type, a `useEffect` hook detects the change and removes any
6+
parameter selections that are no longer valid for the new type. However, it
7+
leaves parameter values and FHIRPath filter expressions intact, which creates a
8+
confusing experience.
9+
10+
## Goals / Non-Goals
11+
12+
**Goals:**
13+
14+
- Reset all filter rows and parameter rows to their initial empty state when the
15+
resource type changes.
16+
17+
**Non-Goals:**
18+
19+
- Persisting search state across resource type changes (e.g. remembering filters
20+
per type).
21+
- Changing the initial default state of the form.
22+
23+
## Decisions
24+
25+
Replace the existing `useEffect` that selectively clears invalid parameters with
26+
a simpler reset that returns filters and parameter rows to their initial state
27+
(one empty row each). This is simpler than the current logic and matches user
28+
expectations — switching resource type is a fresh search context.
29+
30+
The `idCounter` ref should also be reset so that IDs restart cleanly.
31+
32+
## Risks / Trade-offs
33+
34+
- Users who intentionally share filter expressions across resource types will
35+
need to re-enter them. This is an acceptable trade-off given the confusion
36+
caused by stale values.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## Why
2+
3+
When the user changes the resource type on the resources page, the search
4+
parameter rows and FHIRPath filter expressions remain populated with values from
5+
the previous resource type. This is confusing because those values are likely
6+
irrelevant to the new resource type, and the user must manually clear them
7+
before entering new search criteria.
8+
9+
## What Changes
10+
11+
- Reset all search parameter rows (name and value) to a single empty row when
12+
the resource type changes.
13+
- Reset all FHIRPath filter rows to a single empty row when the resource type
14+
changes.
15+
16+
## Capabilities
17+
18+
### New Capabilities
19+
20+
(none)
21+
22+
### Modified Capabilities
23+
24+
- `search-parameter-form`: The form currently only clears invalid parameter
25+
names on resource type change. The new behaviour fully resets all form fields
26+
(parameter rows and filter rows) to their initial empty state.
27+
28+
## Impact
29+
30+
- `ui/src/components/resources/ResourceSearchForm.tsx` - The resource type
31+
change handler needs to reset filters and parameter rows instead of selectively
32+
clearing invalid parameters.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## MODIFIED Requirements
2+
3+
### Requirement: Parameter dropdown populated by resource type
4+
5+
The parameter name dropdown in each search parameter row SHALL display the
6+
search parameters available for the currently selected resource type, as
7+
extracted from the CapabilityStatement. Each option SHALL show the parameter
8+
name, with the parameter type displayed as a badge next to it.
9+
10+
#### Scenario: Parameter list updates on resource type change
11+
12+
- **WHEN** the user changes the selected resource type from Patient to
13+
Observation
14+
- **THEN** the parameter dropdown options SHALL update to show search parameters
15+
declared for Observation, and all search parameter rows SHALL be reset to a
16+
single empty row
17+
18+
#### Scenario: No search parameters available
19+
20+
- **WHEN** the selected resource type has no declared search parameters
21+
- **THEN** the parameter dropdown SHALL be empty and display placeholder text
22+
indicating no parameters are available
23+
24+
#### Scenario: FHIRPath filters reset on resource type change
25+
26+
- **WHEN** the user has entered FHIRPath filter expressions and then changes the
27+
selected resource type
28+
- **THEN** all FHIRPath filter rows SHALL be reset to a single empty row
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## 1. Tests
2+
3+
- [x] 1.1 Write tests verifying that changing the resource type resets search
4+
parameter rows to a single empty row
5+
- [x] 1.2 Write tests verifying that changing the resource type resets FHIRPath
6+
filter rows to a single empty row
7+
8+
## 2. Implementation
9+
10+
- [x] 2.1 Replace the selective parameter-clearing useEffect with a full form
11+
reset (filters and parameter rows) on resource type change
12+
13+
## 3. Verification
14+
15+
- [x] 3.1 Run the full UI test suite and verify all tests pass

openspec/specs/search-parameter-form/spec.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,21 @@ name, with the parameter type displayed as a badge next to it.
6565
- **WHEN** the user changes the selected resource type from Patient to
6666
Observation
6767
- **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
68+
declared for Observation, and all search parameter rows SHALL be reset to a
69+
single empty row
7070

7171
#### Scenario: No search parameters available
7272

7373
- **WHEN** the selected resource type has no declared search parameters
7474
- **THEN** the parameter dropdown SHALL be empty and display placeholder text
7575
indicating no parameters are available
7676

77+
#### Scenario: FHIRPath filters reset on resource type change
78+
79+
- **WHEN** the user has entered FHIRPath filter expressions and then changes the
80+
selected resource type
81+
- **THEN** all FHIRPath filter rows SHALL be reset to a single empty row
82+
7783
### Requirement: Search parameters included in search request
7884

7985
When the user submits the search form, any search parameter rows with both a

ui/src/components/resources/ResourceSearchForm.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,14 @@ export function ResourceSearchForm({
8888
// Available search parameters for the currently selected resource type.
8989
const availableParams = searchParams?.[resourceType] ?? [];
9090

91-
// Track previous resource type to clear invalid selections on change.
91+
// Reset all form fields when the resource type changes, since the previous
92+
// search criteria are unlikely to be relevant to the new type.
9293
const prevResourceType = useRef(resourceType);
9394
if (prevResourceType.current !== resourceType) {
9495
prevResourceType.current = resourceType;
95-
const validNames = new Set(availableParams.map((p) => p.name));
96-
const needsClear = paramRows.some((row) => row.paramName && !validNames.has(row.paramName));
97-
if (needsClear) {
98-
setParamRows(
99-
paramRows.map((row) =>
100-
row.paramName && !validNames.has(row.paramName) ? { ...row, paramName: "" } : row,
101-
),
102-
);
103-
}
96+
idCounter.current = 1;
97+
setFilters([{ id: 0, expression: "" }]);
98+
setParamRows([{ id: 0, paramName: "", value: "" }]);
10499
}
105100

106101
const handleSubmit = () => {

ui/src/components/resources/__tests__/ResourceSearchForm.test.tsx

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ describe("ResourceSearchForm", () => {
674674
expect(screen.queryByRole("option", { name: /gender/i })).not.toBeInTheDocument();
675675
});
676676

677-
it("clears selected parameter when resource type changes and selection is invalid", async () => {
677+
it("resets parameter rows to a single empty row when resource type changes", async () => {
678678
const user = userEvent.setup();
679679
render(
680680
<ResourceSearchForm
@@ -686,19 +686,63 @@ describe("ResourceSearchForm", () => {
686686
/>,
687687
);
688688

689-
// Select "gender" parameter for Patient.
689+
// Select "gender" parameter for Patient and enter a value.
690690
const paramDropdown = screen.getAllByRole("combobox")[1];
691691
await user.click(paramDropdown);
692692
await user.click(screen.getByRole("option", { name: /gender/i }));
693+
const valueInput = screen.getByPlaceholderText(/e\.g\., male/i);
694+
await user.type(valueInput, "male");
693695

694-
// Change resource type to Observation (which doesn't have "gender").
696+
// Add a second parameter row.
697+
await user.click(screen.getByRole("button", { name: /add parameter/i }));
698+
expect(screen.getAllByPlaceholderText(/e\.g\., male/i)).toHaveLength(2);
699+
700+
// Change resource type to Observation.
695701
const resourceTypeCombobox = screen.getAllByRole("combobox")[0];
696702
await user.click(resourceTypeCombobox);
697703
await user.click(screen.getByRole("option", { name: "Observation" }));
698704

699-
// The parameter dropdown should no longer show "gender".
705+
// Should be back to a single empty parameter row.
706+
const valueInputs = screen.getAllByPlaceholderText(/e\.g\., male/i);
707+
expect(valueInputs).toHaveLength(1);
708+
expect(valueInputs[0]).toHaveValue("");
709+
710+
// The parameter dropdown should be cleared (no selection).
700711
const updatedParamDropdown = screen.getAllByRole("combobox")[1];
701-
expect(updatedParamDropdown).not.toHaveTextContent("gender");
712+
expect(updatedParamDropdown).toHaveTextContent("Select parameter...");
713+
});
714+
715+
it("resets FHIRPath filter rows to a single empty row when resource type changes", async () => {
716+
const user = userEvent.setup();
717+
render(
718+
<ResourceSearchForm
719+
onSubmit={mockOnSubmit}
720+
isLoading={false}
721+
disabled={false}
722+
resourceTypes={defaultResourceTypes}
723+
searchParams={mockSearchParams}
724+
/>,
725+
);
726+
727+
// Enter a FHIRPath filter expression.
728+
const filterInput = screen.getByPlaceholderText(/gender = 'female'/i);
729+
await user.type(filterInput, "active = true");
730+
731+
// Add a second filter row and fill it in.
732+
await user.click(screen.getByRole("button", { name: /add filter/i }));
733+
const filterInputs = screen.getAllByPlaceholderText(/gender = 'female'/i);
734+
expect(filterInputs).toHaveLength(2);
735+
await user.type(filterInputs[1], "gender = 'male'");
736+
737+
// Change resource type to Observation.
738+
const resourceTypeCombobox = screen.getAllByRole("combobox")[0];
739+
await user.click(resourceTypeCombobox);
740+
await user.click(screen.getByRole("option", { name: "Observation" }));
741+
742+
// Should be back to a single empty filter row.
743+
const updatedFilterInputs = screen.getAllByPlaceholderText(/gender = 'female'/i);
744+
expect(updatedFilterInputs).toHaveLength(1);
745+
expect(updatedFilterInputs[0]).toHaveValue("");
702746
});
703747

704748
it("displays help text for search parameters section", () => {

0 commit comments

Comments
 (0)