New front-end Launch Chat API Manage Sources Enable re-embedding of all contents Sources can be added without a notebook now Improved settings Enable model selector on all chats Background processing for better experience Dark mode Improved Notes Improved Docs: - Remove all Streamlit references from documentation - Update deployment guides with React frontend setup - Fix Docker environment variables format (SURREAL_URL, SURREAL_PASSWORD) - Update docker image tag from :latest to :v1-latest - Change navigation references (Settings → Models to just Models) - Update development setup to include frontend npm commands - Add MIGRATION.md guide for users upgrading from Streamlit - Update quick-start guide with correct environment variables - Add port 5055 documentation for API access - Update project structure to reflect frontend/ directory - Remove outdated source-chat documentation files
121 lines
3.4 KiB
TypeScript
121 lines
3.4 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog'
|
|
import { Button } from '@/components/ui/button'
|
|
import { CheckboxList } from '@/components/ui/checkbox-list'
|
|
import { useNotebooks } from '@/lib/hooks/use-notebooks'
|
|
import { useCreateNote } from '@/lib/hooks/use-notes'
|
|
import { LoadingSpinner } from '@/components/common/LoadingSpinner'
|
|
import { toast } from 'sonner'
|
|
|
|
interface SaveToNotebooksDialogProps {
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
question: string
|
|
answer: string
|
|
}
|
|
|
|
export function SaveToNotebooksDialog({
|
|
open,
|
|
onOpenChange,
|
|
question,
|
|
answer
|
|
}: SaveToNotebooksDialogProps) {
|
|
const [selectedNotebooks, setSelectedNotebooks] = useState<string[]>([])
|
|
const { data: notebooks, isLoading } = useNotebooks(false) // false = not archived
|
|
const createNote = useCreateNote()
|
|
|
|
const handleToggle = (notebookId: string) => {
|
|
setSelectedNotebooks(prev =>
|
|
prev.includes(notebookId)
|
|
? prev.filter(id => id !== notebookId)
|
|
: [...prev, notebookId]
|
|
)
|
|
}
|
|
|
|
const handleSave = async () => {
|
|
if (selectedNotebooks.length === 0) {
|
|
toast.error('Please select at least one notebook')
|
|
return
|
|
}
|
|
|
|
try {
|
|
// Create note in each selected notebook
|
|
for (const notebookId of selectedNotebooks) {
|
|
await createNote.mutateAsync({
|
|
title: question,
|
|
content: answer,
|
|
note_type: 'ai',
|
|
notebook_id: notebookId
|
|
})
|
|
}
|
|
|
|
toast.success(`Answer saved to ${selectedNotebooks.length} notebook${selectedNotebooks.length > 1 ? 's' : ''}`)
|
|
setSelectedNotebooks([])
|
|
onOpenChange(false)
|
|
} catch {
|
|
toast.error('Failed to save answer')
|
|
}
|
|
}
|
|
|
|
const notebookItems = notebooks?.map(nb => ({
|
|
id: nb.id,
|
|
title: nb.name,
|
|
description: nb.description || undefined
|
|
})) || []
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-[500px]">
|
|
<DialogHeader>
|
|
<DialogTitle>Save to Notebooks</DialogTitle>
|
|
<DialogDescription>
|
|
Select one or more notebooks to save this answer
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="py-4">
|
|
{isLoading ? (
|
|
<div className="flex items-center justify-center py-8">
|
|
<LoadingSpinner />
|
|
</div>
|
|
) : (
|
|
<CheckboxList
|
|
items={notebookItems}
|
|
selectedIds={selectedNotebooks}
|
|
onToggle={handleToggle}
|
|
emptyMessage="No notebooks found. Create a notebook first."
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
onClick={handleSave}
|
|
disabled={selectedNotebooks.length === 0 || createNote.isPending}
|
|
>
|
|
{createNote.isPending ? (
|
|
<>
|
|
<LoadingSpinner size="sm" className="mr-2" />
|
|
Saving...
|
|
</>
|
|
) : (
|
|
`Save to ${selectedNotebooks.length || ''} Notebook${selectedNotebooks.length !== 1 ? 's' : ''}`
|
|
)}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|