feat(sl-viewer): Search tab + GET /api/search daemon endpoint - #42
Conversation
- Add Tab::Search variant and SearchView Dioxus component in sl-viewer with since/until/model/min_tokens/tags/limit form fields, Search and Clear buttons, and a results list in bundle-card style - Add GET /api/search route to sl-daemon http.rs; accepts query params, applies FilterSpec via apply_filters, returns JSON array of BundleMeta - Derive Serialize on BundleMeta so it can be returned by the HTTP handler - Add 5 unit tests for params_to_spec and 5 for build_query (viewer side)
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Warning Review limit reached
Next review available in: 46 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Free Run ID: 📒 Files selected for processing (5)
Note 🎁 Summarized by CodeRabbit FreeThe PR author is not assigned a seat. To perform a comprehensive line-by-line review, please assign a seat to the pull request author through the subscription management page by visiting https://app.coderabbit.ai/login. Comment |
| spawn(async move { | ||
| #[cfg(feature = "web")] | ||
| { | ||
| use_web_fetch(url, results, error, loading).await; |
There was a problem hiding this comment.
CRITICAL: use_web_fetch is undefined — the web feature will fail to compile
The #[cfg(feature = "web")] branch calls use_web_fetch, but no such function exists in the crate. Enabling the web feature will fail with a compile error.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| } | ||
|
|
||
| /// Daemon base URL used for all HTTP calls. | ||
| const DAEMON_BASE: &str = "http://127.0.0.1:8080"; |
There was a problem hiding this comment.
WARNING: Hardcoded daemon address prevents configuration
DAEMON_BASE is locked to http://127.0.0.1:8080. This makes the viewer unusable if the daemon binds to a different address/port, and prevents proxying or remote daemon setups.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| } | ||
|
|
||
| /// Minimal percent-encoder — encodes the characters that break query strings. | ||
| fn urlencoding(s: &str) -> String { |
There was a problem hiding this comment.
WARNING: Incomplete URL encoder breaks on %, ?, and other reserved characters
The custom urlencoding function only encodes a small subset of characters. Missing % (re-encoding risk), ? (query delimiter injection), ', and others. Unencoded % sequences can cause parse failures or misinterpretation.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| let tags_val = tags.clone(); | ||
| let limit_val = limit.clone(); | ||
|
|
||
| let on_search = move |_| { |
There was a problem hiding this comment.
WARNING: Missing debounce guard on search allows concurrent requests
on_search sets loading.set(true) but never checks loading() to reject or queue additional clicks. Rapid clicks spawn overlapping requests that race to update state.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| #[cfg(not(feature = "web"))] | ||
| async fn reqwest_search(url: &str) -> Result<Vec<SearchResult>, String> { | ||
| // Dioxus desktop bundles tokio; we can do async HTTP directly. | ||
| let client = reqwest::Client::new(); |
There was a problem hiding this comment.
WARNING: Per-request reqwest::Client discards connection pooling
reqwest::Client is intended to be reused across requests. Creating a new instance per search forces fresh TCP/TLS handshakes and prevents connection reuse, degrading performance under repeated use.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| let tags_display = r.tags.join(", "); | ||
| rsx! { | ||
| div { | ||
| key: "{r.session_id}-{idx}", |
There was a problem hiding this comment.
SUGGESTION: Include render index in Dioxus key harms reconciliation stability
key: "{r.session_id}-{idx}" couples the key to the list position. When results reorder (e.g. new search), indices shift and Dioxus recycles DOM nodes unnecessarily. Prefer a stable unique key such as r.session_id alone, assuming it is unique.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| parts.push(format!("tags={}", urlencoding(tags))); | ||
| } | ||
| let limit = limit.trim(); | ||
| let limit_val = limit.parse::<usize>().unwrap_or(50); |
There was a problem hiding this comment.
SUGGESTION: Silent fallback on invalid limit obscures user input
limit.parse::<usize>().unwrap_or(50) silently ignores non-numeric values. Consider preserving the invalid text or showing an inline error so the user understands why their input was ignored.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
Code Review SummaryStatus: 7 Issues Found | Recommendation: Request Changes Overview
Issue Details (click to expand)CRITICAL
WARNING
SUGGESTION
Files Reviewed (5 files)
Fix these issues in Kilo Cloud Reviewed by step-3.7-flash-20260528 · Input: 161.1K · Output: 31.1K · Cached: 636.4K |
Summary
sl-viewerDioxus desktop app with form fields forsince,until,model,min_tokens,tags(comma-separated, AND logic), andlimit(default 50). Clicking Search callsGET /api/searchon the sl-daemon at127.0.0.1:8080and renders results as bundle cards in the same style as the Bundles tab. Clear resets all fields and results.GET /api/searchtosl-daemon/src/http.rs— accepts the same query parameters, appliesFilterSpecvia the existingapply_filtersfunction, and returns a JSON array ofBundleMeta(now alsoSerialize).params_to_spec(daemon query param →FilterSpecmapping) and 5 forbuild_query(viewer URL construction), all green with 70 total tests passing.Test plan
cargo testincrates/sl-daemon— 70 tests, 0 failedcargo build -p sl-viewer— clean build, no warningscargo build -p sl-daemon— clean build, no warningscargo clippy -- -D warningsincrates/sl-daemon— cleansl serve --watch ./sessions --out ./okf-out, open viewer, click Search tab, enter modelclaude, click Search → results list appears🤖 Generated with Claude Code