Skip to content

fix: use parseAsSafeArrayOf for dashboard page array query params - #4801

Merged
akshaydeo merged 3 commits into
devfrom
fix/handle-special-characters-in-dashboard-filters
Jul 1, 2026
Merged

fix: use parseAsSafeArrayOf for dashboard page array query params#4801
akshaydeo merged 3 commits into
devfrom
fix/handle-special-characters-in-dashboard-filters

Conversation

@impoiler

Copy link
Copy Markdown
Contributor

Summary

Dashboard filter query parameters were being stored as comma-separated strings in the URL, requiring manual parsing and serialization on every read and write. This replaces that approach with a proper array-aware query parameter parser (parseAsSafeArrayOf) and uses parseAsBoolean for the missing_cost_only flag, so filter values are stored and consumed as native arrays and booleans directly from URL state.

Changes

  • Replaced parseAsString with parseAsSafeArrayOf for all array-typed filter parameters (providers, models, virtual_key_ids, selected_key_ids, objects, status, routing_rule_ids, routing_engine_used, stop_reasons, user_ids, team_ids, customer_ids, business_unit_ids, aliases)
  • Replaced parseAsString with parseAsBoolean for missing_cost_only, removing the need to compare against the string "true"
  • Removed the local parseCsvParam helper and all intermediate useMemo variables that existed solely to parse CSV strings into arrays — urlState values are now used directly
  • Removed .join(",") serialization calls in setFilters; arrays are passed directly to setUrlState
  • MCP tool name and server label fields (mcp_tool_names, mcp_server_labels) remain as strings for now, with their own minimal memo wrappers retained
  • Removed a stale urlState.period reference from the setFilters dependency array

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

Apply filters on the dashboard (providers, models, virtual keys, statuses, etc.) and verify:

  1. URL query parameters reflect the selected values correctly
  2. Refreshing the page restores all filters as expected
  3. The missing_cost_only toggle persists as true/false in the URL rather than a string
  4. Clearing filters resets URL params to their defaults
cd ui
pnpm i || npm i
pnpm build || npm run build

Screenshots/Recordings

N/A — behavior is unchanged from the user's perspective; this is an internal state management refactor.

Breaking changes

  • Yes
  • No

Related issues

N/A

Security considerations

None. This change only affects how filter values are serialized into and parsed from the URL query string.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 43 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fbd283a8-a8ee-44f1-821f-808b30660c2b

📥 Commits

Reviewing files that changed from the base of the PR and between 17dcf7e and a089f20.

📒 Files selected for processing (1)
  • ui/app/workspace/dashboard/page.tsx
📝 Walkthrough

Walkthrough

DashboardPage migrates multi-value dashboard filter URL parameters from CSV parsing to parseAsSafeArrayOf arrays. missing_cost_only becomes boolean-backed, derived CSV selections are removed, and filters, mcpFilters, and setFilters now operate on array URL state.

Changes

Dashboard filter URL state refactor

Layer / File(s) Summary
URL state parsing: CSV → parseAsSafeArrayOf
ui/app/workspace/dashboard/page.tsx
Imports parseAsSafeArrayOf; removes parseCsvParam; switches multi-value useQueryStates fields to array parsers with [] defaults and missing_cost_only to a boolean parser.
filters/mcpFilters memo construction with array urlState
ui/app/workspace/dashboard/page.tsx
MCP derived selections, filters, and mcpFilters objects now pull directly from urlState arrays instead of CSV-parsed intermediates; memo dependency arrays are updated.
setFilters adapter writes arrays to URL state
ui/app/workspace/dashboard/page.tsx
setFilters writes array fields directly into URL state and sets missing_cost_only via boolean coercion; CSV join logic and adapter comment are updated.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • maximhq/bifrost#4714: Migrates multi-value URL query-state parsing to parseAsSafeArrayOf on another page.
  • maximhq/bifrost#4761: Applies the same safe array-backed URL query-state pattern to a different UI filter flow.
🚥 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
Title check ✅ Passed The title clearly summarizes the main change: switching dashboard array query params to parseAsSafeArrayOf.
Description check ✅ Passed The description follows the template well and covers summary, changes, testing, screenshots, breaking changes, issues, security, and checklist.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/handle-special-characters-in-dashboard-filters

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

@impoiler impoiler self-assigned this Jun 30, 2026
@impoiler
impoiler force-pushed the fix/handle-special-characters-in-dashboard-filters branch from 30915bb to 1158abc Compare June 30, 2026 11:13
@impoiler
impoiler force-pushed the 06-30-fix_sync_batch_model_parameters_and_remove_mcp_library_sync_from_the_model_force_sync_endpoint branch from cc76ad9 to 0008078 Compare June 30, 2026 11:13
@impoiler
impoiler marked this pull request as ready for review June 30, 2026 11:14
@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Safe to merge — this is a pure refactor that swaps manual CSV-string parsing for nuqs's built-in array and boolean parsers, with no behavior change visible to users and URL format backwards-compatibility maintained.

The change is mechanical and well-scoped: array params keep the same comma-separated URL format via parseAsArrayOf, the boolean conversion is a direct drop-in for the old string comparison, the redundant period write and its stale dependency are correctly removed, and data-testid attributes are untouched.

No files require special attention.

Important Files Changed

