fix(web): summarize session titles, sort by activity, and paginate history (BUG-553)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import type { ChatSession } from "@/lib/home-types";
|
||||
|
||||
export const SESSION_RECENCY_LABELS = {
|
||||
today: "今天",
|
||||
yesterday: "昨天",
|
||||
week: "最近 7 天",
|
||||
month: "最近 30 天",
|
||||
older: "更早",
|
||||
} as const;
|
||||
|
||||
export type SessionRecencyKey = keyof typeof SESSION_RECENCY_LABELS;
|
||||
|
||||
export type SessionRecencyGroup<T extends { updatedAt: number } = ChatSession> = {
|
||||
readonly key: SessionRecencyKey;
|
||||
readonly label: string;
|
||||
readonly sessions: readonly T[];
|
||||
};
|
||||
|
||||
function startOfLocalDay(now: Date): number {
|
||||
return new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
|
||||
}
|
||||
|
||||
export function sortSessions<T extends { pinned: boolean; updatedAt: number }>(sessions: readonly T[]): T[] {
|
||||
return sessions
|
||||
.map((session, index) => ({ session, index }))
|
||||
.sort((left, right) => {
|
||||
const pinned = Number(right.session.pinned) - Number(left.session.pinned);
|
||||
if (pinned !== 0) return pinned;
|
||||
const time = right.session.updatedAt - left.session.updatedAt;
|
||||
if (time !== 0) return time;
|
||||
return left.index - right.index;
|
||||
})
|
||||
.map((item) => item.session);
|
||||
}
|
||||
|
||||
export function recencyKeyFor(updatedAt: number, now = Date.now()): SessionRecencyKey {
|
||||
const todayStart = startOfLocalDay(new Date(now));
|
||||
const dayMs = 24 * 60 * 60 * 1000;
|
||||
if (updatedAt >= todayStart) return "today";
|
||||
if (updatedAt >= todayStart - dayMs) return "yesterday";
|
||||
if (updatedAt >= todayStart - 6 * dayMs) return "week";
|
||||
if (updatedAt >= todayStart - 29 * dayMs) return "month";
|
||||
return "older";
|
||||
}
|
||||
|
||||
export function groupSessionsByRecency<T extends { updatedAt: number }>(
|
||||
sessions: readonly T[],
|
||||
now = Date.now(),
|
||||
): SessionRecencyGroup<T>[] {
|
||||
const buckets: Record<SessionRecencyKey, T[]> = {
|
||||
today: [],
|
||||
yesterday: [],
|
||||
week: [],
|
||||
month: [],
|
||||
older: [],
|
||||
};
|
||||
for (const session of sessions) {
|
||||
buckets[recencyKeyFor(session.updatedAt, now)].push(session);
|
||||
}
|
||||
const order: SessionRecencyKey[] = ["today", "yesterday", "week", "month", "older"];
|
||||
return order.flatMap((key) => {
|
||||
const group = buckets[key];
|
||||
if (group.length === 0) return [];
|
||||
return [{ key, label: SESSION_RECENCY_LABELS[key], sessions: group }];
|
||||
});
|
||||
}
|
||||
|
||||
export function mergeSessionPage<T extends { id: string; updatedAt: number }>(
|
||||
existing: readonly T[],
|
||||
incoming: readonly T[],
|
||||
): T[] {
|
||||
const seen = new Map(existing.map((session) => [session.id, session]));
|
||||
const next = [...existing];
|
||||
for (const row of incoming) {
|
||||
const current = seen.get(row.id);
|
||||
if (current) continue;
|
||||
seen.set(row.id, row);
|
||||
next.push(row);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
export function beginSessionPageLoad(
|
||||
inFlight: { current: boolean },
|
||||
cursor: string | null,
|
||||
): boolean {
|
||||
if (inFlight.current || !cursor) return false;
|
||||
inFlight.current = true;
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user