mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
Wrap database in async suspense value (#36)
This commit is contained in:
parent
12cd21f1d3
commit
6acb94b5af
@ -4,7 +4,6 @@ import { classNames } from '~/utils/classNames';
|
|||||||
import { AssistantMessage, getAnnotationsTokensUsage } from './AssistantMessage';
|
import { AssistantMessage, getAnnotationsTokensUsage } from './AssistantMessage';
|
||||||
import { UserMessage } from './UserMessage';
|
import { UserMessage } from './UserMessage';
|
||||||
import { useLocation } from '@remix-run/react';
|
import { useLocation } from '@remix-run/react';
|
||||||
import { db, chatId } from '~/lib/persistence/useChatHistory';
|
|
||||||
import { forkChat } from '~/lib/persistence/db';
|
import { forkChat } from '~/lib/persistence/db';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import WithTooltip from '~/components/ui/Tooltip';
|
import WithTooltip from '~/components/ui/Tooltip';
|
||||||
@ -29,7 +28,7 @@ export function saveProjectContents(messageId: string, contents: ProjectContents
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hasFileModifications(content: string) {
|
function hasFileModifications(content: string) {
|
||||||
return content.includes("__boltArtifact__");
|
return content.includes('__boltArtifact__');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Messages = React.forwardRef<HTMLDivElement, MessagesProps>((props: MessagesProps, ref) => {
|
export const Messages = React.forwardRef<HTMLDivElement, MessagesProps>((props: MessagesProps, ref) => {
|
||||||
@ -95,27 +94,27 @@ export const Messages = React.forwardRef<HTMLDivElement, MessagesProps>((props:
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!isUserMessage &&
|
{!isUserMessage &&
|
||||||
messageId &&
|
messageId &&
|
||||||
onRewind &&
|
onRewind &&
|
||||||
getLastMessageProjectContents(index) &&
|
getLastMessageProjectContents(index) &&
|
||||||
hasFileModifications(content) && (
|
hasFileModifications(content) && (
|
||||||
<div className="flex gap-2 flex-col lg:flex-row">
|
<div className="flex gap-2 flex-col lg:flex-row">
|
||||||
<WithTooltip tooltip="Undo changes in this message">
|
<WithTooltip tooltip="Undo changes in this message">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const info = getLastMessageProjectContents(index);
|
const info = getLastMessageProjectContents(index);
|
||||||
assert(info);
|
assert(info);
|
||||||
onRewind(info.messageId, info.contents.content);
|
onRewind(info.messageId, info.contents.content);
|
||||||
}}
|
}}
|
||||||
key="i-ph:arrow-u-up-left"
|
key="i-ph:arrow-u-up-left"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'i-ph:arrow-u-up-left',
|
'i-ph:arrow-u-up-left',
|
||||||
'text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors',
|
'text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</WithTooltip>
|
</WithTooltip>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
|||||||
import { useNavigate } from '@remix-run/react';
|
import { useNavigate } from '@remix-run/react';
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { db, deleteById, getAll, setMessages } from '~/lib/persistence';
|
import { database, deleteById, getAll, setMessages } from '~/lib/persistence';
|
||||||
import { logStore } from '~/lib/stores/logs';
|
import { logStore } from '~/lib/stores/logs';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import type { Message } from 'ai';
|
import type { Message } from 'ai';
|
||||||
@ -31,6 +31,7 @@ interface ApiKeys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function DataTab() {
|
export default function DataTab() {
|
||||||
|
const db = database?.read();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from
|
|||||||
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
||||||
import { SettingsWindow } from '~/components/settings/SettingsWindow';
|
import { SettingsWindow } from '~/components/settings/SettingsWindow';
|
||||||
import { SettingsButton } from '~/components/ui/SettingsButton';
|
import { SettingsButton } from '~/components/ui/SettingsButton';
|
||||||
import { db, deleteById, getAll, chatId, type ChatHistoryItem, useChatHistory } from '~/lib/persistence';
|
import { database, deleteById, getAll, chatId, type ChatHistoryItem, useChatHistory } 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';
|
||||||
@ -39,6 +39,7 @@ const menuVariants = {
|
|||||||
type DialogContent = { type: 'delete'; item: ChatHistoryItem } | null;
|
type DialogContent = { type: 'delete'; item: ChatHistoryItem } | null;
|
||||||
|
|
||||||
export const Menu = () => {
|
export const Menu = () => {
|
||||||
|
const db = database?.read();
|
||||||
const { duplicateCurrentChat, exportChat } = useChatHistory();
|
const { duplicateCurrentChat, exportChat } = useChatHistory();
|
||||||
const menuRef = useRef<HTMLDivElement>(null);
|
const menuRef = useRef<HTMLDivElement>(null);
|
||||||
const [list, setList] = useState<ChatHistoryItem[]>([]);
|
const [list, setList] = useState<ChatHistoryItem[]>([]);
|
||||||
|
@ -32,6 +32,21 @@ export function createAsyncSuspenseValue<T>(getValue: () => Promise<T>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const asyncValue = {
|
const asyncValue = {
|
||||||
|
load: async () => {
|
||||||
|
if (!record) {
|
||||||
|
return load();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (record.status) {
|
||||||
|
case 'pending':
|
||||||
|
return record.promise;
|
||||||
|
case 'resolved':
|
||||||
|
return record.value;
|
||||||
|
case 'rejected':
|
||||||
|
throw record.error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
read() {
|
read() {
|
||||||
if (!record) {
|
if (!record) {
|
||||||
throw load();
|
throw load();
|
||||||
|
@ -3,7 +3,7 @@ import { useCallback, useEffect, useState } from 'react';
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import {
|
import {
|
||||||
chatId as chatIdStore,
|
chatId as chatIdStore,
|
||||||
db,
|
database,
|
||||||
description as descriptionStore,
|
description as descriptionStore,
|
||||||
getMessages,
|
getMessages,
|
||||||
updateChatDescription,
|
updateChatDescription,
|
||||||
@ -44,6 +44,7 @@ export function useEditChatDescription({
|
|||||||
customChatId,
|
customChatId,
|
||||||
syncWithGlobalStore,
|
syncWithGlobalStore,
|
||||||
}: EditChatDescriptionOptions): EditChatDescriptionHook {
|
}: EditChatDescriptionOptions): EditChatDescriptionHook {
|
||||||
|
const db = database?.read();
|
||||||
const chatIdFromStore = useStore(chatIdStore);
|
const chatIdFromStore = useStore(chatIdStore);
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
const [currentDescription, setCurrentDescription] = useState(initialDescription);
|
const [currentDescription, setCurrentDescription] = useState(initialDescription);
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
createChatFromMessages,
|
createChatFromMessages,
|
||||||
} from './db';
|
} from './db';
|
||||||
import { loadProblem } from '~/components/chat/LoadProblemButton';
|
import { loadProblem } from '~/components/chat/LoadProblemButton';
|
||||||
|
import { createAsyncSuspenseValue } from '../asyncSuspenseValue';
|
||||||
|
|
||||||
export interface ChatHistoryItem {
|
export interface ChatHistoryItem {
|
||||||
id: string;
|
id: string;
|
||||||
@ -26,14 +27,19 @@ export interface ChatHistoryItem {
|
|||||||
|
|
||||||
const persistenceEnabled = !import.meta.env.VITE_DISABLE_PERSISTENCE;
|
const persistenceEnabled = !import.meta.env.VITE_DISABLE_PERSISTENCE;
|
||||||
|
|
||||||
export const db = persistenceEnabled ? await openDatabase() : undefined;
|
export const database = persistenceEnabled ? createAsyncSuspenseValue(openDatabase) : undefined;
|
||||||
|
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
database?.preload();
|
||||||
|
}
|
||||||
|
|
||||||
export const chatId = atom<string | undefined>(undefined);
|
export const chatId = atom<string | undefined>(undefined);
|
||||||
export const description = atom<string | undefined>(undefined);
|
export const description = atom<string | undefined>(undefined);
|
||||||
|
|
||||||
export function useChatHistory() {
|
export function useChatHistory() {
|
||||||
|
const db = database?.read();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { id: mixedId, problemId } = useLoaderData<{ id?: string, problemId?: string }>() ?? {};
|
const { id: mixedId, problemId } = useLoaderData<{ id?: string; problemId?: string }>() ?? {};
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
const [initialMessages, setInitialMessages] = useState<Message[]>([]);
|
const [initialMessages, setInitialMessages] = useState<Message[]>([]);
|
||||||
|
Loading…
Reference in New Issue
Block a user