Skip to content

Commit da21a5b

Browse files
Add basic chat history component to homepag
1 parent 334ac73 commit da21a5b

File tree

7 files changed

+90
-10
lines changed

7 files changed

+90
-10
lines changed

packages/web/src/app/[domain]/chat/layout.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { NavigationGuardProvider } from 'next-navigation-guard';
77
import { getRecentChats } from '@/features/chat/actions';
88
import { ServiceErrorException } from '@/lib/serviceError';
99
import { isServiceError } from '@/lib/utils';
10+
import { auth } from '@/auth';
1011

1112
interface LayoutProps {
1213
children: React.ReactNode;
@@ -16,7 +17,8 @@ interface LayoutProps {
1617
}
1718

1819
export default async function Layout({ children, params: { domain } }: LayoutProps) {
19-
const chatHistory = await getRecentChats(domain);
20+
const session = await auth();
21+
const chatHistory = session ? await getRecentChats(domain) : [];
2022

2123
if (isServiceError(chatHistory)) {
2224
throw new ServiceErrorException(chatHistory);

packages/web/src/app/[domain]/components/homepage/agenticSearch.tsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { SearchModeSelector, SearchModeSelectorProps } from "./toolbar";
1010
import { ReactEditor, useSlate } from "slate-react";
1111
import { resetEditor } from "@/features/chat/utils";
1212
import { ChatBoxToolbar, ChatBoxToolbarProps } from "@/features/chat/components/chatBox/chatBoxToolbar";
13+
import { getDisplayTime } from "@/lib/utils";
14+
import { useDomain } from "@/hooks/useDomain";
15+
import Link from "next/link";
1316

1417
// @todo: we should probably rename this to a different type since it sort-of clashes
1518
// with the Suggestion system we have built into the chat box.
@@ -68,22 +71,31 @@ const suggestions: Record<SuggestionType, {
6871
],
6972
}
7073

74+
const MAX_RECENT_CHAT_HISTORY_COUNT = 10;
75+
7176

7277
interface AgenticSearchProps {
7378
searchModeSelectorProps: SearchModeSelectorProps;
7479
chatBoxToolbarProps: Omit<ChatBoxToolbarProps, "selectedRepos" | "onSelectedReposChange">;
80+
chatHistory: {
81+
id: string;
82+
createdAt: Date;
83+
name: string | null;
84+
}[];
7585
}
7686

7787
export const AgenticSearch = ({
7888
searchModeSelectorProps,
7989
chatBoxToolbarProps,
90+
chatHistory,
8091
}: AgenticSearchProps) => {
8192
const [selectedSuggestionType, _setSelectedSuggestionType] = useState<SuggestionType | undefined>(undefined);
8293
const { createNewChatThread, isLoading } = useCreateNewChatThread();
8394
const dropdownRef = useRef<HTMLDivElement>(null);
8495
const editor = useSlate();
8596
const [selectedRepos, setSelectedRepos] = useState<string[]>([]);
86-
97+
const domain = useDomain();
98+
8799
const setSelectedSuggestionType = useCallback((type: SuggestionType | undefined) => {
88100
_setSelectedSuggestionType(type);
89101
if (type) {
@@ -172,6 +184,40 @@ export const AgenticSearch = ({
172184
))}
173185
</div>
174186
</div>
187+
{chatHistory.length > 0 && (
188+
<div className="flex flex-col items-center w-[80%]">
189+
<Separator className="my-6" />
190+
<span className="font-semibold mb-2">Recent conversations</span>
191+
<div
192+
className="flex flex-col gap-1 w-full"
193+
>
194+
{chatHistory
195+
.slice(0, MAX_RECENT_CHAT_HISTORY_COUNT)
196+
.map((chat) => (
197+
<Link
198+
key={chat.id}
199+
className="flex flex-row items-center justify-between gap-1 w-full rounded-md hover:bg-muted px-2 py-0.5 cursor-pointer group"
200+
href={`/${domain}/chat/${chat.id}`}
201+
>
202+
<span className="text-sm text-muted-foreground group-hover:text-foreground">
203+
{chat.name ?? "Untitled Chat"}
204+
</span>
205+
<span className="text-sm text-muted-foreground group-hover:text-foreground">
206+
{getDisplayTime(chat.createdAt)}
207+
</span>
208+
</Link>
209+
))}
210+
</div>
211+
{chatHistory.length > MAX_RECENT_CHAT_HISTORY_COUNT && (
212+
<Link
213+
href={`/${domain}/chat`}
214+
className="text-sm text-link hover:underline mt-6"
215+
>
216+
View all
217+
</Link>
218+
)}
219+
</div>
220+
)}
175221
</div>
176222
)
177223
}

packages/web/src/app/[domain]/components/homepage/index.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ import { CustomSlateEditor } from "@/features/chat/customSlateEditor";
1313
interface HomepageProps {
1414
initialRepos: RepositoryQuery[];
1515
languageModels: LanguageModelInfo[];
16+
chatHistory: {
17+
id: string;
18+
createdAt: Date;
19+
name: string | null;
20+
}[];
1621
}
1722

1823

1924
export const Homepage = ({
2025
initialRepos,
2126
languageModels,
27+
chatHistory,
2228
}: HomepageProps) => {
2329
const [searchMode, setSearchMode] = useLocalStorage<SearchMode>("search-mode", "precise", { initializeWithValue: false });
2430
const isAgenticSearchEnabled = languageModels.length > 0;
@@ -70,6 +76,7 @@ export const Homepage = ({
7076
repos: initialRepos,
7177
languageModels,
7278
}}
79+
chatHistory={chatHistory}
7380
/>
7481
</CustomSlateEditor>
7582
)}

packages/web/src/app/[domain]/components/homepage/repositorySnapshot.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export function RepositorySnapshot({
7171
{`Search ${indexedRepos.length} `}
7272
<Link
7373
href={`${domain}/repos`}
74-
className="text-link"
74+
className="text-link hover:underline"
7575
>
7676
{indexedRepos.length > 1 ? 'repositories' : 'repository'}
7777
</Link>

packages/web/src/app/[domain]/page.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
import { getRepos } from "@/actions";
22
import { Footer } from "@/app/components/footer";
33
import { getOrgFromDomain } from "@/data/org";
4-
import { getConfiguredLanguageModelsInfo } from "@/features/chat/actions";
4+
import { getConfiguredLanguageModelsInfo, getRecentChats } from "@/features/chat/actions";
55
import { isServiceError } from "@/lib/utils";
66
import { Homepage } from "./components/homepage";
77
import { NavigationMenu } from "./components/navigationMenu";
88
import { PageNotFound } from "./components/pageNotFound";
99
import { UpgradeToast } from "./components/upgradeToast";
10+
import { ServiceErrorException } from "@/lib/serviceError";
11+
import { auth } from "@/auth";
1012

1113
export default async function Home({ params: { domain } }: { params: { domain: string } }) {
1214
const org = await getOrgFromDomain(domain);
1315
if (!org) {
1416
return <PageNotFound />
1517
}
1618

17-
const repos = await getRepos(domain);
19+
const session = await auth();
20+
1821
const models = await getConfiguredLanguageModelsInfo();
22+
const repos = await getRepos(domain);
23+
const chatHistory = session ? await getRecentChats(domain) : [];
24+
25+
if (isServiceError(repos)) {
26+
throw new ServiceErrorException(repos);
27+
}
28+
29+
if (isServiceError(chatHistory)) {
30+
throw new ServiceErrorException(chatHistory);
31+
}
1932

2033
return (
2134
<div className="flex flex-col items-center overflow-hidden min-h-screen">
@@ -25,8 +38,9 @@ export default async function Home({ params: { domain } }: { params: { domain: s
2538
<UpgradeToast />
2639

2740
<Homepage
28-
initialRepos={isServiceError(repos) ? [] : repos}
41+
initialRepos={repos}
2942
languageModels={models}
43+
chatHistory={chatHistory}
3044
/>
3145
<Footer />
3246
</div>

packages/web/src/features/chat/components/chatBox/chatBoxToolbar.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
77
import { LanguageModelInfo } from "@/features/chat/types";
88
import { RepositoryQuery } from "@/lib/types";
99
import { AtSignIcon } from "lucide-react";
10-
import { useCallback } from "react";
10+
import { useCallback, useEffect } from "react";
1111
import { useHotkeys } from "react-hotkeys-hook";
1212
import { ReactEditor, useSlate } from "slate-react";
1313
import { useSelectedLanguageModel } from "../../useSelectedLanguageModel";
@@ -45,6 +45,13 @@ export const ChatBoxToolbar = ({
4545

4646
const { selectedLanguageModel, setSelectedLanguageModel } = useSelectedLanguageModel();
4747

48+
// Default to the first language model if one is not selected.
49+
useEffect(() => {
50+
if (!selectedLanguageModel && languageModels.length > 0) {
51+
setSelectedLanguageModel(languageModels[0]);
52+
}
53+
}, [languageModels, selectedLanguageModel, setSelectedLanguageModel]);
54+
4855
return (
4956
<>
5057
<Tooltip>

packages/web/src/features/chat/useSelectedLanguageModel.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ import { useLocalStorage } from "usehooks-ts";
44
import { LanguageModelInfo } from "./types";
55

66
export const useSelectedLanguageModel = () => {
7-
const [selectedLanguageModel, setSelectedLanguageModel] = useLocalStorage<LanguageModelInfo | undefined>("selectedLanguageModel", undefined, {
8-
initializeWithValue: false,
9-
});
7+
const [selectedLanguageModel, setSelectedLanguageModel] = useLocalStorage<LanguageModelInfo | undefined>(
8+
"selectedLanguageModel",
9+
undefined,
10+
{
11+
initializeWithValue: false,
12+
}
13+
);
1014

1115
return {
1216
selectedLanguageModel,

0 commit comments

Comments
 (0)