Wire up query history: localStorage session persistence + sidebar UI
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Plus,
|
||||
MessageSquare,
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
ShieldCheck,
|
||||
History,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@duoc-thu/ui";
|
||||
@@ -59,6 +60,12 @@ const QUICK_PROMPTS = [
|
||||
},
|
||||
];
|
||||
|
||||
interface HistoryItem {
|
||||
trace_id: string;
|
||||
query: string;
|
||||
decision: string;
|
||||
}
|
||||
|
||||
export function Sidebar({
|
||||
currentSessionId,
|
||||
sessions,
|
||||
@@ -70,6 +77,32 @@ export function Sidebar({
|
||||
}: SidebarProps) {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [isCollapsed, setIsCollapsed] = useState(false);
|
||||
const [historyItems, setHistoryItems] = useState<HistoryItem[]>([]);
|
||||
|
||||
// Feature-List #25: past queries FOR THIS SESSION, most recent first —
|
||||
// click one to re-run it (via `onQuickQuery`, same path the hardcoded
|
||||
// quick-prompts below already use). Deliberately re-fetched whenever the
|
||||
// active session changes, not lifted to page.tsx: `Composer.tsx`'s own
|
||||
// autocomplete fetch already establishes the pattern of a component
|
||||
// owning its own small read, rather than everything prop-drilled down.
|
||||
useEffect(() => {
|
||||
if (!currentSessionId) {
|
||||
setHistoryItems([]);
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
fetch(`/api/history?conversation_id=${encodeURIComponent(currentSessionId)}`)
|
||||
.then((res) => (res.ok ? res.json() : { items: [] }))
|
||||
.then((data) => {
|
||||
if (!cancelled) setHistoryItems(Array.isArray(data?.items) ? data.items : []);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setHistoryItems([]);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [currentSessionId]);
|
||||
|
||||
const filteredSessions = sessions.filter((s) =>
|
||||
s.title.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
@@ -204,6 +237,33 @@ export function Sidebar({
|
||||
})
|
||||
)}
|
||||
|
||||
{/* Query History — real past questions for this session (Feature-
|
||||
List #25), click to re-run the same question. Empty when the
|
||||
session has no persisted queries yet (a brand-new session, or
|
||||
history backend unavailable) — the quick-prompt templates below
|
||||
still work as a starting point either way. */}
|
||||
{historyItems.length > 0 && (
|
||||
<div className="pt-4 px-2 border-t border-border-subtle mt-4">
|
||||
<div className="pb-2 text-[0.68rem] font-bold tracking-wider text-txt-muted uppercase flex items-center gap-1">
|
||||
<History className="w-3 h-3 text-accent-primary" />
|
||||
<span>Lịch sử câu hỏi</span>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
{historyItems.map((item) => (
|
||||
<button
|
||||
key={item.trace_id}
|
||||
onClick={() => onQuickQuery(item.query)}
|
||||
title={item.query}
|
||||
className="w-full text-left p-2 rounded-xl bg-surface-elevated hover:bg-surface-hover border border-border-subtle text-txt-secondary hover:text-txt-primary text-[0.72rem] leading-snug transition-all flex items-center justify-between group"
|
||||
>
|
||||
<span className="truncate pr-1">{item.query}</span>
|
||||
<History className="w-3 h-3 text-accent-primary shrink-0 opacity-70 group-hover:opacity-100" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Quick Prompts Section */}
|
||||
<div className="pt-4 px-2 border-t border-border-subtle mt-4">
|
||||
<div className="pb-2 text-[0.68rem] font-bold tracking-wider text-txt-muted uppercase flex items-center gap-1">
|
||||
|
||||
Reference in New Issue
Block a user