feat(ui): add session content search via API (#7050)

This commit is contained in:
tfsq
2026-02-06 14:21:08 -05:00
committed by GitHub
parent 99c25c4f0d
commit 459ae33df5
7 changed files with 238 additions and 28 deletions
+79
View File
@@ -2745,6 +2745,85 @@
]
}
},
"/sessions/search": {
"get": {
"tags": [
"Session Management"
],
"operationId": "search_sessions",
"parameters": [
{
"name": "query",
"in": "query",
"description": "Search query string",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "Maximum results (default: 10, max: 50)",
"required": false,
"schema": {
"type": "integer",
"nullable": true,
"minimum": 0
}
},
{
"name": "after_date",
"in": "query",
"description": "Filter after date (ISO 8601)",
"required": false,
"schema": {
"type": "string",
"nullable": true
}
},
{
"name": "before_date",
"in": "query",
"description": "Filter before date (ISO 8601)",
"required": false,
"schema": {
"type": "string",
"nullable": true
}
}
],
"responses": {
"200": {
"description": "Matching sessions",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Session"
}
}
}
}
},
"400": {
"description": "Bad request - Invalid query"
},
"401": {
"description": "Unauthorized"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"api_key": []
}
]
}
},
"/sessions/{session_id}": {
"get": {
"tags": [
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+48
View File
@@ -3530,6 +3530,54 @@ export type GetSessionInsightsResponses = {
export type GetSessionInsightsResponse = GetSessionInsightsResponses[keyof GetSessionInsightsResponses];
export type SearchSessionsData = {
body?: never;
path?: never;
query: {
/**
* Search query string
*/
query: string;
/**
* Maximum results (default: 10, max: 50)
*/
limit?: number | null;
/**
* Filter after date (ISO 8601)
*/
after_date?: string | null;
/**
* Filter before date (ISO 8601)
*/
before_date?: string | null;
};
url: '/sessions/search';
};
export type SearchSessionsErrors = {
/**
* Bad request - Invalid query
*/
400: unknown;
/**
* Unauthorized
*/
401: unknown;
/**
* Internal server error
*/
500: unknown;
};
export type SearchSessionsResponses = {
/**
* Matching sessions
*/
200: Array<Session>;
};
export type SearchSessionsResponse = SearchSessionsResponses[keyof SearchSessionsResponses];
export type DeleteSessionData = {
body?: never;
path: {
@@ -33,6 +33,7 @@ import {
forkSession,
importSession,
listSessions,
searchSessions,
Session,
updateSessionName,
ExtensionConfig,
@@ -342,7 +343,7 @@ const SessionListView: React.FC<SessionListViewProps> = React.memo(
}
}, [selectedSessionId, sessions]);
// Debounced search effect - performs actual filtering
// Debounced search effect - performs content search via API
useEffect(() => {
if (!debouncedSearchTerm) {
startTransition(() => {
@@ -352,32 +353,25 @@ const SessionListView: React.FC<SessionListViewProps> = React.memo(
return;
}
// Use startTransition to make search non-blocking
startTransition(() => {
const searchTerm = caseSensitive ? debouncedSearchTerm : debouncedSearchTerm.toLowerCase();
const filtered = sessions.filter((session) => {
const description = session.name;
const workingDir = session.working_dir;
const sessionId = session.id;
if (caseSensitive) {
return (
description.includes(searchTerm) ||
sessionId.includes(searchTerm) ||
workingDir.includes(searchTerm)
);
} else {
return (
description.toLowerCase().includes(searchTerm) ||
sessionId.toLowerCase().includes(searchTerm) ||
workingDir.toLowerCase().includes(searchTerm)
);
}
// Call the backend search API for content search
const performSearch = async () => {
const resp = await searchSessions({
query: { query: debouncedSearchTerm },
});
if (resp.data) {
// Response is Vec<Session> - sessions that match the search
const matchedSessionIds = new Set(resp.data.map((s: { id: string }) => s.id));
const filtered = sessions.filter((session) => matchedSessionIds.has(session.id));
startTransition(() => {
setFilteredSessions(filtered);
setSearchResults(filtered.length > 0 ? { count: filtered.length, currentIndex: 1 } : null);
});
}
};
setFilteredSessions(filtered);
setSearchResults(filtered.length > 0 ? { count: filtered.length, currentIndex: 1 } : null);
});
performSearch();
}, [debouncedSearchTerm, caseSensitive, sessions]);
// Handle immediate search input (updates search term for debouncing)