Skip to content

Commit 2db097e

Browse files
guest sidebar footer
1 parent bca3a54 commit 2db097e

File tree

6 files changed

+147
-134
lines changed

6 files changed

+147
-134
lines changed

packages/web/src/app/(app)/@sidebar/components/defaultSidebar/chatHistory.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ export function ChatHistory({ chatHistory, hasMore }: ChatHistoryProps) {
6767
captureEvent('wa_chat_deleted', { chatId: chatIdToDelete });
6868
if (pathname === `/chat/${chatIdToDelete}`) {
6969
router.push("/chat");
70+
} else {
71+
router.refresh();
7072
}
7173
return true;
7274
}, [pathname, router, toast]);

packages/web/src/app/(app)/@sidebar/components/sidebarBase.tsx

Lines changed: 120 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ import {
66
DropdownMenuContent,
77
DropdownMenuGroup,
88
DropdownMenuItem,
9+
DropdownMenuPortal,
10+
DropdownMenuRadioGroup,
11+
DropdownMenuRadioItem,
912
DropdownMenuSeparator,
13+
DropdownMenuSub,
14+
DropdownMenuSubContent,
15+
DropdownMenuSubTrigger,
1016
DropdownMenuTrigger,
1117
} from "@/components/ui/dropdown-menu";
1218
import {
@@ -21,14 +27,19 @@ import {
2127
useSidebar,
2228
} from "@/components/ui/sidebar";
2329
import { UserAvatar } from "@/components/userAvatar";
30+
import { useKeymapType } from "@/hooks/useKeymapType";
31+
import { KeymapType } from "@/lib/types";
2432
import { cn } from "@/lib/utils";
25-
import { ArrowLeftToLineIcon, ArrowRightToLineIcon, ChevronsUpDown, LogOut, SettingsIcon } from "lucide-react";
33+
import {
34+
ArrowLeftToLineIcon, ArrowRightToLineIcon, ChevronsUpDown, CodeIcon,
35+
Laptop, LogIn, LogOut, Moon, SettingsIcon, Sun, UserIcon
36+
} from "lucide-react";
2637
import { Session } from "next-auth";
2738
import { signOut } from "next-auth/react";
39+
import { useTheme } from "next-themes";
2840
import Link from "next/link";
2941
import posthog from "posthog-js";
30-
import { ReactNode, useEffect, useRef, useState } from "react";
31-
import { AppearanceDropdownMenuGroup } from "../../components/appearanceDropdownMenuGroup";
42+
import { ReactNode, useEffect, useMemo, useRef, useState } from "react";
3243

3344
interface SidebarBaseProps {
3445
session: Session | null;
@@ -72,8 +83,10 @@ export function SidebarBase({ session, collapsible = "icon", headerContent, chil
7283
</SidebarContent>
7384
<SidebarFooter className="border-t border-sidebar-border">
7485
{collapsible !== "none" && <CollapseSidebarButton />}
75-
{session && (
86+
{session ? (
7687
<MeControlDropdownMenu session={session} />
88+
) : (
89+
<GuestDropdownMenu />
7790
)}
7891
</SidebarFooter>
7992
{collapsible !== "none" && <SidebarRail />}
@@ -176,3 +189,106 @@ const MeControlDropdownMenu = ({
176189
</SidebarMenu>
177190
)
178191
}
192+
193+
const GuestDropdownMenu = () => {
194+
return (
195+
<SidebarMenu>
196+
<SidebarMenuItem>
197+
<DropdownMenu>
198+
<DropdownMenuTrigger asChild>
199+
<SidebarMenuButton
200+
size="lg"
201+
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
202+
>
203+
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-muted flex-shrink-0">
204+
<UserIcon className="h-4 w-4 text-muted-foreground" />
205+
</div>
206+
<div className="grid flex-1 text-left text-sm leading-tight">
207+
<span className="truncate font-semibold">Guest</span>
208+
<span className="truncate text-xs text-muted-foreground">Not signed in</span>
209+
</div>
210+
<ChevronsUpDown className="ml-auto size-4" />
211+
</SidebarMenuButton>
212+
</DropdownMenuTrigger>
213+
<DropdownMenuContent className="w-64" side="top" align="start" sideOffset={4}>
214+
<AppearanceDropdownMenuGroup />
215+
<DropdownMenuSeparator />
216+
<DropdownMenuItem asChild>
217+
<a href="/login">
218+
<LogIn className="h-4 w-4 mr-2" />
219+
<span>Sign in</span>
220+
</a>
221+
</DropdownMenuItem>
222+
</DropdownMenuContent>
223+
</DropdownMenu>
224+
</SidebarMenuItem>
225+
</SidebarMenu>
226+
);
227+
}
228+
229+
230+
const AppearanceDropdownMenuGroup = () => {
231+
const { theme: _theme, setTheme } = useTheme();
232+
const [keymapType, setKeymapType] = useKeymapType();
233+
234+
const theme = useMemo(() => {
235+
return _theme ?? "light";
236+
}, [_theme]);
237+
238+
const ThemeIcon = useMemo(() => {
239+
switch (theme) {
240+
case "light":
241+
return <Sun className="h-4 w-4 mr-2" />;
242+
case "dark":
243+
return <Moon className="h-4 w-4 mr-2" />;
244+
case "system":
245+
return <Laptop className="h-4 w-4 mr-2" />;
246+
default:
247+
return <Laptop className="h-4 w-4 mr-2" />;
248+
}
249+
}, [theme]);
250+
251+
return (
252+
<DropdownMenuGroup>
253+
<DropdownMenuSub>
254+
<DropdownMenuSubTrigger>
255+
{ThemeIcon}
256+
<span>Theme</span>
257+
</DropdownMenuSubTrigger>
258+
<DropdownMenuPortal>
259+
<DropdownMenuSubContent>
260+
<DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
261+
<DropdownMenuRadioItem value="light">
262+
Light
263+
</DropdownMenuRadioItem>
264+
<DropdownMenuRadioItem value="dark">
265+
Dark
266+
</DropdownMenuRadioItem>
267+
<DropdownMenuRadioItem value="system">
268+
System
269+
</DropdownMenuRadioItem>
270+
</DropdownMenuRadioGroup>
271+
</DropdownMenuSubContent>
272+
</DropdownMenuPortal>
273+
</DropdownMenuSub>
274+
<DropdownMenuSub>
275+
<DropdownMenuSubTrigger>
276+
<CodeIcon className="h-4 w-4 mr-2" />
277+
<span>Code navigation</span>
278+
</DropdownMenuSubTrigger>
279+
<DropdownMenuPortal>
280+
<DropdownMenuSubContent>
281+
<DropdownMenuRadioGroup value={keymapType} onValueChange={(value) => setKeymapType(value as KeymapType)}>
282+
<DropdownMenuRadioItem value="default">
283+
Default
284+
</DropdownMenuRadioItem>
285+
<DropdownMenuRadioItem value="vim">
286+
Vim
287+
</DropdownMenuRadioItem>
288+
</DropdownMenuRadioGroup>
289+
</DropdownMenuSubContent>
290+
</DropdownMenuPortal>
291+
</DropdownMenuSub>
292+
</DropdownMenuGroup>
293+
)
294+
}

packages/web/src/app/(app)/chat/[id]/page.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getRepos, getSearchContexts } from '@/actions';
2-
import { getChatInfo, claimAnonymousChats, getSharedWithUsersForChat } from '@/features/chat/actions';
2+
import { getChatInfo, getSharedWithUsersForChat } from '@/features/chat/actions';
33
import { getConfiguredLanguageModelsInfo } from "@/features/chat/utils.server";
44
import { ServiceErrorException } from '@/lib/serviceError';
55
import { isServiceError } from '@/lib/utils';
@@ -80,15 +80,6 @@ export default async function Page(props: PageProps) {
8080
const params = await props.params;
8181
const session = await auth();
8282

83-
// Claim any anonymous chats created by this user before they signed in.
84-
// This must happen before getChatInfo so the chat ownership is updated.
85-
if (session) {
86-
const claimResult = await claimAnonymousChats();
87-
if (isServiceError(claimResult)) {
88-
throw new ServiceErrorException(claimResult);
89-
}
90-
}
91-
9283
const languageModels = await getConfiguredLanguageModelsInfo();
9384
const repos = await getRepos();
9485
const searchContexts = await getSearchContexts();

packages/web/src/app/(app)/components/appearanceDropdownMenu.tsx

Lines changed: 0 additions & 33 deletions
This file was deleted.

packages/web/src/app/(app)/components/appearanceDropdownMenuGroup.tsx

Lines changed: 0 additions & 87 deletions
This file was deleted.

packages/web/src/auth.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import { onCreateUser } from '@/lib/authUtils';
1818
import { getAuditService } from '@/ee/features/audit/factory';
1919
import { SINGLE_TENANT_ORG_ID } from './lib/constants';
2020
import { EncryptedPrismaAdapter, encryptAccountData } from '@/lib/encryptedPrismaAdapter';
21+
import { getAnonymousId } from '@/lib/anonymousId';
22+
import { captureEvent } from '@/lib/posthog';
2123

2224
const auditService = getAuditService();
2325
const eeIdentityProviders = hasEntitlement("sso") ? await getEEIdentityProviders() : [];
@@ -187,6 +189,28 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
187189
}
188190

189191
if (user.id) {
192+
// Claim any anonymous chats created before sign-in.
193+
const anonymousId = await getAnonymousId();
194+
if (anonymousId) {
195+
const result = await __unsafePrisma.chat.updateMany({
196+
where: {
197+
orgId: SINGLE_TENANT_ORG_ID,
198+
anonymousCreatorId: anonymousId,
199+
createdById: null,
200+
},
201+
data: {
202+
createdById: user.id,
203+
anonymousCreatorId: null,
204+
},
205+
});
206+
207+
if (result.count > 0) {
208+
await captureEvent('wa_anonymous_chats_claimed', {
209+
claimedCount: result.count,
210+
});
211+
}
212+
}
213+
190214
await auditService.createAudit({
191215
action: "user.signed_in",
192216
actor: {

0 commit comments

Comments
 (0)