feat(client): let the session search match the last message
The placeholder promised less than the user wanted and the matcher
delivered less than the placeholder should: the search box only
substring-matched title and directory. It now also matches the
session's newest own message (timeline.lastUser, the card preview
text), case-insensitively, and a non-string fold shape safely never
matches. The placeholder copy follows in both locales ("Search title /
path / last message..." / "搜索标题 / 目录 / 最后消息...").
This commit is contained in:
1 parent
b377e36fc4
commit
07d389993e
3 files changed
+15
-6
No files matched your search
+2
-2
@@ -273,7 +273,7 @@ export const DICT_ZH: Record<string, string> = {
|
||||
'ov.heat.mon.07': '7月', 'ov.heat.mon.08': '8月', 'ov.heat.mon.09': '9月',
|
||||
'ov.heat.mon.10': '10月', 'ov.heat.mon.11': '11月', 'ov.heat.mon.12': '12月',
|
||||
'ov.list.title': '会话',
|
||||
'ov.list.search': '搜索标题或目录…',
|
||||
'ov.list.search': '搜索标题 / 目录 / 最后消息…',
|
||||
'ov.list.sortLabel': '排序',
|
||||
'ov.list.sort.recent': '最近更新', 'ov.list.sort.tokens': 'Token 总用量', 'ov.list.sort.context': '当前 Context',
|
||||
'ov.list.empty': '还没有会话 — 发起一轮对话后,这里会列出每个会话的上下文画像',
|
||||
@@ -563,7 +563,7 @@ export const DICT_EN: Record<string, string> = {
|
||||
'ov.heat.mon.07': 'Jul', 'ov.heat.mon.08': 'Aug', 'ov.heat.mon.09': 'Sep',
|
||||
'ov.heat.mon.10': 'Oct', 'ov.heat.mon.11': 'Nov', 'ov.heat.mon.12': 'Dec',
|
||||
'ov.list.title': 'Sessions',
|
||||
'ov.list.search': 'Search title or path…',
|
||||
'ov.list.search': 'Search title / path / last message…',
|
||||
'ov.list.sortLabel': 'Sort',
|
||||
'ov.list.sort.recent': 'Last updated', 'ov.list.sort.tokens': 'Total Tokens', 'ov.list.sort.context': 'Current Context',
|
||||
'ov.list.empty': 'No sessions yet — each session’s context profile appears here once you start one',
|
||||
|
||||
@@ -274,8 +274,8 @@ export function createdDayOf(activity: ContextActivity | null): string | undefin
|
||||
/**
|
||||
* The panel's row pipeline: range (by last-activity), then the heatmap's
|
||||
* picked day (sessions contributing to that day's merged ledger), then the
|
||||
* search box (title or directory substring). Each stage keeps the rows it
|
||||
* cannot prove out of the result — never an exception.
|
||||
* search box (title, directory, or last-message substring). Each stage keeps
|
||||
* the rows it cannot prove out of the result — never an exception.
|
||||
*/
|
||||
export function filterRows(
|
||||
rows: readonly OverviewRow[],
|
||||
@@ -293,7 +293,9 @@ export function filterRows(
|
||||
if (query !== '') {
|
||||
const inTitle = row.title.toLowerCase().includes(query)
|
||||
const inCwd = row.cwd !== undefined && row.cwd.toLowerCase().includes(query)
|
||||
if (!inTitle && !inCwd) return false
|
||||
const lastUser = row.timeline?.lastUser
|
||||
const inLastUser = typeof lastUser === 'string' && lastUser.toLowerCase().includes(query)
|
||||
if (!inTitle && !inCwd && !inLastUser) return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -228,11 +228,18 @@ describe('filterRows', () => {
|
||||
assert.deepEqual(filterRows(rows, { range: 'all', day: '2026-09-11', query: '' }, now), [], 'no ledger entry')
|
||||
})
|
||||
|
||||
test('the query matches title or directory, case-insensitively', () => {
|
||||
test('the query matches title, directory, or last message, case-insensitively', () => {
|
||||
assert.deepEqual(filterRows(rows, { range: 'all', day: null, query: 'FRESH' }, now).map(r => r.id), ['new'])
|
||||
assert.deepEqual(filterRows(rows, { range: 'all', day: null, query: '/repo' }, now).map(r => r.id), ['new'])
|
||||
assert.deepEqual(filterRows(rows, { range: 'all', day: null, query: ' ' }, now).length, 3, 'a blank query matches all')
|
||||
assert.deepEqual(filterRows(rows, { range: 'all', day: null, query: 'zzz' }, now), [])
|
||||
// The session's newest own message joins the haystack.
|
||||
const talked = rowOf({ id: 'talk', title: 'quiet title', timeline: { lastUser: 'ship the QUARTERLY report' } as unknown as ContextTimeline })
|
||||
assert.deepEqual(filterRows([talked], { range: 'all', day: null, query: 'quarterly' }, now).map(r => r.id), ['talk'])
|
||||
assert.deepEqual(filterRows([talked], { range: 'all', day: null, query: 'quiet' }, now).map(r => r.id), ['talk'], 'the title still matches')
|
||||
// A non-string last message (a hostile fold shape) never matches.
|
||||
const odd = rowOf({ id: 'odd', title: 'odd one', timeline: { lastUser: 42 } as unknown as ContextTimeline })
|
||||
assert.deepEqual(filterRows([odd], { range: 'all', day: null, query: '42' }, now), [])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user