Fix review cycle 2 findings

- thread-sidebar: use callback-based modify+delete in handleDeleteFolder
  to properly clear folderId (Dexie ignores undefined in object-form modify)
- chat-page: clear artifact store on compare enter/exit/new transitions
- artifact-panel: remove redundant viewedContent from useEffect deps to
  prevent unnecessary re-syncs during store updates
- db.ts: use toArray()+sort() instead of sortBy() inside upgrade transaction
  for better Dexie compatibility
- thread-export: prefer modelType over modelId for compare-export filename
  suffix to differentiate LoRA compare pairs
This commit is contained in:
Daniel Han 2026-03-31 11:46:54 +00:00
commit d26c56a43b
5 changed files with 13 additions and 5 deletions

View file

@ -537,6 +537,7 @@ export function ChatPage(): ReactElement {
);
const handleNewCompare = useCallback(
() => {
useArtifactStore.getState().clearArtifacts();
setView({ mode: "compare", pairId: crypto.randomUUID() });
useChatRuntimeStore.getState().setContextUsage(null);
},
@ -565,6 +566,7 @@ export function ChatPage(): ReactElement {
const openSidebar = useCallback(() => setSidebarOpen(true), []);
const enterCompare = useCallback(() => {
useArtifactStore.getState().clearArtifacts();
setViewBeforeCompare((prev) => prev ?? view);
setView({ mode: "compare", pairId: crypto.randomUUID() });
useChatRuntimeStore.getState().setContextUsage(null);
@ -572,6 +574,7 @@ export function ChatPage(): ReactElement {
const exitCompare = useCallback(() => {
if (!viewBeforeCompare) return;
useArtifactStore.getState().clearArtifacts();
setView(viewBeforeCompare);
setViewBeforeCompare(null);
// Restore context usage from the active thread's last assistant message

View file

@ -74,8 +74,10 @@ export const ArtifactPanel: FC = () => {
// Sync local editor value when switching artifacts or versions
useEffect(() => {
if (active) setLocalValue(viewedContent);
}, [active?.id, active?.activeVersion, viewedContent]);
if (!active) return;
setLocalValue(active.history[active.activeVersion] ?? active.content);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [active?.id, active?.activeVersion]);
// Cleanup copy timer on unmount
useEffect(() => {

View file

@ -62,7 +62,8 @@ db.version(4)
.table("messages")
.where("threadId")
.equals(thread.id)
.sortBy("createdAt");
.toArray();
msgs.sort((a: MessageRecord, b: MessageRecord) => a.createdAt - b.createdAt);
const firstUser = msgs.find(
(m: MessageRecord) => m.role === "user",
);

View file

@ -102,7 +102,7 @@ function buildExportFilename(
): string {
const base = sanitizeFilename(thread.title);
const suffix = thread.pairId
? `_${sanitizeFilename(thread.modelId || thread.modelType || "compare")}`
? `_${sanitizeFilename(thread.modelType || thread.modelId || "compare")}`
: "";
return `${base}${suffix}.${ext}`;
}

View file

@ -245,7 +245,9 @@ export function ThreadSidebar({
const handleDeleteFolder = useCallback(async (folderId: string) => {
await db.transaction("rw", db.threads, db.folders, async () => {
await db.threads.where("folderId").equals(folderId).modify({ folderId: undefined });
await db.threads.where("folderId").equals(folderId).modify((thread) => {
delete thread.folderId;
});
await db.folders.delete(folderId);
});
}, []);