Skip to content

Commit afbeddb

Browse files
cursoragentmsukkari
andcommitted
feat(askgh): allow users to select additional search scopes
- Added repos and searchContexts props to LandingPage component - Implemented local storage for persisting selected search scopes - Current repo is pre-selected by default when visiting Ask GH page - Users can now add/remove search scopes using the SearchScopeSelector Fixes SOU-1496 Co-authored-by: Michael Sukkarieh <msukkari@users.noreply.github.com>
1 parent 53360a8 commit afbeddb

2 files changed

Lines changed: 60 additions & 14 deletions

File tree

packages/web/src/app/(app)/askgh/[owner]/[repo]/components/landingPage.tsx

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import { ChatBox, ChatBoxHandle } from "@/features/chat/components/chatBox";
77
import { ChatBoxToolbar } from "@/features/chat/components/chatBox/chatBoxToolbar";
88
import { ChatPaneDropzone } from "@/features/chat/components/chatBox/chatPaneDropzone";
99
import { NotConfiguredErrorBanner } from "@/features/chat/components/notConfiguredErrorBanner";
10-
import { LanguageModelInfo, RepoSearchScope } from "@/features/chat/types";
10+
import { LanguageModelInfo, RepoSearchScope, SearchScope } from "@/features/chat/types";
1111
import { useCreateNewChatThread } from "@/features/chat/useCreateNewChatThread";
1212
import { DISABLED_MCP_SERVER_IDS_LOCAL_STORAGE_KEY } from "@/features/chat/constants";
1313
import { getRepoImageSrc } from '@/lib/utils';
14-
import { useMemo, useRef, useState } from "react";
14+
import { useEffect, useMemo, useRef, useState } from "react";
1515
import { useLocalStorage } from "usehooks-ts";
1616
import type { AskCommandDefinition } from '@/features/chat/commands/types';
17+
import { RepositoryQuery, SearchContextQuery } from "@/lib/types";
18+
19+
const ASKGH_SELECTED_SEARCH_SCOPES_LOCAL_STORAGE_KEY = 'askGhSelectedSearchScopes';
1720

