mirror of
https://github.com/stackblitz/bolt.new
synced 2024-11-27 14:32:46 +00:00
feat: navigate away when deleting current chat (#44)
This commit is contained in:
parent
1e11ab6395
commit
a7b1f5046d
@ -5,6 +5,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"playground:dev": "pnpm run --filter=playground dev",
|
"playground:dev": "pnpm run --filter=playground dev",
|
||||||
"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
|
"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
|
||||||
|
"lint:fix": "npm run lint -- --fix",
|
||||||
"build": "pnpm run -r build",
|
"build": "pnpm run -r build",
|
||||||
"test": "pnpm run -r test",
|
"test": "pnpm run -r test",
|
||||||
"typecheck": "pnpm run -r typecheck"
|
"typecheck": "pnpm run -r typecheck"
|
||||||
|
@ -3,6 +3,7 @@ import { ClientOnly } from 'remix-utils/client-only';
|
|||||||
import { chatStore } from '~/lib/stores/chat';
|
import { chatStore } from '~/lib/stores/chat';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { HeaderActionButtons } from './HeaderActionButtons.client';
|
import { HeaderActionButtons } from './HeaderActionButtons.client';
|
||||||
|
import { ChatDescription } from '~/lib/persistence/ChatDescription.client';
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const chat = useStore(chatStore);
|
const chat = useStore(chatStore);
|
||||||
@ -23,7 +24,9 @@ export function Header() {
|
|||||||
<span className="i-bolt:logo-text?mask w-[46px] inline-block" />
|
<span className="i-bolt:logo-text?mask w-[46px] inline-block" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1" />
|
<span className="flex-1 px-4 truncate text-center text-bolt-elements-textPrimary">
|
||||||
|
<ClientOnly>{() => <ChatDescription />}</ClientOnly>
|
||||||
|
</span>
|
||||||
{chat.started && (
|
{chat.started && (
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
{() => (
|
{() => (
|
||||||
|
@ -4,7 +4,7 @@ import { toast } from 'react-toastify';
|
|||||||
import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
|
import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
|
||||||
import { IconButton } from '~/components/ui/IconButton';
|
import { IconButton } from '~/components/ui/IconButton';
|
||||||
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
||||||
import { db, deleteId, getAll, type ChatHistoryItem } from '~/lib/persistence';
|
import { db, deleteById, getAll, chatId, type ChatHistoryItem } from '~/lib/persistence';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
import { logger } from '~/utils/logger';
|
import { logger } from '~/utils/logger';
|
||||||
import { HistoryItem } from './HistoryItem';
|
import { HistoryItem } from './HistoryItem';
|
||||||
@ -52,8 +52,15 @@ export function Menu() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
deleteId(db, item.id)
|
deleteById(db, item.id)
|
||||||
.then(() => loadEntries())
|
.then(() => {
|
||||||
|
loadEntries();
|
||||||
|
|
||||||
|
if (chatId.get() === item.id) {
|
||||||
|
// hard page navigation to clear the stores
|
||||||
|
window.location.pathname = '/';
|
||||||
|
}
|
||||||
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast.error('Failed to delete conversation');
|
toast.error('Failed to delete conversation');
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
import { useStore } from '@nanostores/react';
|
||||||
|
import { description } from './useChatHistory';
|
||||||
|
|
||||||
|
export function ChatDescription() {
|
||||||
|
return useStore(description);
|
||||||
|
}
|
@ -92,7 +92,7 @@ export async function getMessagesById(db: IDBDatabase, id: string): Promise<Chat
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteId(db: IDBDatabase, id: string): Promise<void> {
|
export async function deleteById(db: IDBDatabase, id: string): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const transaction = db.transaction('chats', 'readwrite');
|
const transaction = db.transaction('chats', 'readwrite');
|
||||||
const store = transaction.objectStore('chats');
|
const store = transaction.objectStore('chats');
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useLoaderData, useNavigate } from '@remix-run/react';
|
import { useLoaderData, useNavigate } from '@remix-run/react';
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { atom } from 'nanostores';
|
||||||
import type { Message } from 'ai';
|
import type { Message } from 'ai';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { AnalyticsAction, sendAnalyticsEvent } from '~/lib/analytics';
|
import { AnalyticsAction, sendAnalyticsEvent } from '~/lib/analytics';
|
||||||
import { workbenchStore } from '~/lib/stores/workbench';
|
import { workbenchStore } from '~/lib/stores/workbench';
|
||||||
@ -18,16 +19,16 @@ const persistenceEnabled = !import.meta.env.VITE_DISABLE_PERSISTENCE;
|
|||||||
|
|
||||||
export const db = persistenceEnabled ? await openDatabase() : undefined;
|
export const db = persistenceEnabled ? await openDatabase() : undefined;
|
||||||
|
|
||||||
|
export const chatId = atom<string | undefined>(undefined);
|
||||||
|
export const description = atom<string | undefined>(undefined);
|
||||||
|
|
||||||
export function useChatHistory() {
|
export function useChatHistory() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { id: mixedId } = useLoaderData<{ id?: string }>();
|
const { id: mixedId } = useLoaderData<{ id?: string }>();
|
||||||
|
|
||||||
const [chatId, setChatId] = useState(mixedId);
|
|
||||||
const [initialMessages, setInitialMessages] = useState<Message[]>([]);
|
const [initialMessages, setInitialMessages] = useState<Message[]>([]);
|
||||||
const [ready, setReady] = useState<boolean>(false);
|
const [ready, setReady] = useState<boolean>(false);
|
||||||
const [entryId, setEntryId] = useState<string | undefined>();
|
|
||||||
const [urlId, setUrlId] = useState<string | undefined>();
|
const [urlId, setUrlId] = useState<string | undefined>();
|
||||||
const [description, setDescription] = useState<string | undefined>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!db) {
|
if (!db) {
|
||||||
@ -40,14 +41,14 @@ export function useChatHistory() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chatId) {
|
if (mixedId) {
|
||||||
getMessages(db, chatId)
|
getMessages(db, mixedId)
|
||||||
.then((storedMessages) => {
|
.then((storedMessages) => {
|
||||||
if (storedMessages && storedMessages.messages.length > 0) {
|
if (storedMessages && storedMessages.messages.length > 0) {
|
||||||
setInitialMessages(storedMessages.messages);
|
setInitialMessages(storedMessages.messages);
|
||||||
setUrlId(storedMessages.urlId);
|
setUrlId(storedMessages.urlId);
|
||||||
setDescription(storedMessages.description);
|
description.set(storedMessages.description);
|
||||||
setChatId(storedMessages.id);
|
chatId.set(storedMessages.id);
|
||||||
} else {
|
} else {
|
||||||
navigate(`/`, { replace: true });
|
navigate(`/`, { replace: true });
|
||||||
}
|
}
|
||||||
@ -61,7 +62,7 @@ export function useChatHistory() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ready: !chatId || ready,
|
ready: !mixedId || ready,
|
||||||
initialMessages,
|
initialMessages,
|
||||||
storeMessageHistory: async (messages: Message[]) => {
|
storeMessageHistory: async (messages: Message[]) => {
|
||||||
if (!db || messages.length === 0) {
|
if (!db || messages.length === 0) {
|
||||||
@ -77,27 +78,21 @@ export function useChatHistory() {
|
|||||||
setUrlId(urlId);
|
setUrlId(urlId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!description && firstArtifact?.title) {
|
if (!description.get() && firstArtifact?.title) {
|
||||||
setDescription(firstArtifact?.title);
|
description.set(firstArtifact?.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initialMessages.length === 0) {
|
if (initialMessages.length === 0 && !chatId.get()) {
|
||||||
if (!entryId) {
|
const nextId = await getNextId(db);
|
||||||
const nextId = await getNextId(db);
|
|
||||||
|
|
||||||
await setMessages(db, nextId, messages, urlId, description);
|
chatId.set(nextId);
|
||||||
|
|
||||||
setEntryId(nextId);
|
if (!urlId) {
|
||||||
|
navigateChat(nextId);
|
||||||
if (!urlId) {
|
|
||||||
navigateChat(nextId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await setMessages(db, entryId, messages, urlId, description);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
await setMessages(db, chatId as string, messages, urlId, description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await setMessages(db, chatId.get() as string, messages, urlId, description.get());
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user