| 1 | import { t, useT } from "./i18n"; |
| 2 | import { sessionActivityTime } from "./session"; |
| 3 | import type { HistoryMessage, SessionMeta } from "./types"; |
| 4 | import { historyMessagesToItems, type Item } from "./useController"; |
| 5 | |
| 6 | export function historyDayLabel(ms: number): string { |
| 7 | const startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime(); |
| 8 | const days = Math.round((startOfDay(new Date()) - startOfDay(new Date(ms))) / 86_400_000); |
| 9 | if (days <= 0) return t("history.today"); |
| 10 | if (days === 1) return t("history.yesterday"); |
| 11 | return new Date(ms).toLocaleDateString(); |
| 12 | } |
| 13 | |
| 14 | export function historyTimeLabel(ms: number): string { |
| 15 | return new Date(ms).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); |
| 16 | } |
| 17 | |
| 18 | export function historyDateBucket(ms: number): "today" | "yesterday" | "older" { |
| 19 | const startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime(); |
| 20 | const days = Math.round((startOfDay(new Date()) - startOfDay(new Date(ms))) / 86_400_000); |
| 21 | if (days <= 0) return "today"; |
| 22 | if (days === 1) return "yesterday"; |
| 23 | return "older"; |
| 24 | } |
| 25 | |
| 26 | export function historySessionTime(s: SessionMeta, trash: boolean): number { |
| 27 | return trash ? s.deletedAt || sessionActivityTime(s) : sessionActivityTime(s); |
| 28 | } |
| 29 | |
| 30 | export function historySessionScope(s: SessionMeta): "project" | "global" { |
| 31 | return s.scope === "project" ? "project" : "global"; |
| 32 | } |
| 33 | |
| 34 | export function isChannelHistorySession(s: SessionMeta): boolean { |
| 35 | return s.kind === "channel" || s.sessionSource === "auto"; |
| 36 | } |
| 37 | |
| 38 | export function historySessionLocation(s: SessionMeta, tr: ReturnType<typeof useT>): string { |
| 39 | if (isChannelHistorySession(s)) return [s.channelLabel || s.channel || tr("history.channel"), s.remoteId].filter(Boolean).join(" · "); |
| 40 | if (s.workspaceRoot) { |
| 41 | const parts = s.workspaceRoot.split(/[\\/]/).filter(Boolean); |
| 42 | return parts[parts.length - 1] || s.workspaceRoot; |
| 43 | } |
| 44 | return historySessionScope(s) === "project" ? tr("history.filterProject") : tr("history.filterGlobal"); |
| 45 | } |
| 46 | |
| 47 | export function historySessionMetaLine(s: SessionMeta, tr: ReturnType<typeof useT>, trash = false): string { |
| 48 | const time = historyTimeLabel(historySessionTime(s, trash)); |
| 49 | const suffix = trash && s.deletedAt ? ` · ${tr("history.deleted")}` : ""; |
| 50 | const prefix = isChannelHistorySession(s) ? `${tr("history.channelReadOnly")} · ` : ""; |
| 51 | const turns = s.turnsState === "unknown" |
| 52 | ? tr("history.indexing") |
| 53 | : tr(s.turns === 1 ? "history.turnOne" : "history.turnOther", { n: s.turns }); |
| 54 | return `${prefix}${turns} · ${time}${suffix}`; |
| 55 | } |
| 56 | |
| 57 | export function historyPreviewItems(messages: HistoryMessage[]): Item[] { |
| 58 | return historyMessagesToItems(messages, "hp").items; |
| 59 | } |
| 60 |