url and history

This commit is contained in:
2026-02-15 22:57:10 -08:00
parent cec7d902be
commit 22d2509d0e

View File

@@ -48,6 +48,32 @@ type ContextMenuState = {
y: number;
};
function readSidebarSelectionFromUrl(): SidebarSelection | null {
if (typeof window === "undefined") return null;
const params = new URLSearchParams(window.location.search);
const chatId = params.get("chat")?.trim();
if (chatId) {
return { kind: "chat", id: chatId };
}
const searchId = params.get("search")?.trim();
if (searchId) {
return { kind: "search", id: searchId };
}
return null;
}
function buildWorkspaceUrl(selection: SidebarSelection | null) {
if (typeof window === "undefined") return "/";
const params = new URLSearchParams(window.location.search);
params.delete("chat");
params.delete("search");
if (selection) {
params.set(selection.kind === "chat" ? "chat" : "search", selection.id);
}
const query = params.toString();
return `${window.location.pathname}${query ? `?${query}` : ""}`;
}
const PROVIDER_FALLBACK_MODELS: Record<Provider, string[]> = {
openai: ["gpt-4.1-mini"],
anthropic: ["claude-3-5-sonnet-latest"],
@@ -302,6 +328,8 @@ export default function App() {
const searchRunCounterRef = useRef(0);
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
const initialRouteSelectionRef = useRef<SidebarSelection | null>(readSidebarSelectionFromUrl());
const hasSyncedSelectionHistoryRef = useRef(false);
useEffect(() => {
if (typeof document === "undefined") return;
@@ -417,9 +445,43 @@ export default function App() {
useEffect(() => {
if (!isAuthenticated) return;
void Promise.all([refreshCollections(), refreshModels()]);
const preferredSelection = initialRouteSelectionRef.current;
initialRouteSelectionRef.current = null;
void Promise.all([refreshCollections(preferredSelection ?? undefined), refreshModels()]);
}, [isAuthenticated]);
useEffect(() => {
const onPopState = () => {
setContextMenu(null);
setDraftKind(null);
setSelectedItem(readSidebarSelectionFromUrl());
setIsMobileSidebarOpen(false);
};
window.addEventListener("popstate", onPopState);
return () => window.removeEventListener("popstate", onPopState);
}, []);
useEffect(() => {
if (!isAuthenticated) {
hasSyncedSelectionHistoryRef.current = false;
return;
}
const current = `${window.location.pathname}${window.location.search}`;
const next = buildWorkspaceUrl(selectedItem);
if (!hasSyncedSelectionHistoryRef.current) {
hasSyncedSelectionHistoryRef.current = true;
if (current !== next) {
window.history.replaceState({}, "", next);
}
return;
}
if (current !== next) {
window.history.pushState({}, "", next);
}
}, [isAuthenticated, selectedItem]);
const providerModelOptions = useMemo(() => getModelOptions(modelCatalog, provider), [modelCatalog, provider]);
useEffect(() => {