mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-11 20:05:25 +00:00
fix: Move search mode selection into a cookie to avoid SSR flashes
This commit is contained in:
parent
eb04422b9f
commit
11099695da
6 changed files with 37 additions and 9 deletions
|
|
@ -25,7 +25,7 @@ import { auth } from "./auth";
|
||||||
import { getConnection } from "./data/connection";
|
import { getConnection } from "./data/connection";
|
||||||
import { IS_BILLING_ENABLED } from "./ee/features/billing/stripe";
|
import { IS_BILLING_ENABLED } from "./ee/features/billing/stripe";
|
||||||
import InviteUserEmail from "./emails/inviteUserEmail";
|
import InviteUserEmail from "./emails/inviteUserEmail";
|
||||||
import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, SINGLE_TENANT_ORG_DOMAIN, SOURCEBOT_GUEST_USER_ID, SOURCEBOT_SUPPORT_EMAIL } from "./lib/constants";
|
import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, SEARCH_MODE_COOKIE_NAME, SINGLE_TENANT_ORG_DOMAIN, SOURCEBOT_GUEST_USER_ID, SOURCEBOT_SUPPORT_EMAIL } from "./lib/constants";
|
||||||
import { orgDomainSchema, orgNameSchema, repositoryQuerySchema } from "./lib/schemas";
|
import { orgDomainSchema, orgNameSchema, repositoryQuerySchema } from "./lib/schemas";
|
||||||
import { TenancyMode, ApiKeyPayload } from "./lib/types";
|
import { TenancyMode, ApiKeyPayload } from "./lib/types";
|
||||||
import { decrementOrgSeatCount, getSubscriptionForOrg } from "./ee/features/billing/serverUtils";
|
import { decrementOrgSeatCount, getSubscriptionForOrg } from "./ee/features/billing/serverUtils";
|
||||||
|
|
@ -1998,6 +1998,13 @@ export const setAnonymousAccessStatus = async (domain: string, enabled: boolean)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export async function setSearchModeCookie(searchMode: "precise" | "agentic") {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
cookieStore.set(SEARCH_MODE_COOKIE_NAME, searchMode, {
|
||||||
|
httpOnly: false, // Allow client-side access
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
////// Helpers ///////
|
////// Helpers ///////
|
||||||
|
|
||||||
const parseConnectionConfig = (config: string) => {
|
const parseConnectionConfig = (config: string) => {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export const NewChatPanel = ({
|
||||||
repos,
|
repos,
|
||||||
order,
|
order,
|
||||||
}: NewChatPanelProps) => {
|
}: NewChatPanelProps) => {
|
||||||
const [selectedRepos, setSelectedRepos] = useLocalStorage<string[]>("selectedRepos", []);
|
const [selectedRepos, setSelectedRepos] = useLocalStorage<string[]>("selectedRepos", [], { initializeWithValue: false });
|
||||||
const { createNewChatThread, isLoading } = useCreateNewChatThread();
|
const { createNewChatThread, isLoading } = useCreateNewChatThread();
|
||||||
const [isRepoSelectorOpen, setIsRepoSelectorOpen] = useState(false);
|
const [isRepoSelectorOpen, setIsRepoSelectorOpen] = useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ export const AgenticSearch = ({
|
||||||
const { createNewChatThread, isLoading } = useCreateNewChatThread();
|
const { createNewChatThread, isLoading } = useCreateNewChatThread();
|
||||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||||
const editor = useSlate();
|
const editor = useSlate();
|
||||||
const [selectedRepos, setSelectedRepos] = useLocalStorage<string[]>("selectedRepos", []);
|
const [selectedRepos, setSelectedRepos] = useLocalStorage<string[]>("selectedRepos", [], { initializeWithValue: false });
|
||||||
const domain = useDomain();
|
const domain = useDomain();
|
||||||
const [isRepoSelectorOpen, setIsRepoSelectorOpen] = useState(false);
|
const [isRepoSelectorOpen, setIsRepoSelectorOpen] = useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ import { SourcebotLogo } from "@/app/components/sourcebotLogo";
|
||||||
import { LanguageModelInfo } from "@/features/chat/types";
|
import { LanguageModelInfo } from "@/features/chat/types";
|
||||||
import { RepositoryQuery } from "@/lib/types";
|
import { RepositoryQuery } from "@/lib/types";
|
||||||
import { useHotkeys } from "react-hotkeys-hook";
|
import { useHotkeys } from "react-hotkeys-hook";
|
||||||
import { useLocalStorage } from "usehooks-ts";
|
|
||||||
import { AgenticSearch } from "./agenticSearch";
|
import { AgenticSearch } from "./agenticSearch";
|
||||||
import { PreciseSearch } from "./preciseSearch";
|
import { PreciseSearch } from "./preciseSearch";
|
||||||
import { SearchMode } from "./toolbar";
|
import { SearchMode } from "./toolbar";
|
||||||
import { CustomSlateEditor } from "@/features/chat/customSlateEditor";
|
import { CustomSlateEditor } from "@/features/chat/customSlateEditor";
|
||||||
|
import { setSearchModeCookie } from "@/actions";
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
interface HomepageProps {
|
interface HomepageProps {
|
||||||
initialRepos: RepositoryQuery[];
|
initialRepos: RepositoryQuery[];
|
||||||
|
|
@ -18,6 +19,7 @@ interface HomepageProps {
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
}[];
|
}[];
|
||||||
|
initialSearchMode: SearchMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -25,13 +27,19 @@ export const Homepage = ({
|
||||||
initialRepos,
|
initialRepos,
|
||||||
languageModels,
|
languageModels,
|
||||||
chatHistory,
|
chatHistory,
|
||||||
|
initialSearchMode,
|
||||||
}: HomepageProps) => {
|
}: HomepageProps) => {
|
||||||
const [searchMode, setSearchMode] = useLocalStorage<SearchMode>("search-mode", "precise", { initializeWithValue: false });
|
const [searchMode, setSearchMode] = useState<SearchMode>(initialSearchMode);
|
||||||
const isAgenticSearchEnabled = languageModels.length > 0;
|
const isAgenticSearchEnabled = languageModels.length > 0;
|
||||||
|
|
||||||
|
const onSearchModeChanged = useCallback(async (newMode: SearchMode) => {
|
||||||
|
setSearchMode(newMode);
|
||||||
|
await setSearchModeCookie(newMode);
|
||||||
|
}, [setSearchMode]);
|
||||||
|
|
||||||
useHotkeys("mod+i", (e) => {
|
useHotkeys("mod+i", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSearchMode("agentic");
|
onSearchModeChanged("agentic");
|
||||||
}, {
|
}, {
|
||||||
enableOnFormTags: true,
|
enableOnFormTags: true,
|
||||||
enableOnContentEditable: true,
|
enableOnContentEditable: true,
|
||||||
|
|
@ -40,7 +48,7 @@ export const Homepage = ({
|
||||||
|
|
||||||
useHotkeys("mod+p", (e) => {
|
useHotkeys("mod+p", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSearchMode("precise");
|
onSearchModeChanged("precise");
|
||||||
}, {
|
}, {
|
||||||
enableOnFormTags: true,
|
enableOnFormTags: true,
|
||||||
enableOnContentEditable: true,
|
enableOnContentEditable: true,
|
||||||
|
|
@ -61,7 +69,7 @@ export const Homepage = ({
|
||||||
searchModeSelectorProps={{
|
searchModeSelectorProps={{
|
||||||
searchMode: "precise",
|
searchMode: "precise",
|
||||||
isAgenticSearchEnabled,
|
isAgenticSearchEnabled,
|
||||||
onSearchModeChange: setSearchMode,
|
onSearchModeChange: onSearchModeChanged,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -70,7 +78,7 @@ export const Homepage = ({
|
||||||
searchModeSelectorProps={{
|
searchModeSelectorProps={{
|
||||||
searchMode: "agentic",
|
searchMode: "agentic",
|
||||||
isAgenticSearchEnabled,
|
isAgenticSearchEnabled,
|
||||||
onSearchModeChange: setSearchMode,
|
onSearchModeChange: onSearchModeChanged,
|
||||||
}}
|
}}
|
||||||
languageModels={languageModels}
|
languageModels={languageModels}
|
||||||
repos={initialRepos}
|
repos={initialRepos}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { PageNotFound } from "./components/pageNotFound";
|
||||||
import { UpgradeToast } from "./components/upgradeToast";
|
import { UpgradeToast } from "./components/upgradeToast";
|
||||||
import { ServiceErrorException } from "@/lib/serviceError";
|
import { ServiceErrorException } from "@/lib/serviceError";
|
||||||
import { auth } from "@/auth";
|
import { auth } from "@/auth";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { SEARCH_MODE_COOKIE_NAME } from "@/lib/constants";
|
||||||
|
|
||||||
export default async function Home({ params: { domain } }: { params: { domain: string } }) {
|
export default async function Home({ params: { domain } }: { params: { domain: string } }) {
|
||||||
const org = await getOrgFromDomain(domain);
|
const org = await getOrgFromDomain(domain);
|
||||||
|
|
@ -32,6 +34,15 @@ export default async function Home({ params: { domain } }: { params: { domain: s
|
||||||
|
|
||||||
const indexedRepos = repos.filter((repo) => repo.indexedAt !== undefined);
|
const indexedRepos = repos.filter((repo) => repo.indexedAt !== undefined);
|
||||||
|
|
||||||
|
// Read search mode from cookie, defaulting to agentic if not set
|
||||||
|
// (assuming a language model is configured).
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
const searchModeCookie = cookieStore.get(SEARCH_MODE_COOKIE_NAME);
|
||||||
|
const initialSearchMode = (
|
||||||
|
searchModeCookie?.value === "agentic" ||
|
||||||
|
searchModeCookie?.value === "precise"
|
||||||
|
) ? searchModeCookie.value : models.length > 0 ? "agentic" : "precise";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center overflow-hidden min-h-screen">
|
<div className="flex flex-col items-center overflow-hidden min-h-screen">
|
||||||
<NavigationMenu
|
<NavigationMenu
|
||||||
|
|
@ -43,6 +54,7 @@ export default async function Home({ params: { domain } }: { params: { domain: s
|
||||||
initialRepos={indexedRepos}
|
initialRepos={indexedRepos}
|
||||||
languageModels={models}
|
languageModels={models}
|
||||||
chatHistory={chatHistory}
|
chatHistory={chatHistory}
|
||||||
|
initialSearchMode={initialSearchMode}
|
||||||
/>
|
/>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export const TEAM_FEATURES = [
|
||||||
]
|
]
|
||||||
|
|
||||||
export const MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME = 'sb.mobile-unsupported-splash-screen-dismissed';
|
export const MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME = 'sb.mobile-unsupported-splash-screen-dismissed';
|
||||||
|
export const SEARCH_MODE_COOKIE_NAME = 'sb.search-mode';
|
||||||
|
|
||||||
// NOTE: changing SOURCEBOT_GUEST_USER_ID may break backwards compatibility since this value is used
|
// NOTE: changing SOURCEBOT_GUEST_USER_ID may break backwards compatibility since this value is used
|
||||||
// to detect old guest users in the DB. If you change this value ensure it doesn't break upgrade flows
|
// to detect old guest users in the DB. If you change this value ensure it doesn't break upgrade flows
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue