Skip to content

Commit 5a50ced

Browse files
committed
feat(web): reuse session search in sessions/groups and fix dark tab styles
1 parent 7d8175b commit 5a50ced

5 files changed

Lines changed: 56 additions & 19 deletions

File tree

web/src/lib/locales/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default {
4747
'sessions.projectOffline.disable': 'Unmark project offline',
4848
'sessions.display.toggleToCompact': 'Switch to compact view',
4949
'sessions.display.toggleToComfortable': 'Switch to comfortable view',
50+
'sessions.search.placeholder': 'Search sessions…',
5051
'sessions.sidebar.resize': 'Resize sidebar',
5152
'sessions.sidebar.open': 'Open sessions sidebar',
5253
'sessions.sidebar.close': 'Close sessions sidebar',

web/src/lib/locales/zh-CN.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default {
4747
'sessions.projectOffline.disable': '取消项目离线',
4848
'sessions.display.toggleToCompact': '切换到紧凑视图',
4949
'sessions.display.toggleToComfortable': '切换到舒适视图',
50+
'sessions.search.placeholder': '搜索会话…',
5051
'sessions.sidebar.resize': '调整侧边栏宽度',
5152
'sessions.sidebar.open': '打开会话侧边栏',
5253
'sessions.sidebar.close': '关闭会话侧边栏',

web/src/lib/session-search.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { SessionSummary } from '@/types/api'
2+
import { getSessionTitle } from '@/lib/session-title'
3+
4+
function normalizeQuery(query: string): string {
5+
return query.trim().toLowerCase()
6+
}
7+
8+
function buildSessionSearchFields(session: SessionSummary): string[] {
9+
const title = getSessionTitle(session, { fallbackIdLength: 12 }).toLowerCase()
10+
const name = (session.metadata?.name ?? '').toLowerCase()
11+
const summary = (session.metadata?.summary?.text ?? '').toLowerCase()
12+
const path = (session.metadata?.path ?? '').toLowerCase()
13+
const sessionId = session.id.toLowerCase()
14+
return [title, name, summary, path, sessionId]
15+
}
16+
17+
export function matchesSessionSearch(session: SessionSummary, query: string): boolean {
18+
const normalizedQuery = normalizeQuery(query)
19+
if (!normalizedQuery) {
20+
return true
21+
}
22+
return buildSessionSearchFields(session).some((field) => field.includes(normalizedQuery))
23+
}
24+
25+
export function filterSessionsBySearch(sessions: SessionSummary[], query: string): SessionSummary[] {
26+
const normalizedQuery = normalizeQuery(query)
27+
if (!normalizedQuery) {
28+
return sessions
29+
}
30+
return sessions.filter((session) => matchesSessionSearch(session, normalizedQuery))
31+
}

web/src/router.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createContext, useCallback, useContext, useEffect, useState, type CSSProperties } from 'react'
1+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, type CSSProperties } from 'react'
22
import { useQueryClient } from '@tanstack/react-query'
33
import {
44
Navigate,
@@ -40,6 +40,7 @@ import { usePlatform } from '@/hooks/usePlatform'
4040
import { SessionActionMenu } from '@/components/SessionActionMenu'
4141
import { ConfirmDialog } from '@/components/ui/ConfirmDialog'
4242
import type { GroupDetail } from '@/types/api'
43+
import { filterSessionsBySearch } from '@/lib/session-search'
4344
import FilesPage from '@/routes/sessions/files'
4445
import FilePage from '@/routes/sessions/file'
4546
import PreviewPage from '@/routes/sessions/preview'
@@ -231,6 +232,12 @@ function SessionsPage() {
231232
const { sidebarWidth, isResizing, startSidebarResize } = useSessionSidebarWidth()
232233
const { desktopSidebarHidden, setDesktopSidebarHidden, toggleDesktopSidebar } = useSessionSidebarVisibility()
233234
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false)
235+
const [sessionSearchQuery, setSessionSearchQuery] = useState('')
236+
237+
const visibleSessions = useMemo(
238+
() => filterSessionsBySearch(sessions, sessionSearchQuery),
239+
[sessions, sessionSearchQuery]
240+
)
234241

235242
const handleRefresh = useCallback(() => {
236243
void refetch()
@@ -244,7 +251,7 @@ function SessionsPage() {
244251
})
245252
}, [navigate])
246253

