mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-05 08:06:19 +00:00
feat: add Save to Space button in Nova chat UI
Add a 'Save to [space name]' button in the ChatSidebar component:
- saveState useState to track idle/saving/saved states
- useEffect to reset saveState to idle when new assistant messages arrive
- handleSaveToSpace callback that POSTs to /chat/save-as-document endpoint
- Save button rendered in chatToolbarActions, visible only when messages
exist and not in auto-space mode
The button shows contextual text: 'Save to {space}', 'Saving...', or
'Saved to space' based on the current save state.
This commit is contained in:
parent
ed809b26f9
commit
5cf4da0814
1 changed files with 50 additions and 0 deletions
|
|
@ -143,6 +143,9 @@ export function ChatSidebar({
|
|||
const [confirmingDeleteId, setConfirmingDeleteId] = useState<string | null>(
|
||||
null,
|
||||
)
|
||||
const [saveState, setSaveState] = useState<"idle" | "saving" | "saved">(
|
||||
"idle",
|
||||
)
|
||||
const messagesContainerRef = useRef<HTMLDivElement>(null)
|
||||
const isScrolledToBottomRef = useRef(true)
|
||||
const userJustSentRef = useRef(false)
|
||||
|
|
@ -428,6 +431,39 @@ export function ChatSidebar({
|
|||
setInput("")
|
||||
}, [setThreadId, setMessages])
|
||||
|
||||
// Reset saveState to idle when a new assistant message arrives
|
||||
const lastMessageRole = messages.at(-1)?.role
|
||||
useEffect(() => {
|
||||
if (lastMessageRole === "assistant") {
|
||||
setSaveState("idle")
|
||||
}
|
||||
}, [messages.length, lastMessageRole])
|
||||
|
||||
const handleSaveToSpace = useCallback(async () => {
|
||||
if (saveState !== "idle" || messages.length === 0) return
|
||||
setSaveState("saving")
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_BACKEND_URL}/chat/save-as-document`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
chatId: currentChatId,
|
||||
projectId: chatProject,
|
||||
messages,
|
||||
}),
|
||||
},
|
||||
)
|
||||
if (!response.ok) throw new Error("Save failed")
|
||||
setSaveState("saved")
|
||||
} catch (error) {
|
||||
console.error("Failed to save chat:", error)
|
||||
setSaveState("idle")
|
||||
}
|
||||
}, [saveState, messages, currentChatId, chatProject])
|
||||
|
||||
const fetchThreads = useCallback(async () => {
|
||||
setIsLoadingThreads(true)
|
||||
try {
|
||||
|
|
@ -905,6 +941,20 @@ export function ChatSidebar({
|
|||
|
||||
const chatToolbarActions = (
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
{messages.length > 0 && !isAutoChatSpace && (
|
||||
<button
|
||||
type="button"
|
||||
disabled={saveState === "saving"}
|
||||
onClick={handleSaveToSpace}
|
||||
className="text-xs text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50"
|
||||
>
|
||||
{saveState === "saving"
|
||||
? "Saving..."
|
||||
: saveState === "saved"
|
||||
? "Saved to space"
|
||||
: `Save to ${chatSpaceLabel}`}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsHistoryOpen(true)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue