6
6
SearchAIAnswer ,
7
7
SearchPageResult ,
8
8
Site ,
9
+ SiteSpace ,
9
10
Space ,
10
11
} from '@gitbook/api' ;
11
- import { headers } from 'next/headers' ;
12
12
13
13
import { getContentPointer } from '@/app/(space)/fetch' ;
14
14
import { streamResponse } from '@/lib/actions' ;
@@ -52,6 +52,61 @@ export interface AskAnswerResult {
52
52
hasAnswer : boolean ;
53
53
}
54
54
55
+ export async function searchSiteContent ( args : {
56
+ query : string ;
57
+ siteSpaceIds ?: string [ ] ;
58
+ cacheBust ?: string ;
59
+ } ) : Promise < OrderedComputedResult [ ] > {
60
+ const { siteSpaceIds, query, cacheBust } = args ;
61
+ const pointer = getContentPointer ( ) ;
62
+
63
+ if ( siteSpaceIds ?. length === 0 ) {
64
+ // if we have no siteSpaces to search in then we won't find anything. skip the call.
65
+ return [ ] ;
66
+ }
67
+
68
+ if ( 'siteId' in pointer && 'organizationId' in pointer ) {
69
+ const [ searchResults , allSiteSpaces ] = await Promise . all ( [
70
+ api . searchSiteContent (
71
+ pointer . organizationId ,
72
+ pointer . siteId ,
73
+ query ,
74
+ siteSpaceIds ,
75
+ cacheBust ,
76
+ ) ,
77
+ siteSpaceIds
78
+ ? null
79
+ : api . getSiteSpaces ( {
80
+ organizationId : pointer . organizationId ,
81
+ siteId : pointer . siteId ,
82
+ siteShareKey : pointer . siteShareKey ,
83
+ } ) ,
84
+ ] ) ;
85
+
86
+ if ( ! siteSpaceIds ) {
87
+ // We are searching all of this Site's content
88
+ return searchResults . items
89
+ . map ( ( spaceItem ) => {
90
+ const siteSpace = allSiteSpaces ?. find (
91
+ ( siteSpace ) => siteSpace . space . id === spaceItem . id ,
92
+ ) ;
93
+
94
+ return spaceItem . pages . map ( ( item ) => transformSitePageResult ( item , siteSpace ) ) ;
95
+ } )
96
+ . flat ( 2 ) ;
97
+ }
98
+
99
+ return searchResults . items
100
+ . map ( ( spaceItem ) => {
101
+ return spaceItem . pages . map ( ( item ) => transformPageResult ( item ) ) ;
102
+ } )
103
+ . flat ( 2 ) ;
104
+ }
105
+
106
+ // This should never happen
107
+ return [ ] ;
108
+ }
109
+
55
110
/**
56
111
* Server action to search content in a space
57
112
*/
@@ -60,6 +115,16 @@ export async function searchSpaceContent(
60
115
revisionId : string ,
61
116
query : string ,
62
117
) : Promise < OrderedComputedResult [ ] > {
118
+ const pointer = getContentPointer ( ) ;
119
+
120
+ if ( 'siteId' in pointer && 'organizationId' in pointer ) {
121
+ const siteSpaceIds = pointer . siteSpaceId ? [ pointer . siteSpaceId ] : [ ] ; // if we don't have a siteSpaceID search all content
122
+
123
+ // This is a site so use a different function which we can eventually call directly
124
+ // We also want to break cache for this specific space if the revisionId is different so use it as a cache busting key
125
+ return await searchSiteContent ( { siteSpaceIds, query, cacheBust : revisionId } ) ;
126
+ }
127
+
63
128
const data = await api . searchSpaceContent ( spaceId , revisionId , query ) ;
64
129
return data . items . map ( ( item ) => transformPageResult ( item , undefined ) ) . flat ( ) ;
65
130
}
@@ -72,36 +137,18 @@ export async function searchParentContent(
72
137
query : string ,
73
138
) : Promise < OrderedComputedResult [ ] > {
74
139
const pointer = getContentPointer ( ) ;
140
+ const isSite = 'siteId' in pointer ;
141
+
142
+ if ( isSite ) {
143
+ return searchSiteContent ( { query } ) ;
144
+ }
75
145
76
- const [ data , collectionSpaces , siteSpaces ] = await Promise . all ( [
146
+ const [ data , collectionSpaces ] = await Promise . all ( [
77
147
api . searchParentContent ( parent . id , query ) ,
78
148
parent . object === 'collection' ? api . getCollectionSpaces ( parent . id ) : null ,
79
- parent . object === 'site' && 'organizationId' in pointer
80
- ? api . getSiteSpaces ( {
81
- organizationId : pointer . organizationId ,
82
- siteId : parent . id ,
83
- siteShareKey : pointer . siteShareKey ,
84
- } )
85
- : null ,
86
149
] ) ;
87
150
88
- let spaces : Space [ ] = [ ] ;
89
-
90
- if ( collectionSpaces ) {
91
- spaces = collectionSpaces ;
92
- } else if ( siteSpaces ) {
93
- spaces = Object . values (
94
- siteSpaces . reduce (
95
- ( acc , siteSpace ) => {
96
- acc [ siteSpace . space . id ] = siteSpace . space ;
97
- // replace the published url for the "space" with the site's published url
98
- acc [ siteSpace . space . id ] . urls . published = siteSpace . urls . published ;
99
- return acc ;
100
- } ,
101
- { } as Record < string , Space > ,
102
- ) ,
103
- ) ;
104
- }
151
+ let spaces : Space [ ] = collectionSpaces ? collectionSpaces : [ ] ;
105
152
106
153
return data . items
107
154
. map ( ( spaceItem ) => {
@@ -183,19 +230,24 @@ function transformAnswer(
183
230
} ;
184
231
}
185
232
186
- function transformPageResult ( item : SearchPageResult , space ?: Space ) {
233
+ function transformSectionsAndPage ( args : {
234
+ item : SearchPageResult ;
235
+ space ?: Space ;
236
+ spaceURL ?: string ;
237
+ } ) : [ ComputedPageResult , ComputedSectionResult [ ] ] {
238
+ const { item, space, spaceURL } = args ;
239
+
187
240
// Resolve a relative path to an absolute URL
188
241
// if the search result is relative to another space, we use the space URL
189
- const getURL = ( path : string ) => {
190
- if ( space ) {
191
- let url = space . urls . published ?? space . urls . app ;
192
- if ( ! url . endsWith ( '/' ) ) {
193
- url += '/' ;
242
+ const getURL = ( path : string , spaceURL ?: string ) => {
243
+ if ( spaceURL ) {
244
+ if ( ! spaceURL . endsWith ( '/' ) ) {
245
+ spaceURL += '/' ;
194
246
}
195
247
if ( path . startsWith ( '/' ) ) {
196
248
path = path . slice ( 1 ) ;
197
249
}
198
- return url + path ;
250
+ return spaceURL + path ;
199
251
} else {
200
252
return absoluteHref ( path ) ;
201
253
}
@@ -206,7 +258,7 @@ function transformPageResult(item: SearchPageResult, space?: Space) {
206
258
type : 'section' ,
207
259
id : item . id + '/' + section . id ,
208
260
title : section . title ,
209
- href : getURL ( section . path ) ,
261
+ href : getURL ( section . path , spaceURL ) ,
210
262
body : section . body ,
211
263
} ) ) ?? [ ] ;
212
264
@@ -218,5 +270,25 @@ function transformPageResult(item: SearchPageResult, space?: Space) {
218
270
spaceTitle : space ?. title ,
219
271
} ;
220
272
273
+ return [ page , sections ] ;
274
+ }
275
+
276
+ function transformSitePageResult ( item : SearchPageResult , siteSpace ?: SiteSpace ) {
277
+ const [ page , sections ] = transformSectionsAndPage ( {
278
+ item,
279
+ space : siteSpace ?. space ,
280
+ spaceURL : siteSpace ?. urls . published ,
281
+ } ) ;
282
+
283
+ return [ page , ...sections ] ;
284
+ }
285
+
286
+ function transformPageResult ( item : SearchPageResult , space ?: Space ) {
287
+ const [ page , sections ] = transformSectionsAndPage ( {
288
+ item,
289
+ space,
290
+ spaceURL : space ?. urls . published ?? space ?. urls . app ,
291
+ } ) ;
292
+
221
293
return [ page , ...sections ] ;
222
294
}
0 commit comments