247-
const projectCount = new Set(sessions.map(s => s.metadata?.worktree?.basePath ?? s.metadata?.path ?? 'Other')).size
254+
const projectCount = new Set(visibleSessions.map(s => s.metadata?.worktree?.basePath ?? s.metadata?.path ?? 'Other')).size
248255
const sessionMatch = matchRoute({ to: '/sessions/$sessionId', fuzzy: true })
249256
const chatRouteMatch = matchRoute({ to: '/sessions/$sessionId', fuzzy: false })
250257
const selectedSessionId = sessionMatch && sessionMatch.sessionId !== 'new' ? sessionMatch.sessionId : null
@@ -325,7 +332,7 @@ function SessionsPage() {
325332
<div className="flex items-center gap-1">
326333
<button
327334
type="button"
328-
className="rounded-md px-2.5 py-1.5 text-xs bg-[var(--app-link)] text-white font-medium"
335+
className="rounded-md px-2.5 py-1.5 text-xs bg-[var(--app-button)] text-[var(--app-button-text)] font-medium"
329336
>
330337
Sessions
331338
</button>
@@ -392,9 +399,17 @@ function SessionsPage() {
392399
</div>
393400
<div className="mx-auto w-full max-w-content flex items-center justify-between px-3 py-1.5">
394401
<div className="text-xs text-[var(--app-hint)]">
395-
{t('sessions.count', { n: sessions.length, m: projectCount })}
402+
{t('sessions.count', { n: visibleSessions.length, m: projectCount })}
396403
</div>
397404
</div>
405+
<div className="mx-auto w-full max-w-content px-3 pb-2">
406+
<input
407+
value={sessionSearchQuery}
408+
onChange={(e) => setSessionSearchQuery(e.target.value)}
409+
placeholder={t('sessions.search.placeholder')}
410+
className="w-full rounded-md border border-[var(--app-divider)] bg-[var(--app-secondary-bg)] px-3 py-1.5 text-sm outline-none focus:border-[var(--app-link)]"
411+
/>
412+
</div>
398413
</div>
399414

400415
<div className="flex min-h-0 flex-1 flex-col">
@@ -405,7 +420,7 @@ function SessionsPage() {
405420
) : null}
406421
<div className="min-h-0 flex-1">
407422
<SessionList
408-
sessions={sessions}
423+
sessions={visibleSessions}
409424
selectedSessionId={selectedSessionId}
410425
onSelect={selectSession}
411426
onNewSession={openNewSession}
@@ -886,7 +901,7 @@ function GroupsLayout() {
886901
</button>
887902
<button
888903
type="button"
889-
className="rounded-md px-2.5 py-1.5 text-xs bg-[var(--app-link)] text-white font-medium"
904+
className="rounded-md px-2.5 py-1.5 text-xs bg-[var(--app-button)] text-[var(--app-button-text)] font-medium"
890905
>
891906
Groups
892907
</button>

web/src/routes/groups/detail.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { LoadingState } from '@/components/LoadingState'
1212
import { NewSession } from '@/components/NewSession'
1313
import { useTranslation } from '@/lib/use-translation'
1414
import { getSessionTitle } from '@/lib/session-title'
15+
import { matchesSessionSearch } from '@/lib/session-search'
1516

1617
// ─── Icons ───────────────────────────────────────────────────────────────────
1718

@@ -216,21 +217,9 @@ function AddMemberModal(props: {
216217
const onlineMachines = useMemo(() => machines.filter((m) => m.active), [machines])
217218

218219
const { online, offline } = useMemo(() => {
219-
const q = search.trim().toLowerCase()
220220
const available = sessions.filter((s) => {
221221
if (props.existingMemberSessionIds.has(s.id)) return false
222-
if (!q) return true
223-
const name = getSessionTitle(s, { fallbackIdLength: 12 }).toLowerCase()
224-
const rawName = (s.metadata?.name ?? '').toLowerCase()
225-
const summary = (s.metadata?.summary?.text ?? '').toLowerCase()
226-
const path = (s.metadata?.path ?? '').toLowerCase()
227-
return (
228-
name.includes(q)
229-
|| rawName.includes(q)
230-
|| summary.includes(q)
231-
|| path.includes(q)
232-
|| s.id.toLowerCase().includes(q)
233-
)
222+
return matchesSessionSearch(s, search)
234223
})
235224
return {
236225
online: available.filter((s) => s.active),

0 commit comments

Comments
 (0)