Skip to content

Commit 9daa72d

Browse files
committed
webui : fixed download-format, import of one conversation
1 parent a00837e commit 9daa72d

File tree

2 files changed

+27
-14
lines changed

2 files changed

+27
-14
lines changed

tools/server/webui/src/lib/components/app/chat/ChatSidebar/ChatSidebarActions.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { KeyboardShortcutInfo } from '$lib/components/app';
44
import { Button } from '$lib/components/ui/button';
55
import { Input } from '$lib/components/ui/input';
6-
import { exportAllConversations, importAllConversations } from '$lib/stores/chat.svelte';
6+
import { exportAllConversations, importConversations } from '$lib/stores/chat.svelte';
77
88
interface Props {
99
handleMobileSidebarItemClick: () => void;
@@ -97,7 +97,7 @@
9797
<Button
9898
class="w-full justify-start text-sm"
9999
onclick={() => {
100-
importAllConversations().catch(err => {
100+
importConversations().catch(err => {
101101
console.error('Import failed:', err);
102102
// Optional: show toast or dialog
103103
});

tools/server/webui/src/lib/stores/chat.svelte.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -964,15 +964,15 @@ class ChatStore {
964964

965965
const messages = await DatabaseStore.getConversationMessages(convId);
966966
const conversationData = {
967-
...conversation,
967+
conv: conversation,
968968
messages
969969
};
970970

971971
this.triggerDownload(conversationData);
972972
} else {
973973
// Use current active conversation data
974974
const conversationData = {
975-
...this.activeConversation,
975+
conv: this.activeConversation,
976976
messages: this.activeMessages
977977
};
978978

@@ -982,14 +982,16 @@ class ChatStore {
982982

983983
/**
984984
* Triggers file download in browser
985-
* @param data - Data to download
985+
* @param data - Data to download (expected: { conv: DatabaseConversation, messages: DatabaseMessage[] })
986986
* @param filename - Optional filename
987987
*/
988988
private triggerDownload(data: any, filename?: string): void {
989-
const conversationName = data.name || '';
989+
const conversation = data.conv || data;
990+
const conversationName = conversation.name ? conversation.name.trim() : '';
991+
const convId = conversation.id || 'unknown';
990992
const truncatedSuffix = conversationName.toLowerCase()
991993
.replace(/[^a-z0-9]/gi, '_').replace(/_+/g, '_').substring(0, 20);
992-
const downloadFilename = filename || `conversation_${data.id}_${truncatedSuffix}.json`;
994+
const downloadFilename = filename || `conversation_${convId}_${truncatedSuffix}.json`;
993995

994996
const conversationJson = JSON.stringify(data, null, 2);
995997
const blob = new Blob([conversationJson], {
@@ -1042,10 +1044,11 @@ class ChatStore {
10421044
}
10431045

10441046
/**
1045-
* Imports conversations from a JSON file
1047+
* Imports conversations from a JSON file.
1048+
* Supports both single conversation (object) and multiple conversations (array).
10461049
* Uses DatabaseStore for safe, encapsulated data access
10471050
*/
1048-
async importAllConversations(): Promise<void> {
1051+
async importConversations(): Promise<void> {
10491052
return new Promise((resolve, reject) => {
10501053
const input = document.createElement('input');
10511054
input.type = 'file';
@@ -1060,11 +1063,18 @@ class ChatStore {
10601063

10611064
try {
10621065
const text = await file.text();
1063-
const importedData: { conv: DatabaseConversation; messages: DatabaseMessage[] }[] =
1064-
JSON.parse(text);
1066+
const parsedData = JSON.parse(text);
10651067

1066-
if (!Array.isArray(importedData)) {
1067-
throw new Error('Invalid file format: expected array of conversations');
1068+
// Handle both single conversation object and array of conversations
1069+
let importedData: { conv: DatabaseConversation; messages: DatabaseMessage[] }[];
1070+
1071+
if (Array.isArray(parsedData)) {
1072+
importedData = parsedData;
1073+
} else if (parsedData && typeof parsedData === 'object' && 'conv' in parsedData && 'messages' in parsedData) {
1074+
// Single conversation object
1075+
importedData = [parsedData];
1076+
} else {
1077+
throw new Error('Invalid file format: expected array of conversations or single conversation object');
10681078
}
10691079

10701080
const result = await DatabaseStore.importConversations(importedData);
@@ -1078,6 +1088,9 @@ class ChatStore {
10781088
} catch (err: unknown) {
10791089
const message = err instanceof Error ? err.message : 'Unknown error';
10801090
console.error('Failed to import conversations:', err);
1091+
toast.error('Import failed', {
1092+
description: message
1093+
});
10811094
reject(new Error(`Import failed: ${message}`));
10821095
}
10831096
};
@@ -1564,7 +1577,7 @@ export const maxContextError = () => chatStore.maxContextError;
15641577
export const createConversation = chatStore.createConversation.bind(chatStore);
15651578
export const downloadConversation = chatStore.downloadConversation.bind(chatStore);
15661579
export const exportAllConversations = chatStore.exportAllConversations.bind(chatStore);
1567-
export const importAllConversations = chatStore.importAllConversations.bind(chatStore);
1580+
export const importConversations = chatStore.importConversations.bind(chatStore);
15681581
export const deleteConversation = chatStore.deleteConversation.bind(chatStore);
15691582
export const sendMessage = chatStore.sendMessage.bind(chatStore);
15701583
export const gracefulStop = chatStore.gracefulStop.bind(chatStore);

0 commit comments

Comments
 (0)