Session + message pagination, SVG favicon, load-more buttons
This commit is contained in:
@@ -25,7 +25,8 @@ export default function SessionReplayPage({ params }: { params: Promise<{ id: st
|
|||||||
const [editingTitle, setEditingTitle] = useState(false);
|
const [editingTitle, setEditingTitle] = useState(false);
|
||||||
const [titleDraft, setTitleDraft] = useState("");
|
const [titleDraft, setTitleDraft] = useState("");
|
||||||
const { data: sessionData } = useSession(id);
|
const { data: sessionData } = useSession(id);
|
||||||
const { data: messagesData, isLoading } = useMessages(id);
|
const [msgLimit, setMsgLimit] = useState(100);
|
||||||
|
const { data: messagesData, isLoading } = useMessages(id, msgLimit);
|
||||||
const [input, setInput] = useState("");
|
const [input, setInput] = useState("");
|
||||||
const [sending, setSending] = useState(false);
|
const [sending, setSending] = useState(false);
|
||||||
const [pendingMsg, setPendingMsg] = useState<string | null>(null);
|
const [pendingMsg, setPendingMsg] = useState<string | null>(null);
|
||||||
@@ -266,6 +267,17 @@ export default function SessionReplayPage({ params }: { params: Promise<{ id: st
|
|||||||
Empty session
|
Empty session
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Load more (at bottom = older messages since list is reversed) */}
|
||||||
|
{(messagesData?.total || 0) > msgLimit && (
|
||||||
|
<button
|
||||||
|
onClick={() => setMsgLimit((l) => l + 100)}
|
||||||
|
className="w-full py-3 mt-2 text-[13px] font-medium rounded-xl transition-colors"
|
||||||
|
style={{ color: "var(--accent)", background: "var(--accent-dim)" }}
|
||||||
|
>
|
||||||
|
Load older messages
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+12
-1
@@ -19,7 +19,9 @@ export default function HistoryPage() {
|
|||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [searching, setSearching] = useState(false);
|
const [searching, setSearching] = useState(false);
|
||||||
|
|
||||||
const { data: sessionsData, isLoading } = useSessions(30, filter || undefined);
|
const [limit, setLimit] = useState(20);
|
||||||
|
const { data: sessionsData, isLoading } = useSessions(limit, filter || undefined);
|
||||||
|
const hasMore = (sessionsData?.total || 0) > (sessionsData?.items?.length || 0);
|
||||||
const { data: searchData, isFetching: searchLoading } = useSessionSearch(searching ? query : "");
|
const { data: searchData, isFetching: searchLoading } = useSessionSearch(searching ? query : "");
|
||||||
const showSearch = searching && query.length >= 2;
|
const showSearch = searching && query.length >= 2;
|
||||||
|
|
||||||
@@ -107,6 +109,15 @@ export default function HistoryPage() {
|
|||||||
{sessionsData?.items?.length === 0 && (
|
{sessionsData?.items?.length === 0 && (
|
||||||
<p className="text-sm py-8 text-center" style={{ color: "var(--text-3)" }}>No sessions found</p>
|
<p className="text-sm py-8 text-center" style={{ color: "var(--text-3)" }}>No sessions found</p>
|
||||||
)}
|
)}
|
||||||
|
{hasMore && (
|
||||||
|
<button
|
||||||
|
onClick={() => setLimit((l) => l + 20)}
|
||||||
|
className="w-full py-3 mt-2 text-[13px] font-medium rounded-xl transition-colors"
|
||||||
|
style={{ color: "var(--accent)", background: "var(--accent-dim)" }}
|
||||||
|
>
|
||||||
|
Load more
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ import { ErrorBoundary } from "@/components/ErrorBoundary";
|
|||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Hermes OS",
|
title: "Hermes OS",
|
||||||
description: "Mobile dashboard for Hermes Agent",
|
description: "Mobile dashboard for Hermes Agent",
|
||||||
icons: { icon: "/icon-192.png", apple: "/icon-192.png" },
|
icons: { icon: "/favicon.svg", apple: "/icon-192.png" },
|
||||||
appleWebApp: { capable: true, statusBarStyle: "black-translucent", title: "Hermes" },
|
appleWebApp: { capable: true, statusBarStyle: "black-translucent", title: "Hermes" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -19,10 +19,10 @@ export function useSession(id: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMessages(sessionId: string) {
|
export function useMessages(sessionId: string, limit = 200) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["messages", sessionId],
|
queryKey: ["messages", sessionId, limit],
|
||||||
queryFn: () => api.fetchMessages(sessionId),
|
queryFn: () => api.fetchMessages(sessionId, limit),
|
||||||
enabled: !!sessionId,
|
enabled: !!sessionId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||||
|
<rect width="32" height="32" rx="8" fill="#111113"/>
|
||||||
|
<circle cx="16" cy="14" r="6" fill="none" stroke="#7c6ef0" stroke-width="2"/>
|
||||||
|
<path d="M12 22 L16 26 L20 22" fill="none" stroke="#7c6ef0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<circle cx="16" cy="14" r="2" fill="#7c6ef0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 380 B |
Reference in New Issue
Block a user