Files
agent-desktop/console/src/utils/sessionGrouping.ts
T
Pine 9b30f681c6 feat: 智能体控制台前端(console)
- React+antd+zustand,注册表驱动路由/菜单/权限
- Tauri 桌面壳、后端托管 SPA、跨标签页消息队列
2026-08-23 22:43:18 +08:00

109 lines
2.8 KiB
TypeScript

/**
* Shared session grouping utilities for both SidebarSessionList and ChatSessionDrawer.
* Groups sessions by date: pinned, today, within 7 days, within 30 days, older.
*/
export type DateGroup = "pinned" | "today" | "week" | "month" | "older";
export interface SessionGroup<T> {
key: DateGroup;
label: string;
sessions: T[];
}
/**
* Determine which date group a timestamp belongs to.
* Uses calendar dates (not elapsed-time) so "today" always means the same Y/M/D.
*/
export function getDateGroup(
timestamp: string | null | undefined,
): Exclude<DateGroup, "pinned"> {
if (!timestamp) return "older";
const date = new Date(timestamp);
if (isNaN(date.getTime())) return "older";
const now = new Date();
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const dateStart = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate(),
);
const calendarDays = Math.floor(
(todayStart.getTime() - dateStart.getTime()) / (1000 * 60 * 60 * 24),
);
if (calendarDays <= 0) return "today";
if (calendarDays < 7) return "week";
if (calendarDays < 30) return "month";
return "older";
}
/**
* Group sessions by pinned status and date.
* Pinned sessions go to "pinned" group, others are grouped by date.
* Empty groups are filtered out.
*/
export function groupSessions<
T extends {
pinned?: boolean;
updatedAt?: string | null;
createdAt?: string | null;
},
>(
sessions: T[],
t: (key: string, fallback: string) => string,
): SessionGroup<T>[] {
const buckets: Record<DateGroup, T[]> = {
pinned: [],
today: [],
week: [],
month: [],
older: [],
};
for (const s of sessions) {
if (s.pinned) {
buckets.pinned.push(s);
} else {
buckets[getDateGroup(s.updatedAt ?? s.createdAt)].push(s);
}
}
const order: Array<{ key: DateGroup; fallback: string }> = [
{ key: "pinned", fallback: "Pinned" },
{ key: "today", fallback: "Today" },
{ key: "week", fallback: "Within 7 days" },
{ key: "month", fallback: "Within 30 days" },
{ key: "older", fallback: "Earlier" },
];
return order
.filter(({ key }) => buckets[key].length > 0)
.map(({ key, fallback }) => ({
key,
label: t(`chat.group.${key}`, fallback),
sessions: buckets[key],
}));
}
/**
* Locate a session inside the flattened (group header + session) rows
* of the virtualized session lists. Rows inside collapsed groups are
* not present, so a -1 result also means "not currently visible".
*/
export function findSessionRowIndex(
rows: Array<{
kind: string;
session?: { id?: string; realId?: string };
}>,
sessionId: string | undefined,
): number {
if (!sessionId) return -1;
return rows.findIndex(
(row) =>
row.kind === "session" &&
(row.session?.id === sessionId || row.session?.realId === sessionId),
);
}