Skip to content

Commit 28887cc

Browse files
improved rendering
1 parent d73c22e commit 28887cc

13 files changed

Lines changed: 225 additions & 191 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { DefaultSidebar } from "../../../components/defaultSidebar";
2+
3+
export default async function Page() {
4+
return <DefaultSidebar />;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { DefaultSidebar } from "../../components/defaultSidebar";
2+
3+
export default async function Page() {
4+
return <DefaultSidebar />;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { SettingsSidebar } from "../../../components/settingsSidebar";
2+
3+
export default async function Page() {
4+
return <SettingsSidebar />;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { SettingsSidebar } from "../../components/settingsSidebar";
2+
3+
export default async function Page() {
4+
return <SettingsSidebar />;
5+
}

packages/web/src/app/(app)/components/appSidebar/chatHistorySidebarGroup.tsx renamed to packages/web/src/app/(app)/@sidebar/components/defaultSidebar/chatHistory.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ export interface ChatHistoryItem {
2828
createdAt: Date;
2929
}
3030

31-
interface ChatHistorySidebarGroupProps {
31+
interface ChatHistoryProps {
3232
chatHistory: ChatHistoryItem[];
3333
}
3434

35-
export function ChatHistorySidebarGroup({ chatHistory }: ChatHistorySidebarGroupProps) {
35+
export function ChatHistory({ chatHistory }: ChatHistoryProps) {
3636
const pathname = usePathname();
3737
const router = useRouter();
3838
const { toast } = useToast();
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { auth } from "@/auth";
2+
import { getUserChatHistory } from "@/features/chat/actions";
3+
import { getConnectionStats, getOrgAccountRequests } from "@/actions";
4+
import { isServiceError } from "@/lib/utils";
5+
import { ServiceErrorException } from "@/lib/serviceError";
6+
import { __unsafePrisma } from "@/prisma";
7+
import { SINGLE_TENANT_ORG_ID } from "@/lib/constants";
8+
import { OrgRole } from "@prisma/client";
9+
import { SidebarBase } from "@/app/(app)/@sidebar/components/sidebarBase";
10+
import { Nav } from "./nav";
11+
import { ChatHistory } from "./chatHistory";
12+
13+
export async function DefaultSidebar() {
14+
const session = await auth();
15+
16+
const chatHistory = session ? await getUserChatHistory() : [];
17+
if (isServiceError(chatHistory)) {
18+
throw new ServiceErrorException(chatHistory);
19+
}
20+
21+
const isSettingsNotificationVisible = await (async () => {
22+
if (!session) {
23+
return false;
24+
}
25+
const membership = await __unsafePrisma.userToOrg.findUnique({
26+
where: { orgId_userId: { orgId: SINGLE_TENANT_ORG_ID, userId: session.user.id } },
27+
select: { role: true },
28+
});
29+
if (membership?.role !== OrgRole.OWNER) {
30+
return false;
31+
}
32+
const connectionStats = await getConnectionStats();
33+
const joinRequests = await getOrgAccountRequests();
34+
const hasConnectionNotification = !isServiceError(connectionStats) && connectionStats.numberOfConnectionsWithFirstTimeSyncJobsInProgress > 0;
35+
const hasJoinRequestNotification = !isServiceError(joinRequests) && joinRequests.length > 0;
36+
return hasConnectionNotification || hasJoinRequestNotification;
37+
})();
38+
39+
return (
40+
<SidebarBase
41+
session={session}
42+
collapsible="icon"
43+
headerContent={<Nav isSettingsNotificationVisible={isSettingsNotificationVisible} />}
44+
>
45+
<ChatHistory chatHistory={chatHistory} />
46+
</SidebarBase>
47+
);
48+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"use client";
2+
3+
import {
4+
SidebarMenu,
5+
SidebarMenuButton,
6+
SidebarMenuItem,
7+
} from "@/components/ui/sidebar";
8+
import { BookMarkedIcon, MessageCircleIcon, MessagesSquareIcon, SearchIcon, SettingsIcon } from "lucide-react";
9+
import { usePathname } from "next/navigation";
10+
import { NotificationDot } from "../../../components/notificationDot";
11+
12+
const baseItems = [
13+
{ title: "Code Search", href: "/search", icon: SearchIcon, key: "search" },
14+
{ title: "Ask", href: "/chat", icon: MessageCircleIcon, key: "chat" },
15+
{ title: "Chats", href: "/chats", icon: MessagesSquareIcon, key: "chats" },
16+
{ title: "Repositories", href: "/repos", icon: BookMarkedIcon, key: "repos" },
17+
{ title: "Settings", href: "/settings", icon: SettingsIcon, key: "settings" },
18+
];
19+
20+
interface NavProps {
21+
isSettingsNotificationVisible?: boolean;
22+
}
23+
24+
export function Nav({ isSettingsNotificationVisible }: NavProps) {
25+
const pathname = usePathname();
26+
27+
const isActive = (href: string) => {
28+
if (href === "/search") {
29+
return pathname === "/" || pathname.startsWith("/search");
30+
}
31+
if (href === "/chat") {
32+
return pathname === "/chat";
33+
}
34+
return pathname.startsWith(href);
35+
};
36+
37+
return (
38+
<SidebarMenu>
39+
{baseItems.map((item) => {
40+
const showNotification =
41+
(item.key === "settings" && isSettingsNotificationVisible);
42+
return (
43+
<SidebarMenuItem key={item.title}>
44+
<SidebarMenuButton asChild isActive={isActive(item.href)}>
45+
<a href={item.href}>
46+
<item.icon />
47+
<span>{item.title}</span>
48+
{showNotification && <NotificationDot className="ml-1.5" />}
49+
</a>
50+
</SidebarMenuButton>
51+
</SidebarMenuItem>
52+
);
53+
})}
54+
</SidebarMenu>
55+
);
56+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { auth } from "@/auth";
2+
import { isServiceError } from "@/lib/utils";
3+
import { ServiceErrorException } from "@/lib/serviceError";
4+
import { getSidebarNavGroups } from "@/app/(app)/settings/layout";
5+
import { SidebarBase } from "../sidebarBase";
6+
import { Nav } from "./nav";
7+
import {
8+
SidebarMenu,
9+
SidebarMenuButton,
10+
SidebarMenuItem,
11+
} from "@/components/ui/sidebar";
12+
import { ArrowLeftIcon } from "lucide-react";
13+
import Link from "next/link";
14+
15+
export async function SettingsSidebar() {
16+
const session = await auth();
17+
18+
const sidebarNavGroups = await getSidebarNavGroups();
19+
if (isServiceError(sidebarNavGroups)) {
20+
throw new ServiceErrorException(sidebarNavGroups);
21+
}
22+
23+
return (
24+
<SidebarBase
25+
session={session}
26+
collapsible="none"
27+
headerContent={
28+
<SidebarMenu>
29+
<SidebarMenuItem>
30+
<SidebarMenuButton asChild>
31+
<Link href="/">
32+
<ArrowLeftIcon />
33+
<span>Back to app</span>
34+
</Link>
35+
</SidebarMenuButton>
36+
</SidebarMenuItem>
37+
</SidebarMenu>
38+
}
39+
>
40+
<Nav groups={sidebarNavGroups} />
41+
</SidebarBase>
42+
);
43+
}

packages/web/src/app/(app)/settings/components/settingsSidebarOverride.tsx renamed to packages/web/src/app/(app)/@sidebar/components/settingsSidebar/nav.tsx

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"use client";
22

3-
import { SetSidebarOverride } from "@/app/(app)/components/appSidebar/sidebarOverrideContext";
43
import { NotificationDot } from "@/app/(app)/components/notificationDot";
54
import {
65
SidebarGroup,
@@ -10,51 +9,49 @@ import {
109
SidebarMenuButton,
1110
SidebarMenuItem,
1211
} from "@/components/ui/sidebar";
13-
import { ArrowLeftIcon } from "lucide-react";
14-
import { DynamicIcon, IconName } from "lucide-react/dynamic";
12+
import {
13+
ChartAreaIcon,
14+
KeyRoundIcon,
15+
LinkIcon,
16+
type LucideIcon,
17+
PlugIcon,
18+
ScrollTextIcon,
19+
ShieldIcon,
20+
UsersIcon,
21+
} from "lucide-react";
1522
import Link from "next/link";
1623
import { usePathname } from "next/navigation";
17-
import React from "react";
1824

19-
export type SidebarNavItem = {
25+
const iconMap = {
26+
"link": LinkIcon,
27+
"key-round": KeyRoundIcon,
28+
"shield": ShieldIcon,
29+
"users": UsersIcon,
30+
"plug": PlugIcon,
31+
"chart-area": ChartAreaIcon,
32+
"scroll-text": ScrollTextIcon,
33+
} satisfies Record<string, LucideIcon>;
34+
35+
export type NavIconName = keyof typeof iconMap;
36+
37+
export type NavItem = {
2038
href: string;
2139
hrefRegex?: string;
2240
title: React.ReactNode;
23-
icon?: IconName;
41+
icon?: NavIconName;
2442
isNotificationDotVisible?: boolean;
2543
};
2644

27-
export type SidebarNavGroup = {
45+
export type NavGroup = {
2846
label: string;
29-
items: SidebarNavItem[];
47+
items: NavItem[];
3048
};
3149

32-
interface SettingsSidebarOverrideProps {
33-
groups: SidebarNavGroup[];
34-
}
35-
36-
export function SettingsSidebarOverride({ groups }: SettingsSidebarOverrideProps) {
37-
return (
38-
<SetSidebarOverride
39-
header={
40-
<SidebarMenu>
41-
<SidebarMenuItem>
42-
<SidebarMenuButton asChild>
43-
<Link href="/">
44-
<ArrowLeftIcon />
45-
<span>Back to app</span>
46-
</Link>
47-
</SidebarMenuButton>
48-
</SidebarMenuItem>
49-
</SidebarMenu>
50-
}
51-
content={<SettingsSidebarContent groups={groups} />}
52-
collapsible="none"
53-
/>
54-
);
50+
interface NavProps {
51+
groups: NavGroup[];
5552
}
5653

57-
function SettingsSidebarContent({ groups }: { groups: SidebarNavGroup[] }) {
54+
export function Nav({ groups }: NavProps) {
5855
const pathname = usePathname();
5956

6057
return (
@@ -68,11 +65,12 @@ function SettingsSidebarContent({ groups }: { groups: SidebarNavGroup[] }) {
6865
const isActive = item.hrefRegex
6966
? new RegExp(item.hrefRegex).test(pathname)
7067
: pathname === item.href;
68+
const Icon = item.icon ? iconMap[item.icon] : undefined;
7169
return (
7270
<SidebarMenuItem key={item.href}>
7371
<SidebarMenuButton asChild isActive={isActive}>
7472
<Link href={item.href}>
75-
{item.icon && <DynamicIcon name={item.icon} />}
73+
{Icon && <Icon />}
7674
<span>{item.title}</span>
7775
{item.isNotificationDotVisible && <NotificationDot className="ml-1.5" />}
7876
</Link>

packages/web/src/app/(app)/components/appSidebar/index.tsx renamed to packages/web/src/app/(app)/@sidebar/components/sidebarBase.tsx

Lines changed: 10 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,24 @@ import {
2222
} from "@/components/ui/sidebar";
2323
import { UserAvatar } from "@/components/userAvatar";
2424
import { cn } from "@/lib/utils";
25-
import { ArrowLeftToLineIcon, ArrowRightToLineIcon, BookMarkedIcon, ChevronsUpDown, LogOut, MessageCircleIcon, MessagesSquareIcon, SearchIcon, SettingsIcon } from "lucide-react";
25+
import { ArrowLeftToLineIcon, ArrowRightToLineIcon, ChevronsUpDown, LogOut, SettingsIcon } from "lucide-react";
2626
import { Session } from "next-auth";
2727
import { signOut } from "next-auth/react";
2828
import Link from "next/link";
29-
import { usePathname } from "next/navigation";
3029
import posthog from "posthog-js";
31-
import { useEffect, useRef, useState } from "react";
32-
import { AppearanceDropdownMenuGroup } from "../appearanceDropdownMenuGroup";
33-
import { NotificationDot } from "../notificationDot";
34-
import { ChatHistoryItem, ChatHistorySidebarGroup } from "./chatHistorySidebarGroup";
35-
import { useSidebarOverride } from "./sidebarOverrideContext";
30+
import { ReactNode, useEffect, useRef, useState } from "react";
31+
import { AppearanceDropdownMenuGroup } from "../../components/appearanceDropdownMenuGroup";
3632

37-
const baseItems = [
38-
{ title: "Code Search", href: "/search", icon: SearchIcon, key: "search" },
39-
{ title: "Ask", href: "/chat", icon: MessageCircleIcon, key: "chat" },
40-
{ title: "Chats", href: "/chats", icon: MessagesSquareIcon, key: "chats" },
41-
{ title: "Repositories", href: "/repos", icon: BookMarkedIcon, key: "repos" },
42-
{ title: "Settings", href: "/settings", icon: SettingsIcon, key: "settings" },
43-
];
44-
45-
interface AppSidebarProps {
33+
interface SidebarBaseProps {
4634
session: Session | null;
47-
chatHistory: ChatHistoryItem[];
48-
isSettingsNotificationVisible?: boolean;
35+
collapsible?: "icon" | "offcanvas" | "none";
36+
headerContent: ReactNode;
37+
children: ReactNode;
4938
}
5039

51-
export function AppSidebar({ session, chatHistory, isSettingsNotificationVisible }: AppSidebarProps) {
52-
const pathname = usePathname();
40+
export function SidebarBase({ session, collapsible = "icon", headerContent, children }: SidebarBaseProps) {
5341
const [isScrolled, setIsScrolled] = useState(false);
5442
const contentRef = useRef<HTMLDivElement>(null);
55-
const sidebarOverride = useSidebarOverride();
5643

5744
useEffect(() => {
5845
const el = contentRef.current;
@@ -64,19 +51,6 @@ export function AppSidebar({ session, chatHistory, isSettingsNotificationVisible
6451
return () => el.removeEventListener("scroll", handleScroll);
6552
}, []);
6653

67-
const isActive = (href: string) => {
68-
if (href === "/search") {
69-
return pathname === "/" || pathname.startsWith("/search");
70-
}
71-
if (href === "/chat") {
72-
return pathname === "/chat";
73-
}
74-
return pathname.startsWith(href);
75-
};
76-
77-
const hasOverride = sidebarOverride?.override != null;
78-
const collapsible = sidebarOverride?.override?.collapsible ?? "icon";
79-
8054
return (
8155
<Sidebar
8256
collapsible={collapsible}
@@ -91,30 +65,10 @@ export function AppSidebar({ session, chatHistory, isSettingsNotificationVisible
9165
<SourcebotLogo className="w-fit h-8" size="small" />
9266
</div>
9367
</Link>
94-
{hasOverride ? sidebarOverride.override?.header : (
95-
<SidebarMenu>
96-
{baseItems.map((item) => {
97-
const showNotification =
98-
(item.key === "settings" && isSettingsNotificationVisible);
99-
return (
100-
<SidebarMenuItem key={item.title}>
101-
<SidebarMenuButton asChild isActive={isActive(item.href)}>
102-
<a href={item.href}>
103-
<item.icon />
104-
<span>{item.title}</span>
105-
{showNotification && <NotificationDot className="ml-1.5" />}
106-
</a>
107-
</SidebarMenuButton>
108-
</SidebarMenuItem>
109-
);
110-
})}
111-
</SidebarMenu>
112-
)}
68+
{headerContent}
11369
</SidebarHeader>
11470
<SidebarContent ref={contentRef}>
115-
{hasOverride ? sidebarOverride.override?.content : (
116-
<ChatHistorySidebarGroup chatHistory={chatHistory} />
117-
)}
71+
{children}
11872
</SidebarContent>
11973
<SidebarFooter className="border-t border-sidebar-border">
12074
{collapsible !== "none" && <CollapseSidebarButton />}

0 commit comments

Comments
 (0)