feat(chat): add conversation import from JSON (M8.8)
Import AIUI JSON exports and Claude.ai export format via file picker. Merges imported conversations into existing data without overwriting. Shows import summary with count and format detected. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
6182adb01c
commit
37e8aec920
@@ -191,6 +191,12 @@
|
||||
Plain text (.txt)
|
||||
</button>
|
||||
<div class="border-t border-white/10 mt-1 pt-1">
|
||||
<button
|
||||
class="w-full text-left px-3 py-2 rounded-lg text-xs text-white/60 hover:text-white hover:bg-white/10 transition-all"
|
||||
@click="triggerImport"
|
||||
>
|
||||
Import conversations
|
||||
</button>
|
||||
<button
|
||||
class="w-full text-left px-3 py-2 rounded-lg text-xs text-red-400/80 hover:text-red-400 hover:bg-white/10 transition-all"
|
||||
@click="handleDelete"
|
||||
@@ -201,6 +207,23 @@
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
|
||||
<input
|
||||
ref="importInputRef"
|
||||
type="file"
|
||||
accept=".json"
|
||||
class="hidden"
|
||||
@change="handleImportFile"
|
||||
/>
|
||||
|
||||
<!-- Import status -->
|
||||
<div
|
||||
v-if="importStatus"
|
||||
class="absolute top-full left-3 right-3 mt-1 z-[100] glass px-3 py-2 rounded-lg text-xs animate-fade-up-fast"
|
||||
:class="importStatus.startsWith('Error') ? 'text-red-400' : 'text-accent'"
|
||||
>
|
||||
{{ importStatus }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -210,6 +233,7 @@ import { useChatStore } from '@/stores/chat'
|
||||
import { useAI } from '@/composables/useAI'
|
||||
import { useContentPanel } from '@/composables/useContentPanel'
|
||||
import { downloadConversation, type ExportFormat } from '@/utils/conversation-export'
|
||||
import { parseImportFile } from '@/utils/conversation-import'
|
||||
|
||||
defineProps<{
|
||||
title: string
|
||||
@@ -330,6 +354,44 @@ function handleDelete() {
|
||||
chatStore.deleteConversation(id)
|
||||
showMenu.value = false
|
||||
}
|
||||
|
||||
const importInputRef = ref<HTMLInputElement | null>(null)
|
||||
const importStatus = ref<string | null>(null)
|
||||
|
||||
function triggerImport() {
|
||||
showMenu.value = false
|
||||
importInputRef.value?.click()
|
||||
}
|
||||
|
||||
async function handleImportFile(e: Event) {
|
||||
const input = e.target as HTMLInputElement
|
||||
const file = input.files?.[0]
|
||||
if (!file) return
|
||||
|
||||
try {
|
||||
const text = await file.text()
|
||||
const result = parseImportFile(text)
|
||||
|
||||
if (result.error || result.conversations.length === 0) {
|
||||
importStatus.value = `Error: ${result.error ?? 'No conversations found'}`
|
||||
} else {
|
||||
for (const conv of result.conversations) {
|
||||
chatStore.conversations.set(conv.id, conv)
|
||||
}
|
||||
const count = result.conversations.length
|
||||
importStatus.value = `Imported ${count} conversation${count > 1 ? 's' : ''} (${result.format})`
|
||||
// Switch to first imported conversation
|
||||
chatStore.setActiveConversation(result.conversations[0].id)
|
||||
}
|
||||
} catch {
|
||||
importStatus.value = 'Error: Failed to read file'
|
||||
}
|
||||
|
||||
// Clear file input for re-use
|
||||
input.value = ''
|
||||
// Auto-hide status after 3 seconds
|
||||
setTimeout(() => { importStatus.value = null }, 3000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user