1821
interface LandingPageProps {
1922
languageModels: LanguageModelInfo[];
@@ -24,6 +27,8 @@ interface LandingPageProps {
2427
askCommands: AskCommandDefinition[];
2528
isAuthenticated: boolean;
2629
maxImageBytes: number;
30+
repos: RepositoryQuery[];
31+
searchContexts: SearchContextQuery[];
2732
}
2833

2934
export const LandingPage = ({
@@ -35,21 +40,49 @@ export const LandingPage = ({
3540
askCommands,
3641
isAuthenticated,
3742
maxImageBytes,
43+
repos,
44+
searchContexts,
3845
}: LandingPageProps) => {
3946
const { createNewChatThread, isLoading } = useCreateNewChatThread();
4047
const [isContextSelectorOpen, setIsContextSelectorOpen] = useState(false);
4148
const [disabledMcpServerIds, setDisabledMcpServerIds] = useLocalStorage<string[]>(DISABLED_MCP_SERVER_IDS_LOCAL_STORAGE_KEY, [], { initializeWithValue: false });
4249
const chatBoxRef = useRef<ChatBoxHandle>(null);
4350
const isChatBoxDisabled = languageModels.length === 0;
4451

45-
const selectedSearchScopes = useMemo(() => [
46-
{
47-
type: 'repo',
48-
name: repoDisplayName ?? repoName,
49-
value: repoName,
50-
codeHostType: 'github' as const,
51-
} satisfies RepoSearchScope,
52-
], [repoDisplayName, repoName]);
52+
// Default scope for the current repo
53+
const defaultRepoScope = useMemo(() => ({
54+
type: 'repo' as const,
55+
name: repoDisplayName ?? repoName,
56+
value: repoName,
57+
codeHostType: 'github' as const,
58+
} satisfies RepoSearchScope), [repoDisplayName, repoName]);
59+
60+
// Use local storage for selected scopes, with the current repo as default
61+
const [selectedSearchScopes, setSelectedSearchScopes] = useLocalStorage<SearchScope[]>(
62+
ASKGH_SELECTED_SEARCH_SCOPES_LOCAL_STORAGE_KEY,
63+
[defaultRepoScope],
64+
{ initializeWithValue: false }
65+
);
66+
67+
// Ensure the current repo is always included in selected scopes when visiting this page
68+
// This handles the case where the user visits a different repo's Ask GH page
69+
const [hasInitialized, setHasInitialized] = useState(false);
70+
useEffect(() => {
71+
if (hasInitialized) {
72+
return;
73+
}
74+
setHasInitialized(true);
75+
76+
// Check if the current repo is already in the selected scopes
77+
const currentRepoIncluded = selectedSearchScopes.some(
78+
(scope) => scope.type === 'repo' && scope.value === repoName
79+
);
80+
81+
// If not, add it to the scopes
82+
if (!currentRepoIncluded) {
83+
setSelectedSearchScopes([defaultRepoScope, ...selectedSearchScopes]);
84+
}
85+
}, [hasInitialized, selectedSearchScopes, repoName, defaultRepoScope, setSelectedSearchScopes]);
5386

5487
const imageSrc = imageUrl ? getRepoImageSrc(imageUrl, repoId) : undefined;
5588
const displayName = repoDisplayName ?? repoName;
@@ -88,7 +121,7 @@ export const LandingPage = ({
88121
className="min-h-[50px]"
89122
isRedirecting={isLoading}
90123
selectedSearchScopes={selectedSearchScopes}
91-
searchContexts={[]}
124+
searchContexts={searchContexts}
92125
askCommands={askCommands}
93126
isDisabled={isChatBoxDisabled}
94127
isAuthenticated={isAuthenticated}
@@ -100,10 +133,10 @@ export const LandingPage = ({
100133
<div className="w-full flex flex-row items-center bg-accent rounded-b-md px-2">
101134
<ChatBoxToolbar
102135
languageModels={languageModels}
103-
repos={[]}
104-
searchContexts={[]}
136+
repos={repos}
137+
searchContexts={searchContexts}
105138
selectedSearchScopes={selectedSearchScopes}
106-
onSelectedSearchScopesChange={() => { }}
139+
onSelectedSearchScopesChange={setSelectedSearchScopes}
107140
isContextSelectorOpen={isContextSelectorOpen}
108141
onContextSelectorOpenChanged={setIsContextSelectorOpen}
109142
disabledMcpServerIds={disabledMcpServerIds}

packages/web/src/app/(app)/askgh/[owner]/[repo]/page.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { hasEntitlement } from "@/lib/entitlements";
1414
import { ChatEntitlementMessage } from "@/features/chat/components/chatEntitlementMessage";
1515
import { env } from "@sourcebot/shared";
1616
import { listAgentSkillCommandsOrEmpty } from "@/ee/features/chat/skills/skillCommands.server";
17+
import { getRepos, getSearchContexts } from "@/actions";
1718

1819
interface PageProps {
1920
params: Promise<{ owner: string; repo: string }>;
@@ -70,11 +71,21 @@ export default async function GitHubRepoPage(props: PageProps) {
7071
const askCommands = session?.user
7172
? await listAgentSkillCommandsOrEmpty()
7273
: [];
74+
const allRepos = await getRepos();
75+
const searchContexts = await getSearchContexts();
7376

7477
if (isServiceError(repoInfo)) {
7578
throw new ServiceErrorException(repoInfo);
7679
}
7780

81+
if (isServiceError(allRepos)) {
82+
throw new ServiceErrorException(allRepos);
83+
}
84+
85+
if (isServiceError(searchContexts)) {
86+
throw new ServiceErrorException(searchContexts);
87+
}
88+
7889
return (
7990
<RepoIndexedGuard initialRepoInfo={repoInfo}>
8091
<CustomSlateEditor>
@@ -87,6 +98,8 @@ export default async function GitHubRepoPage(props: PageProps) {
8798
askCommands={askCommands}
8899
isAuthenticated={!!session?.user}
89100
maxImageBytes={env.SOURCEBOT_CHAT_ATTACHMENT_MAX_IMAGE_BYTES}
101+
repos={allRepos}
102+
searchContexts={searchContexts}
90103
/>
91104
</CustomSlateEditor>
92105
</RepoIndexedGuard>

0 commit comments

Comments
 (0)