Files
momentry_studio/src/composables/useSearchHistory.ts
Momentry Studio 55c39e7732 feat: keep only last 2 hours of search history
- Filter history to show only items from last 2 hours
- Pinned items are always kept regardless of age
- Auto-cleanup old unpinned items from database
- Increased fetch limit to 50 to ensure enough items for filtering
2026-10-20 17:57:27 +08:00

168 lines
4.2 KiB
TypeScript

import { ref } from 'vue'
import { apiCall } from '@/api'
export interface HistoryItem {
id: string
query: string
title: string
chat_state: string | null
mode: string | null
pinned: boolean
created_at: string | null
updated_at: string | null
}
export function useSearchHistory() {
const history = ref<HistoryItem[]>([])
const loading = ref(false)
const HISTORY_HOURS = 2 // Keep last 2 hours of history
async function loadHistory() {
loading.value = true
try {
const result = await apiCall('get_search_history', { limit: 50 })
const allHistory = Array.isArray(result) ? result : []
// Filter to last 2 hours (keep pinned items regardless of age)
const cutoffTime = Date.now() - (HISTORY_HOURS * 60 * 60 * 1000)
history.value = allHistory.filter((item: HistoryItem) => {
if (item.pinned) return true // Always keep pinned items
if (!item.updated_at) return false
const itemTime = new Date(item.updated_at).getTime()
return itemTime >= cutoffTime
})
// Clean up old unpinned items from database
cleanupOldHistory(cutoffTime)
} catch (e) {
console.error('Failed to load history:', e)
} finally {
loading.value = false
}
}
async function cleanupOldHistory(cutoffTime: number) {
try {
const result = await apiCall('get_search_history', { limit: 100 })
const allHistory = Array.isArray(result) ? result : []
for (const item of allHistory) {
if (item.pinned) continue
if (!item.updated_at) continue
const itemTime = new Date(item.updated_at).getTime()
if (itemTime < cutoffTime) {
await apiCall('delete_search_history', { id: item.id })
}
}
} catch (e) {
console.error('Failed to cleanup old history:', e)
}
}
async function saveToHistory(query: string, chatState: string, mode: string) {
const id = `h_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
try {
await apiCall('save_search_history', {
id,
query,
title: query,
chatState,
mode,
})
await loadHistory()
} catch (e) {
console.error('Failed to save history:', e)
}
}
async function renameHistory(id: string, title: string) {
try {
await apiCall('rename_search_history', { id, title })
await loadHistory()
} catch (e) {
console.error('Failed to rename history:', e)
}
}
async function pinHistory(id: string, pinned: boolean) {
try {
await apiCall('pin_search_history', { id, pinned })
await loadHistory()
} catch (e) {
console.error('Failed to pin history:', e)
}
}
async function deleteHistory(id: string) {
try {
await apiCall('delete_search_history', { id })
await loadHistory()
} catch (e) {
console.error('Failed to delete history:', e)
}
}
function restoreFromHistory(item: HistoryItem): any[] | null {
if (!item.chat_state) return null
try {
return JSON.parse(item.chat_state)
} catch {
return null
}
}
return {
history,
loading,
loadHistory,
saveToHistory,
renameHistory,
pinHistory,
deleteHistory,
restoreFromHistory,
}
}
export interface BookmarkItem {
id: number
label: string
history_id: string | null
created_at: string | null
}
export function useBookmarks() {
const bookmarks = ref<BookmarkItem[]>([])
async function loadBookmarks() {
try {
const result = await apiCall('get_bookmarks', {})
bookmarks.value = Array.isArray(result) ? result : []
} catch (e) {
console.error('Failed to load bookmarks:', e)
}
}
async function saveBookmark(label: string, historyId?: string) {
try {
await apiCall('save_bookmark', { label, historyId: historyId || null })
await loadBookmarks()
} catch (e) {
console.error('Failed to save bookmark:', e)
}
}
async function deleteBookmark(id: number) {
try {
await apiCall('delete_bookmark', { id })
await loadBookmarks()
} catch (e) {
console.error('Failed to delete bookmark:', e)
}
}
return {
bookmarks,
loadBookmarks,
saveBookmark,
deleteBookmark,
}
}