Files
supabase/apps/studio/components/layouts/ExplorerLayout/ExplorerNavHome.utils.ts
Joshen Lim 9738035fec Hook up recently updated list (#49296)
## Context

As per PR title: recently updated list just comprises of notebooks and
chats
Note: known API issue that save a notebook doesn't update its
`updated_at` value, so you'll notice that if you save a notebook it
doesn't move up the recently updated list

<img width="281" height="270" alt="image"
src="https://github.com/user-attachments/assets/f637a593-09a7-4df4-85b7-43637f04738d"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added a home view displaying recently updated notebooks and chats.
  * Recent items are sorted by update time and limited to five entries.
  * Added relative timestamps in minutes, hours, or days.
* Chat entries open directly, while notebook entries link to their
explorer view.
  * Added an empty state when no recent items are available.

* **Bug Fixes**
  * Excluded unsupported chat types from recent-item results.
  * Improved handling of unavailable timestamps.

* **Tests**
* Added coverage for sorting, filtering, limits, and relative-time
formatting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-21 00:02:53 +08:00

65 lines
1.9 KiB
TypeScript

import dayjs from 'dayjs'
import type { NotebookRow } from '@/data/content/notebooks/notebooks-infinite-query'
import type { ChatSession } from '@/state/ai-assistant-state'
export const RECENTLY_UPDATED_ITEMS_LIMIT = 5
export interface RecentlyUpdatedItem {
id: string
type: 'notebook' | 'chat'
label: string
updatedAt: number
}
/**
* Merges notebooks and chats into one recency-sorted list. Chats can reach here before
* their persisted state has hydrated (no `updatedAt` yet), so those sort last rather than
* throwing or floating to the top.
*/
export function getRecentlyUpdatedItems({
notebooks,
chats,
limit = RECENTLY_UPDATED_ITEMS_LIMIT,
}: {
notebooks: NotebookRow[]
chats: ChatSession[]
limit?: number
}): RecentlyUpdatedItem[] {
const notebookItems: RecentlyUpdatedItem[] = notebooks.map((notebook) => ({
id: notebook.id,
type: 'notebook',
label: notebook.name,
updatedAt: new Date(notebook.updated_at).getTime(),
}))
const chatItems: RecentlyUpdatedItem[] = chats
.filter((chat) => !chat.supportMetadata?.isSupportChat)
.map((chat) => ({
id: chat.id,
type: 'chat',
label: chat.name,
updatedAt: chat.updatedAt?.getTime() ?? 0,
}))
return [...notebookItems, ...chatItems].sort((a, b) => b.updatedAt - a.updatedAt).slice(0, limit)
}
/** Compact relative time (`12m`, `21h`, `2d`) for the narrow recent-items row. */
export function formatRelativeTimeShort(
timestamp: number,
now: number = Date.now()
): string | undefined {
if (timestamp === 0) return undefined
const diffMinutes = dayjs(now).diff(timestamp, 'minute')
if (diffMinutes < 1) return 'just now'
if (diffMinutes < 60) return `${diffMinutes}m ago`
const diffHours = dayjs(now).diff(timestamp, 'hour')
if (diffHours < 24) return `${diffHours}h ago`
const diffDays = dayjs(now).diff(timestamp, 'day')
return `${diffDays}d ago`
}