Skip to content

Search and filter tasks through url search params - #37

Merged
Alejandroq12 merged 2 commits into
devfrom
feature/search-filter
Aug 7, 2026
Merged

Search and filter tasks through url search params#37
Alejandroq12 merged 2 commits into
devfrom
feature/search-filter

Conversation

@Alejandroq12

@Alejandroq12 Alejandroq12 commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added task filtering by status, estimate, tags, due date, owner, and search text.
    • Filters and search are saved in the URL for shareable, persistent views.
    • Added responsive filter controls, owner selection, date pickers, and active-filter clearing.
    • Added clearer empty states when filters return no tasks.
  • Bug Fixes

    • Search input now stays synchronized with URL parameters and updates smoothly.
  • Documentation

    • Updated documentation to describe search and filtering behavior.

  The header search debounces into ?q= and five filter chips (status,
  estimate, tags, due date, owner) write their own params, so filtered
  views are shareable, survive reloads, and never remount the page —
  search params sit outside the pathname the error boundary keys on.
  filterInputFromParams is the one validated boundary from URL strings to
  the typed FilterTaskInput; unknown values are dropped. Filters combine
  freely and an empty-results component with a clear-filters path renders
  when nothing matches. MenuPanel graduates from TaskForm to a shared
  component so the filter chips reuse the app's menu anatomy. Probing the
  component so the filter chips reuse the app's menu anatomy. Probing the
  live API first shaped the implementation and the README notes: name
  matching is a case-sensitive substring, dueDate matches by exact
  timestamp (satisfied by this app's noon-UTC convention), and ownerId is
  accepted but ignored server-side — sent as required, documented as
  observed.
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
task-flow Ready Ready Preview Aug 7, 2026 10:36pm

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9dd2632f-ab4f-4902-ae77-5d62aece0f0d

📥 Commits

Reviewing files that changed from the base of the PR and between 4c623cc and 8387c09.

⛔ Files ignored due to path filters (2)
  • src/graphql/generated/gql.ts is excluded by !**/generated/**
  • src/graphql/generated/graphql.ts is excluded by !**/generated/**
📒 Files selected for processing (7)
  • README.md
  • src/components/layout/Header.tsx
  • src/features/tasks/FilterBar.tsx
  • src/features/tasks/TasksView.tsx
  • src/features/tasks/filter-params.ts
  • src/features/tasks/queries.ts
  • src/test/fixtures.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/features/tasks/filter-params.ts
  • src/features/tasks/FilterBar.tsx
  • README.md
  • src/components/layout/Header.tsx

📝 Walkthrough

Walkthrough

The pull request adds URL-backed search and filtering for task pages. It adds filter controls, validates filter parameters, updates task views and empty states, loads owner options, and updates router tests, fixtures, and documentation.

Changes

Task filtering

Layer / File(s) Summary
URL filter state
src/features/tasks/filter-params.ts, src/components/layout/Header.tsx
Search and filter parameters are parsed, validated, normalized, and synchronized with the URL.
Filter controls
src/features/tasks/FilterBar.tsx, src/features/tasks/MenuPanel.tsx, src/features/tasks/TaskForm.tsx
FilterBar provides status, estimate, tag, due date, and owner controls. MenuPanel is shared with TaskForm.
Task page integration
src/features/tasks/Dashboard.tsx, src/features/tasks/MyTask.tsx, src/features/tasks/TasksView.tsx, src/features/tasks/queries.ts
Task pages pass URL-derived filters to TasksView, which filters owner results and renders filtered or unfiltered empty states.
Validation and documentation
src/app/router.test.tsx, src/test/fixtures.ts, README.md
Router mocks and user fixtures support profile, user, and task responses. The README documents URL-backed filtering behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Header
  participant FilterBar
  participant URL
  participant Dashboard
  participant TasksView
  User->>Header: Enter search text
  Header->>URL: Replace q after debounce
  User->>FilterBar: Select task filters
  FilterBar->>URL: Replace filter parameters
  URL->>Dashboard: Provide search parameters
  Dashboard->>TasksView: Pass filter input and active state
  TasksView-->>Dashboard: Render filtered or empty task state
Loading

Possibly related PRs

Suggested labels: ui

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding search and filter support through URL search parameters.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/search-filter

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/features/tasks/FilterBar.tsx (2)

249-249: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Both branches of the ternary return the same string.

owner !== null ? 'Owner' : 'Owner' always evaluates to 'Owner'. Remove the condition.

♻️ Proposed refactor
-          {ownerName ?? (owner !== null ? 'Owner' : 'Owner')}
+          {ownerName ?? 'Owner'}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/tasks/FilterBar.tsx` at line 249, In the FilterBar owner label
expression, remove the redundant owner !== null ternary and use the constant
'Owner' fallback directly after ownerName.

110-122: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

aria-haspopup="listbox" does not match the rendered markup.

MenuPanel renders a div that contains button elements. No element has role="listbox" or role="option". A screen reader announces a listbox and then finds none. The same mismatch repeats on the estimate, tags, and owner triggers.

Use aria-haspopup="menu" and give the panel role="menu" with role="menuitem" children, or role="menuitemcheckbox" for the tag toggles.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/tasks/FilterBar.tsx` around lines 110 - 122, Update the status,
estimate, tags, and owner filter triggers from aria-haspopup="listbox" to
aria-haspopup="menu", and update MenuPanel plus its button children to use
role="menu" and role="menuitem"; use role="menuitemcheckbox" for tag toggle
items while preserving their existing behavior.
src/features/tasks/filter-params.ts (1)

19-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer a type guard over the as TaskTag[] cast.

FilterBar.tsx lines 57-59 already uses a predicate for the same parsing. A shared guard removes the cast and keeps both call sites consistent.

♻️ Proposed refactor
   const tags = params
     .get('tags')
     ?.split(',')
-    .filter((tag) => TAGS.has(tag)) as TaskTag[] | undefined
+    .filter((tag): tag is TaskTag => TAGS.has(tag))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/tasks/filter-params.ts` around lines 19 - 23, Update the tags
parsing in filter-params.ts to replace the as TaskTag[] cast with a type-guard
predicate, matching the existing FilterBar.tsx approach. Prefer reusing a shared
guard if one exists, and preserve the current filtering and input.tags
assignment behavior.
src/app/router.test.tsx (1)

24-28: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Make both router mocks enforce the GraphQL request contract.

Handle TasksDocument explicitly, assert URL-derived variables in a filter test, and throw for unknown documents in both callbacks. The current fallback returns a task payload for any document and ignores variables.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/router.test.tsx` around lines 24 - 28, Update both router request
mock callbacks to handle TasksDocument explicitly, validate the URL-derived
variables in the filter test, and throw for any unrecognized document instead of
returning a task payload. Preserve the existing profile and users responses
while enforcing the GraphQL request contract in each mock.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 116: Resolve the owner-filter behavior described by filterInputFromParams
and TasksView: either locally filter the fetched tasks by ownerId before
rendering, or remove/disable the owner filter and update its documented support
state so it is not presented as functional. Ensure selecting an owner no longer
leaves the task list unchanged while the server ignores ownerId.

In `@src/components/layout/Header.tsx`:
- Around line 13-32: Update the Header search state synchronization around
useSearchParams so external changes to the URL’s q parameter update the local
query value, including removals and browser back/forward navigation. Preserve
the existing debounced setSearchParams behavior for user input while preventing
the synchronization effect from rewriting externally applied values.

In `@src/features/tasks/filter-params.ts`:
- Around line 24-25: Create and export a shared parseDueParam helper in
filter-params.ts that validates both DAY_PATTERN and the calendar round-trip,
then use its result when assigning input.dueDate. In
src/features/tasks/filter-params.ts lines 24-25, replace direct validation with
the helper; in src/features/tasks/FilterBar.tsx lines 23-27, import and apply
the same helper to the due value read at line 60, treating invalid values as no
active due filter for both the chip label and active state.

---

Nitpick comments:
In `@src/app/router.test.tsx`:
- Around line 24-28: Update both router request mock callbacks to handle
TasksDocument explicitly, validate the URL-derived variables in the filter test,
and throw for any unrecognized document instead of returning a task payload.
Preserve the existing profile and users responses while enforcing the GraphQL
request contract in each mock.

In `@src/features/tasks/filter-params.ts`:
- Around line 19-23: Update the tags parsing in filter-params.ts to replace the
as TaskTag[] cast with a type-guard predicate, matching the existing
FilterBar.tsx approach. Prefer reusing a shared guard if one exists, and
preserve the current filtering and input.tags assignment behavior.

In `@src/features/tasks/FilterBar.tsx`:
- Line 249: In the FilterBar owner label expression, remove the redundant owner
!== null ternary and use the constant 'Owner' fallback directly after ownerName.
- Around line 110-122: Update the status, estimate, tags, and owner filter
triggers from aria-haspopup="listbox" to aria-haspopup="menu", and update
MenuPanel plus its button children to use role="menu" and role="menuitem"; use
role="menuitemcheckbox" for tag toggle items while preserving their existing
behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a8f4e1ce-6f5a-4612-a07b-98892f821b8b

📥 Commits

Reviewing files that changed from the base of the PR and between 97b32b2 and 4c623cc.

📒 Files selected for processing (11)
  • README.md
  • src/app/router.test.tsx
  • src/components/layout/Header.tsx
  • src/features/tasks/Dashboard.tsx
  • src/features/tasks/FilterBar.tsx
  • src/features/tasks/MenuPanel.tsx
  • src/features/tasks/MyTask.tsx
  • src/features/tasks/TaskForm.tsx
  • src/features/tasks/TasksView.tsx
  • src/features/tasks/filter-params.ts
  • src/test/fixtures.ts

Comment thread README.md
Comment thread src/components/layout/Header.tsx Outdated
Comment thread src/features/tasks/filter-params.ts Outdated
  The server ignores ownerId, so the owner chip changed nothing — a
  placebo control. The tasks query now selects creator id and TasksView
  filters locally when an owner is set, while the param is still sent as
  the requirement demands. The header search gains a last-pushed ref so
  external URL changes (clear filters, back/forward) sync into the input
  instead of being re-pushed by the stale debounce. parseDueParam becomes
  the single validated accessor for the due param, checking shape and
  calendar round-trip so junk or rollover dates mean no filter rather
  than an Invalid Date chip. Removes the stale unchecked search-and-filter
  checklist line.
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code review

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

@Alejandroq12
Alejandroq12 merged commit db3f096 into dev Aug 7, 2026
9 checks passed
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.

1 participant