Bind widgets to query params - Part 2#13682
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
This stack of pull requests is managed by Graphite. Learn more about stacking. |
📉 Python coverage change detectedThe Python unit test coverage has decreased by 0.0000%
✅ Coverage change is within normal range. Coverage by files
|
📈 Frontend coverage change detectedThe frontend unit test (vitest) coverage has increased by 0.0100%
✅ Coverage change is within normal range. |
a3f6a97 to
58e746c
Compare
0e87831 to
a094773
Compare
There was a problem hiding this comment.
Pull request overview
Adds frontend infrastructure for binding widget values to URL query parameters, enabling two-way sync between widget state and the browser URL (including preservation behavior across multipage navigation).
Changes:
- Introduces query param binding registration and URL-sync logic in
WidgetStateManager(including default-value clearing and option index→string mapping). - Integrates widget-driven query param updates into
Appstate to preserve relevant params on page navigation. - Updates
useBasicWidgetStateinitialization semantics aroundsetValue, and adds/updates unit tests.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/lib/src/hooks/useBasicWidgetState.ts | Initializes widget state from proto value when backend sets setValue. |
| frontend/lib/src/hooks/useBasicWidgetState.test.ts | Adds unit tests for setValue/default initialization behavior. |
| frontend/lib/src/components/widgets/ButtonGroup/ButtonGroup.test.tsx | Updates expectation to initialize from .value when setValue is true. |
| frontend/lib/src/WidgetStateManager.ts | Adds query param binding registry, URL sync helpers, and navigation param filtering. |
| frontend/lib/src/WidgetStateManager.test.ts | Adds unit tests for query param binding behavior and URL sync. |
| frontend/app/src/App.tsx | Wires widget URL updates into App state and preserves bound params on page changes. |
| frontend/app/src/App.test.tsx | Updates tests to reflect new query param preservation/clearing behavior on navigation. |
58e746c to
00f8c92
Compare
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
00f8c92 to
e5b021f
Compare
SummaryAdds query param binding support in the frontend by syncing bound widget updates to the URL, preserving bound params across page navigation, and initializing App state from the current URL. Updates Code QualityEncapsulation is clean: query-param logic lives in Test CoverageStrong unit coverage was added for query param binding and Backwards CompatibilityBehavior should remain compatible provided the backend correctly sets Security & RiskNo new security concerns identified. URL updates are local and use Recommendations
VerdictAPPROVED: Solid implementation with thorough unit tests; only optional e2e coverage is missing. This is an automated AI review using |
ab5519d to
db991f2
Compare
db991f2 to
f72245e
Compare
📈 Significant bundle size change detected
Please verify that this change is expected. |
30e35be to
41afb54
Compare
SummaryThis PR adds frontend infrastructure for binding widgets to URL query parameters, enabling two-way synchronization between widget interactions and the browser's URL. Key changes include:
Code QualityStrengths:
Code structure observations: const getDefaultState = useCallback<(wm: WidgetStateManager, el: P) => T>(
(_wm, el) => {
// Backend explicitly set a value (e.g., from URL params or session_state).
// This handles both initial URL seeding and session_state updates.
// On React Strict Mode remount, WidgetStateManager will have the value
// (stored by the first mount's effect), so this path won't be reached.
if (el.setValue) {
return getCurrStateFromProto(el)
}
return getDefaultStateFromProto(el)
},
[getDefaultStateFromProto, getCurrStateFromProto]
)Good pattern using private maybeSyncValueToUrl(
widgetId: string,
source: Source,
value: unknown
): void {
if (!source.fromUi) return
const binding = this.boundWidgets.get(widgetId)
if (!binding) return
// Pure: Convert value to URL format
const urlValue = this.convertToUrlValue(value, binding)
// Pure: Check if we should clear the param
const shouldClear = this.shouldClearUrlParam(urlValue, binding)
// Side effect: Update URL
this.updateUrlParam(
binding.paramKey,
shouldClear ? null : urlValue,
binding.urlFormat
)
}Clean separation of pure logic and side effects. Minor notes:
Test CoverageExcellent test coverage with 524+ new lines of tests for query param binding. The tests follow best practices:
Test pattern quality:
Backwards CompatibilityThe changes are backwards compatible:
The URL initialization change in queryParams: window.location?.search?.replace(/^\?/, "") ?? "",Is safe as it only affects the initial state and preserves expected behavior for shared links. Security & RiskNo security concerns identified:
Low regression risk:
Potential edge case to monitor:
Recommendations
VerdictAPPROVED: This PR provides well-structured, thoroughly tested frontend infrastructure for widget-to-URL query param binding. The code follows existing patterns, has comprehensive test coverage (500+ new lines), is backwards compatible, and introduces no security concerns. The implementation is clean and ready for merge. This is an automated AI review using |
SummaryThis PR adds frontend infrastructure to bind widget values to URL query parameters (two-way-ish sync for UI → URL, plus preserving bound params during page navigation). The core work is in Code Quality
Test Coverage
Backwards Compatibility
Security & Risk
Recommendations
VerdictCHANGES REQUESTED: The query-param binding infrastructure looks solid and well-tested overall, but This is an automated AI review using |
sfc-gh-bnisco
left a comment
There was a problem hiding this comment.
+1 to the most recent AI review pass. I have small perf suggestion inline as well.
| // Pure: Check if we should clear the param | ||
| const shouldClear = this.shouldClearUrlParam(urlValue, binding) | ||
|
|
||
| // Side effect: Update URL |
There was a problem hiding this comment.
suggestion (non-blocking): If the URL doesn't actually change, it might make sense to skip the underlying call to replaceState for performance reasons.
I added logging when all values are filtered out, but I'm not sure this poses a "regression risk" - invalid values can't come from the UI, and if the backend sends them it would indicate an unhandled edge case in user code. |

Describe your changes
Bind Widgets to Query Params - Part 2
This PR adds the frontend infrastructure for binding widgets to query parameters - enabling two-way sync between widget interactions and the browser's URL.
registerQueryParamBinding()/unregisterQueryParamBinding()to track widget-to-param relationships on the frontendsyncToUrlIfBound(),syncCommaArrayToUrlIfBound(),syncRepeatedArrayToUrlIfBound()update the URL when widgets changehandleQueryParamsFromWidget()keeps App state in sync with URL changesfilterParamsForPageChange()preserves embed params and bound widget params while clearing other query params (like ?foo=bar) when navigating between pages - page-specific ones are cleared by the backenduseBasicWidgetState- UsessetValueflag to correctly initialize widget state from backend (URL-seeded orsession_statevalues), withWidgetStateManagerpersisting values across React Strict Mode remountsTesting Plan