Conversations
@@ -77,8 +119,11 @@ export default function Sidebar() {
navigate(`/chat/${conv.id}`)}
dir="auto"
@@ -86,9 +131,30 @@ export default function Sidebar() {
{conv.name}
))}
-
+
Conversations are saved to browser's IndexedDB
+ {/* Clear All Button - Added */}
+ {conversations.length > 0 && ( // Only show if there are conversations to clear
+
+ )}
>
diff --git a/examples/server/webui/src/utils/app.context.tsx b/examples/server/webui/src/utils/app.context.tsx
index 54bb65b6e3cb2..df641aa1502ba 100644
--- a/examples/server/webui/src/utils/app.context.tsx
+++ b/examples/server/webui/src/utils/app.context.tsx
@@ -89,16 +89,22 @@ export const AppContextProvider = ({
useEffect(() => {
// also reset the canvas data
setCanvasData(null);
- const handleConversationChange = async (changedConvId: string) => {
- if (changedConvId !== convId) return;
- setViewingChat(await getViewingChat(changedConvId));
+ const handleConversationChange = async (changedConvId: string | null) => {
+ // Refresh if the change affects the current viewing conversation OR if all conversations were cleared (null)
+ if (changedConvId === convId || changedConvId === null) {
+ // Re-fetch data for the current URL's convId (which might be undefined now)
+ const currentUrlConvId = params?.params?.convId;
+ // Ensure getViewingChat can handle potential undefined/null input if needed, or provide fallback like ''
+ setViewingChat(await getViewingChat(currentUrlConvId ?? '')); // Use currentUrlConvId
+ }
+ // Otherwise, ignore changes for conversations not being viewed.
};
StorageUtils.onConversationChanged(handleConversationChange);
getViewingChat(convId ?? '').then(setViewingChat);
return () => {
StorageUtils.offConversationChanged(handleConversationChange);
};
- }, [convId]);
+ }, [convId, params?.params?.convId]);
const setPending = (convId: string, pendingMsg: PendingMessage | null) => {
// if pendingMsg is null, remove the key from the object
diff --git a/examples/server/webui/src/utils/storage.ts b/examples/server/webui/src/utils/storage.ts
index 1dfc9d9799311..2eff4d74a70e7 100644
--- a/examples/server/webui/src/utils/storage.ts
+++ b/examples/server/webui/src/utils/storage.ts
@@ -6,13 +6,13 @@ import { Conversation, Message, TimingReport } from './types';
import Dexie, { Table } from 'dexie';
const event = new EventTarget();
-
-type CallbackConversationChanged = (convId: string) => void;
+// Modify callback type to accept null for "clear all" events
+type CallbackConversationChanged = (convId: string | null) => void;
let onConversationChangedHandlers: [
CallbackConversationChanged,
EventListener,
][] = [];
-const dispatchConversationChange = (convId: string) => {
+const dispatchConversationChange = (convId: string | null) => {
event.dispatchEvent(
new CustomEvent('conversationChange', { detail: { convId } })
);
@@ -167,18 +167,43 @@ const StorageUtils = {
dispatchConversationChange(convId);
},
+ /**
+ * Added function to clear all conversation data.
+ */
+ async clearAllConversations(): Promise
{
+ try {
+ await db.transaction('rw', db.conversations, db.messages, async () => {
+ await db.conversations.clear(); // Clear conversations table
+ await db.messages.clear(); // Clear messages table
+ });
+ console.log('All conversations cleared.');
+ // Dispatch change with null to indicate everything was cleared
+ dispatchConversationChange(null);
+ } catch (error) {
+ console.error('Failed to clear all conversations:', error);
+ throw error; // Re-throw error for potential handling by the caller
+ }
+ },
+
// event listeners
onConversationChanged(callback: CallbackConversationChanged) {
- const fn = (e: Event) => callback((e as CustomEvent).detail.convId);
+ // Ensure the event listener correctly handles the detail (string | null)
+ const fn = (e: Event) =>
+ callback((e as CustomEvent).detail.convId as string | null);
onConversationChangedHandlers.push([callback, fn]);
event.addEventListener('conversationChange', fn);
},
offConversationChanged(callback: CallbackConversationChanged) {
- const fn = onConversationChangedHandlers.find(([cb, _]) => cb === callback);
- if (fn) {
- event.removeEventListener('conversationChange', fn[1]);
+ const handlerTuple = onConversationChangedHandlers.find(
+ ([cb]) => cb === callback
+ );
+ if (handlerTuple) {
+ event.removeEventListener('conversationChange', handlerTuple[1]);
+ // Filter out the specific handler, don't reset the whole array
+ onConversationChangedHandlers = onConversationChangedHandlers.filter(
+ (tuple) => tuple[0] !== callback
+ );
}
- onConversationChangedHandlers = [];
},
// manage config