Skip to content

Commit d130532

Browse files
authored
Suggest questions in the current space context (#3514)
1 parent 94fcd21 commit d130532

File tree

8 files changed

+36
-14
lines changed

8 files changed

+36
-14
lines changed

.changeset/curly-eagles-arrive.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": minor
3+
---
4+
5+
Suggest questions in the current space context

bun.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@
246246
"react-dom": "^19.0.0",
247247
},
248248
"catalog": {
249-
"@gitbook/api": "^0.129.0",
249+
"@gitbook/api": "^0.130.0",
250250
},
251251
"packages": {
252252
"@ai-sdk/provider": ["@ai-sdk/[email protected]", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-0M+qjp+clUD0R1E5eWQFhxEvWLNaOtGQRUaBn8CUABnSKredagq92hUS9VjOzGsTm37xLfpaxl97AVtbeOsHew=="],
@@ -609,7 +609,7 @@
609609

610610
"@fortawesome/fontawesome-svg-core": ["@fortawesome/[email protected]", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="],
611611

612-
"@gitbook/api": ["@gitbook/api@0.129.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-Uh+k/BiDgdXj5a8BIlvwfEXdZNNlQMFDlGKmivUYH1gvFySqrTO6PjR/HtUOZEdNauAeWZmGoB8CLuwrVZS+YA=="],
612+
"@gitbook/api": ["@gitbook/api@0.130.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-nfAPfTISUou+hJPZLrBsuUSSaHEeWB6eZ4adapWAagmaeeA3CpfopDROXcqGJPBHYPfvfLZIGdgyYhyYC3Objw=="],
613613

614614
"@gitbook/cache-tags": ["@gitbook/cache-tags@workspace:packages/cache-tags"],
615615

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"workspaces": {
3535
"packages": ["packages/*"],
3636
"catalog": {
37-
"@gitbook/api": "^0.129.0"
37+
"@gitbook/api": "^0.130.0"
3838
}
3939
},
4040
"patchedDependencies": {

packages/gitbook/src/components/DocumentView/ReusableContent.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ export async function ReusableContent(props: BlockProps<DocumentBlockReusableCon
2626
}
2727

2828
const { reusableContent } = resolved;
29-
if (!reusableContent || !reusableContent.revisionReusableContent.document) {
29+
if (
30+
!reusableContent ||
31+
!('document' in reusableContent.revisionReusableContent) ||
32+
!reusableContent.revisionReusableContent.document
33+
) {
3034
return null;
3135
}
3236

packages/gitbook/src/components/Search/SearchContainer.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { SearchScopeToggle } from './SearchScopeToggle';
1616
import { useSearch } from './useSearch';
1717

1818
interface SearchContainerProps {
19+
spaceId: string;
1920
spaceTitle: string;
2021
isMultiVariants: boolean;
2122
aiMode: CustomizationAIMode;
@@ -26,7 +27,7 @@ interface SearchContainerProps {
2627
* Client component to render the search input and results.
2728
*/
2829
export function SearchContainer(props: SearchContainerProps) {
29-
const { spaceTitle, isMultiVariants, aiMode, className } = props;
30+
const { spaceId, spaceTitle, isMultiVariants, aiMode, className } = props;
3031

3132
const withAIChat = aiMode === CustomizationAIMode.Assistant;
3233
const [state, setSearchState] = useSearch(withAIChat);
@@ -146,6 +147,7 @@ export function SearchContainer(props: SearchContainerProps) {
146147
query={normalizedQuery}
147148
global={state?.global ?? false}
148149
aiMode={aiMode}
150+
spaceId={spaceId}
149151
/>
150152
) : null}
151153
{normalizedAsk ? <SearchAskAnswer query={normalizedAsk} /> : null}

packages/gitbook/src/components/Search/SearchResults.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { t, useLanguage } from '@/intl/client';
88
import { tcls } from '@/lib/tailwind';
99

1010
import { CustomizationAIMode } from '@gitbook/api';
11+
import { assert } from 'ts-essentials';
1112
import { useTrackEvent } from '../Insights';
1213
import { Loading } from '../primitives';
1314
import { SearchPageResultItem } from './SearchPageResultItem';
@@ -33,9 +34,11 @@ type ResultType =
3334

3435
/**
3536
* We cache the recommended questions globally to avoid calling the API multiple times
36-
* when re-opening the search modal.
37+
* when re-opening the search modal. The cache is per space, so that we can
38+
* have different recommended questions for different spaces of the same site.
39+
* It should not be used outside of an useEffect.
3740
*/
38-
let cachedRecommendedQuestions: null | ResultType[] = null;
41+
const cachedRecommendedQuestions: Map<string, ResultType[]> = new Map();
3942

4043
/**
4144
* Fetch the results of the keyboard navigable elements to display for a query:
@@ -49,10 +52,11 @@ export const SearchResults = React.forwardRef(function SearchResults(
4952
query: string;
5053
global: boolean;
5154
aiMode: CustomizationAIMode;
55+
spaceId: string;
5256
},
5357
ref: React.Ref<SearchResultsRef>
5458
) {
55-
const { children, query, aiMode, global } = props;
59+
const { children, query, aiMode, global, spaceId } = props;
5660

5761
const language = useLanguage();
5862
const trackEvent = useTrackEvent();
@@ -73,8 +77,10 @@ export const SearchResults = React.forwardRef(function SearchResults(
7377
return;
7478
}
7579

76-
if (cachedRecommendedQuestions) {
77-
setResultsState({ results: cachedRecommendedQuestions, fetching: false });
80+
if (cachedRecommendedQuestions.has(spaceId)) {
81+
const results = cachedRecommendedQuestions.get(spaceId);
82+
assert(results, `Cached recommended questions should be set for space ${spaceId}`);
83+
setResultsState({ results, fetching: false });
7884
return;
7985
}
8086

@@ -92,7 +98,7 @@ export const SearchResults = React.forwardRef(function SearchResults(
9298
return;
9399
}
94100

95-
const response = await streamRecommendedQuestions();
101+
const response = await streamRecommendedQuestions(spaceId);
96102
for await (const entry of readStreamableValue(response.stream)) {
97103
if (!entry) {
98104
continue;
@@ -109,7 +115,7 @@ export const SearchResults = React.forwardRef(function SearchResults(
109115
id: question,
110116
question,
111117
});
112-
cachedRecommendedQuestions = recommendedQuestions;
118+
cachedRecommendedQuestions.set(spaceId, recommendedQuestions);
113119

114120
if (!cancelled) {
115121
setResultsState({ results: [...recommendedQuestions], fetching: false });

packages/gitbook/src/components/Search/server-actions.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,9 @@ export async function streamAskQuestion({
185185

186186
/**
187187
* Stream a list of suggested questions for the site.
188+
* Optionally scoped to a specific space.
188189
*/
189-
export async function streamRecommendedQuestions() {
190+
export async function streamRecommendedQuestions(spaceId?: string) {
190191
const siteURLData = await getSiteURLDataFromMiddleware();
191192
const context = await getServerActionBaseContext();
192193

@@ -196,7 +197,10 @@ export async function streamRecommendedQuestions() {
196197
const apiClient = await context.dataFetcher.api();
197198
const apiStream = apiClient.orgs.streamRecommendedQuestionsInSite(
198199
siteURLData.organization,
199-
siteURLData.site
200+
siteURLData.site,
201+
{
202+
spaceId,
203+
}
200204
);
201205

202206
for await (const chunk of apiStream) {

packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export function SpaceLayout(props: {
5858
aiMode={aiMode}
5959
isMultiVariants={siteSpaces.length > 1}
6060
spaceTitle={siteSpace.title}
61+
spaceId={siteSpace.space.id}
6162
/>
6263
</React.Suspense>
6364
{aiMode === CustomizationAIMode.Assistant ? (

0 commit comments

Comments
 (0)