Filename Overview
ui/app/workspace/dashboard/page.tsx Replaces CSV string parsing with parseAsSafeArrayOf and parseAsBoolean; removes parseCsvParam helper and redundant memo variables. Logic is correct and URL format remains backwards-compatible.
ui/lib/queryParamsParser.ts Unchanged; exports parseAsSafeArrayOf = parseAsArrayOf(parseAsSafeString) — no modifications in this PR.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[URL Query Params] -->|parseAsSafeArrayOf| B[string array via nuqs]
    A -->|parseAsBoolean| C[boolean via nuqs]
    A -->|parseAsString| D[string via nuqs]

    B --> E[urlState array fields]
    C --> F[urlState.missing_cost_only]
    D --> G[urlState.mcp_tool_names and mcp_server_labels]

    E --> H[filters useMemo]
    F --> H
    G --> I[selectedMcpToolNames and selectedMcpServerLabels memos]
    I --> J[mcpFilters useMemo]
    E --> J

    H --> K[LogsFilterSidebar]
    J --> L[MCPTabView]

    M[setFilters] -->|arrays directly| A
    M -->|boolean directly| A
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[URL Query Params] -->|parseAsSafeArrayOf| B[string array via nuqs]
    A -->|parseAsBoolean| C[boolean via nuqs]
    A -->|parseAsString| D[string via nuqs]

    B --> E[urlState array fields]
    C --> F[urlState.missing_cost_only]
    D --> G[urlState.mcp_tool_names and mcp_server_labels]

    E --> H[filters useMemo]
    F --> H
    G --> I[selectedMcpToolNames and selectedMcpServerLabels memos]
    I --> J[mcpFilters useMemo]
    E --> J

    H --> K[LogsFilterSidebar]
    J --> L[MCPTabView]

    M[setFilters] -->|arrays directly| A
    M -->|boolean directly| A
Loading

Reviews (5): Last reviewed commit: "fix: handle special characters in dashbo..." | Re-trigger Greptile

Comment thread ui/app/workspace/dashboard/page.tsx
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 30, 2026
@impoiler
impoiler force-pushed the 06-30-fix_sync_batch_model_parameters_and_remove_mcp_library_sync_from_the_model_force_sync_endpoint branch from 0008078 to 11d1653 Compare June 30, 2026 11:20
@impoiler
impoiler force-pushed the fix/handle-special-characters-in-dashboard-filters branch from 1158abc to 5274612 Compare June 30, 2026 11:21
akshaydeo
akshaydeo previously approved these changes Jun 30, 2026
@impoiler
impoiler force-pushed the 06-30-fix_sync_batch_model_parameters_and_remove_mcp_library_sync_from_the_model_force_sync_endpoint branch from 11d1653 to c74e500 Compare July 1, 2026 06:41
@impoiler
impoiler force-pushed the fix/handle-special-characters-in-dashboard-filters branch from 5274612 to 17dcf7e Compare July 1, 2026 06:41

akshaydeo commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jul 1, 8:29 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 1, 8:31 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo changed the base branch from 06-30-fix_sync_batch_model_parameters_and_remove_mcp_library_sync_from_the_model_force_sync_endpoint to graphite-base/4801 July 1, 2026 08:30
@akshaydeo
akshaydeo changed the base branch from graphite-base/4801 to dev July 1, 2026 08:31
@akshaydeo
akshaydeo dismissed stale reviews from coderabbitai[bot] and themself July 1, 2026 08:31

The base branch was changed.

@akshaydeo
akshaydeo merged commit ff678a2 into dev Jul 1, 2026
13 of 14 checks passed
@akshaydeo
akshaydeo deleted the fix/handle-special-characters-in-dashboard-filters branch July 1, 2026 08:31
akshaydeo pushed a commit that referenced this pull request Jul 1, 2026
)

## Summary

Dashboard filter query parameters were being stored as comma-separated strings in the URL, requiring manual parsing and serialization on every read and write. This replaces that approach with a proper array-aware query parameter parser (`parseAsSafeArrayOf`) and uses `parseAsBoolean` for the `missing_cost_only` flag, so filter values are stored and consumed as native arrays and booleans directly from URL state.

## Changes

- Replaced `parseAsString` with `parseAsSafeArrayOf` for all array-typed filter parameters (`providers`, `models`, `virtual_key_ids`, `selected_key_ids`, `objects`, `status`, `routing_rule_ids`, `routing_engine_used`, `stop_reasons`, `user_ids`, `team_ids`, `customer_ids`, `business_unit_ids`, `aliases`)
- Replaced `parseAsString` with `parseAsBoolean` for `missing_cost_only`, removing the need to compare against the string `"true"`
- Removed the local `parseCsvParam` helper and all intermediate `useMemo` variables that existed solely to parse CSV strings into arrays — `urlState` values are now used directly
- Removed `.join(",")` serialization calls in `setFilters`; arrays are passed directly to `setUrlState`
- MCP tool name and server label fields (`mcp_tool_names`, `mcp_server_labels`) remain as strings for now, with their own minimal memo wrappers retained
- Removed a stale `urlState.period` reference from the `setFilters` dependency array

## Type of change

- [ ] Bug fix
- [ ] Feature
- [x] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (React)
- [ ] Docs

## How to test

Apply filters on the dashboard (providers, models, virtual keys, statuses, etc.) and verify:
1. URL query parameters reflect the selected values correctly
2. Refreshing the page restores all filters as expected
3. The `missing_cost_only` toggle persists as `true`/`false` in the URL rather than a string
4. Clearing filters resets URL params to their defaults

```sh
cd ui
pnpm i || npm i
pnpm build || npm run build
```

## Screenshots/Recordings

N/A — behavior is unchanged from the user's perspective; this is an internal state management refactor.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

None. This change only affects how filter values are serialized into and parsed from the URL query string.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
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