Preserve draft views during collection refreshes
This commit is contained in:
@@ -93,6 +93,11 @@ type ActiveRunsState = {
|
||||
chats: Record<string, true>;
|
||||
searches: Record<string, true>;
|
||||
};
|
||||
type RefreshCollectionsOptions = {
|
||||
preferredSelection?: SidebarSelection;
|
||||
reportTransientError?: boolean;
|
||||
selectFallback?: boolean;
|
||||
};
|
||||
|
||||
function readSidebarSelectionFromUrl(): SidebarSelection | null {
|
||||
if (typeof window === "undefined") return null;
|
||||
@@ -1125,7 +1130,11 @@ export default function App() {
|
||||
resetWorkspaceState();
|
||||
};
|
||||
|
||||
const refreshCollections = async (preferredSelection?: SidebarSelection, reportTransientError = true) => {
|
||||
const refreshCollections = async ({
|
||||
preferredSelection,
|
||||
reportTransientError = true,
|
||||
selectFallback = false,
|
||||
}: RefreshCollectionsOptions = {}) => {
|
||||
setIsLoadingCollections(true);
|
||||
try {
|
||||
const nextWorkspaceItems = await listWorkspaceItems();
|
||||
@@ -1146,6 +1155,9 @@ export default function App() {
|
||||
if (hasItem(current)) {
|
||||
return current;
|
||||
}
|
||||
if (!selectFallback) {
|
||||
return null;
|
||||
}
|
||||
const first = nextWorkspaceItems[0];
|
||||
return first ? { kind: first.type, id: first.id } : null;
|
||||
});
|
||||
@@ -1242,7 +1254,12 @@ export default function App() {
|
||||
if (!isAuthenticated) return;
|
||||
const preferredSelection = initialRouteSelectionRef.current;
|
||||
initialRouteSelectionRef.current = null;
|
||||
void Promise.all([refreshCollections(preferredSelection ?? undefined), refreshModels(), refreshChatTools(), refreshActiveRuns()]);
|
||||
void Promise.all([
|
||||
refreshCollections({ preferredSelection: preferredSelection ?? undefined, selectFallback: true }),
|
||||
refreshModels(),
|
||||
refreshChatTools(),
|
||||
refreshActiveRuns(),
|
||||
]);
|
||||
}, [isAuthenticated]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -1269,8 +1286,8 @@ export default function App() {
|
||||
}
|
||||
setError((current) => (current && isRecoverableStreamDisconnect(new Error(current)) ? null : current));
|
||||
void refreshActiveRuns();
|
||||
void refreshCollections(selectedItemRef.current ?? undefined, false);
|
||||
const currentSelection = selectedItemRef.current;
|
||||
void refreshCollections({ reportTransientError: false });
|
||||
if (currentSelection?.kind === "chat") {
|
||||
void refreshChat(currentSelection.id);
|
||||
} else if (currentSelection?.kind === "search") {
|
||||
@@ -1385,10 +1402,18 @@ export default function App() {
|
||||
|
||||
const selectedKey = selectedItem ? `${selectedItem.kind}:${selectedItem.id}` : null;
|
||||
const transcriptViewKey = draftKind ? `draft:${draftKind}` : selectedKey ?? "empty";
|
||||
const selectedChatPendingState = selectedItem?.kind === "chat" ? pendingChatStates[selectedItem.id] ?? null : null;
|
||||
const selectedSearchRunState = selectedItem?.kind === "search" ? runningSearchStates[selectedItem.id] ?? null : null;
|
||||
const selectedChatIsActive = selectedItem?.kind === "chat" && (!!selectedChatPendingState || !!activeRuns.chats[selectedItem.id]);
|
||||
const selectedSearchIsActive = selectedItem?.kind === "search" && (!!selectedSearchRunState || !!activeRuns.searches[selectedItem.id]);
|
||||
const selectedChatPendingState =
|
||||
draftKind === null && selectedItem?.kind === "chat" ? pendingChatStates[selectedItem.id] ?? null : null;
|
||||
const selectedSearchRunState =
|
||||
draftKind === null && selectedItem?.kind === "search" ? runningSearchStates[selectedItem.id] ?? null : null;
|
||||
const selectedChatIsActive =
|
||||
draftKind === null &&
|
||||
selectedItem?.kind === "chat" &&
|
||||
(!!selectedChatPendingState || !!activeRuns.chats[selectedItem.id]);
|
||||
const selectedSearchIsActive =
|
||||
draftKind === null &&
|
||||
selectedItem?.kind === "search" &&
|
||||
(!!selectedSearchRunState || !!activeRuns.searches[selectedItem.id]);
|
||||
const isSearchMode = draftKind ? draftKind === "search" : selectedItem?.kind === "search";
|
||||
const isSearchRunning = !!selectedSearchIsActive;
|
||||
const isSendingActiveChat = draftKind !== "search" && !!selectedChatIsActive;
|
||||
@@ -1495,7 +1520,10 @@ export default function App() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const messages = selectedChat?.messages ?? [];
|
||||
const messages =
|
||||
draftKind === null && selectedItem?.kind === "chat" && selectedChat?.id === selectedItem.id
|
||||
? selectedChat.messages
|
||||
: [];
|
||||
|
||||
useEffect(() => {
|
||||
if (isSearchMode && pendingAttachments.length) {
|
||||
@@ -1602,6 +1630,7 @@ export default function App() {
|
||||
setError(null);
|
||||
setContextMenu(null);
|
||||
setDraftKind("chat");
|
||||
selectedItemRef.current = null;
|
||||
setSelectedItem(null);
|
||||
setSelectedChat(null);
|
||||
setSelectedSearch(null);
|
||||
@@ -1738,6 +1767,7 @@ export default function App() {
|
||||
setError(null);
|
||||
setContextMenu(null);
|
||||
setDraftKind("search");
|
||||
selectedItemRef.current = null;
|
||||
setSelectedItem(null);
|
||||
setSelectedChat(null);
|
||||
setSelectedSearch(null);
|
||||
@@ -2065,7 +2095,7 @@ export default function App() {
|
||||
} else {
|
||||
await deleteSearch(target.id);
|
||||
}
|
||||
await refreshCollections();
|
||||
await refreshCollections({ selectFallback: true });
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
if (message.includes("bearer token")) {
|
||||
@@ -2450,7 +2480,7 @@ export default function App() {
|
||||
|
||||
backgroundSuspendedChatStreamsRef.current.delete(chatId);
|
||||
const persistedChat = await retryAfterAppResume(() => getChat(chatId));
|
||||
await refreshCollections(target, false);
|
||||
await refreshCollections({ preferredSelection: target, reportTransientError: false });
|
||||
if (isCurrentSelection(target)) {
|
||||
setSelectedChat(persistedChat);
|
||||
setSelectedSearch(null);
|
||||
@@ -2664,7 +2694,7 @@ export default function App() {
|
||||
}
|
||||
}
|
||||
|
||||
await refreshCollections(target);
|
||||
await refreshCollections({ preferredSelection: target });
|
||||
return target;
|
||||
};
|
||||
|
||||
@@ -2783,7 +2813,7 @@ export default function App() {
|
||||
setSelectedChat(persistedChat);
|
||||
setSelectedSearch(null);
|
||||
}
|
||||
void refreshCollections(target);
|
||||
void refreshCollections({ preferredSelection: target });
|
||||
return;
|
||||
} catch (resumeError) {
|
||||
err = resumeError;
|
||||
@@ -2889,7 +2919,7 @@ export default function App() {
|
||||
{ signal: abortController.signal }
|
||||
);
|
||||
|
||||
await refreshCollections(target);
|
||||
await refreshCollections({ preferredSelection: target });
|
||||
if (isCurrentSelection(target)) {
|
||||
await refreshSearch(searchId);
|
||||
}
|
||||
@@ -2957,7 +2987,7 @@ export default function App() {
|
||||
messages: [],
|
||||
});
|
||||
setSelectedSearch(null);
|
||||
await refreshCollections({ kind: "chat", id: chat.id });
|
||||
await refreshCollections({ preferredSelection: { kind: "chat", id: chat.id } });
|
||||
await refreshChat(chat.id);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
@@ -3119,7 +3149,7 @@ export default function App() {
|
||||
messages: [],
|
||||
});
|
||||
setSelectedSearch(null);
|
||||
await refreshCollections({ kind: "chat", id: chat.id });
|
||||
await refreshCollections({ preferredSelection: { kind: "chat", id: chat.id } });
|
||||
await refreshChat(chat.id);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
|
||||
Reference in New Issue
Block a user