22
33import { RevisionPage , SearchAIAnswer , SearchPageResult , SiteSpace , Space } from '@gitbook/api' ;
44import * as React from 'react' ;
5+ import { assert } from 'ts-essentials' ;
56
67import { streamResponse } from '@/lib/actions' ;
78import * as api from '@/lib/api' ;
@@ -45,47 +46,61 @@ export interface AskAnswerResult {
4546}
4647
4748/**
48- * Search for content in the entire site .
49+ * Search for content in a site by scoping the search to all content, a specific spaces or current space .
4950 */
50- export async function searchSiteContent ( args : {
51+ async function searchSiteContent ( args : {
5152 pointer : api . SiteContentPointer ;
5253 query : string ;
53- siteSpaceIds ?: string [ ] ;
54+ scope :
55+ | { mode : 'all' }
56+ | { mode : 'current' ; siteSpaceId : string }
57+ | { mode : 'specific' ; siteSpaceIds : string [ ] } ;
5458 cacheBust ?: string ;
5559} ) : Promise < OrderedComputedResult [ ] > {
56- const { pointer, siteSpaceIds , query, cacheBust } = args ;
60+ const { pointer, scope , query, cacheBust } = args ;
5761
5862 if ( query . length <= 1 ) {
5963 return [ ] ;
6064 }
6165
62- if ( siteSpaceIds ?. length === 0 ) {
63- // if we have no siteSpaces to search in then we won't find anything. skip the call.
64- return [ ] ;
65- }
66+ const needsStructure =
67+ scope . mode === 'all' ||
68+ scope . mode === 'current' ||
69+ ( scope . mode === 'specific' && scope . siteSpaceIds . length > 1 ) ;
6670
67- const [ searchResults , allSiteSpaces ] = await Promise . all ( [
68- api . searchSiteContent (
69- pointer . organizationId ,
70- pointer . siteId ,
71- query ,
72- siteSpaceIds ,
73- cacheBust ,
74- ) ,
75- siteSpaceIds
76- ? null
77- : api . getSiteSpaces ( {
71+ const [ searchResults , siteStructure ] = await Promise . all ( [
72+ api . searchSiteContent ( pointer . organizationId , pointer . siteId , query , scope , cacheBust ) ,
73+ needsStructure
74+ ? api . getSiteStructure ( {
7875 organizationId : pointer . organizationId ,
7976 siteId : pointer . siteId ,
8077 siteShareKey : pointer . siteShareKey ,
81- } ) ,
78+ } )
79+ : null ,
8280 ] ) ;
8381
84- if ( ! siteSpaceIds ) {
82+ const siteSpaces = siteStructure
83+ ? siteStructure . type === 'siteSpaces'
84+ ? siteStructure . structure
85+ : siteStructure . structure . reduce < SiteSpace [ ] > ( ( prev , section ) => {
86+ const sectionSiteSpaces = section . siteSpaces . map ( ( siteSpace ) => ( {
87+ ...siteSpace ,
88+ space : {
89+ ...siteSpace . space ,
90+ title : section . title + ' › ' + siteSpace . space . title ,
91+ } ,
92+ } ) ) ;
93+
94+ prev . push ( ...sectionSiteSpaces ) ;
95+ return prev ;
96+ } , [ ] )
97+ : null ;
98+
99+ if ( siteSpaces ) {
85100 // We are searching all of this Site's content
86101 return searchResults . items
87102 . map ( ( spaceItem ) => {
88- const siteSpace = allSiteSpaces ? .find (
103+ const siteSpace = siteSpaces . find (
89104 ( siteSpace ) => siteSpace . space . id === spaceItem . id ,
90105 ) ;
91106
@@ -102,21 +117,39 @@ export async function searchSiteContent(args: {
102117}
103118
104119/**
105- * Server action to search content in the current space
120+ * Server action to search content in the entire site.
121+ */
122+ export async function searchAllSiteContent (
123+ query : string ,
124+ pointer : api . SiteContentPointer ,
125+ ) : Promise < OrderedComputedResult [ ] > {
126+ return await searchSiteContent ( {
127+ pointer,
128+ query,
129+ scope : { mode : 'all' } ,
130+ } ) ;
131+ }
132+
133+ /**
134+ * Server action to search content in a space.
106135 */
107- export async function searchCurrentSpaceContent (
136+ export async function searchSiteSpaceContent (
108137 query : string ,
109138 pointer : api . SiteContentPointer ,
110139 revisionId : string ,
111140) : Promise < OrderedComputedResult [ ] > {
112- const siteSpaceIds = pointer . siteSpaceId ? [ pointer . siteSpaceId ] : [ ] ; // if we don't have a siteSpaceID search all content
141+ const siteSpaceId = pointer . siteSpaceId ;
142+ assert ( siteSpaceId , 'Expected siteSpaceId for searchSiteSpaceContent' ) ;
113143
114- // This is a site so use a different function which we can eventually call directly
115- // We also want to break cache for this specific space if the revisionId is different so use it as a cache busting key
116144 return await searchSiteContent ( {
117145 pointer,
118- siteSpaceIds,
119146 query,
147+ // If we have a siteSectionId that means its a sections site use `current` mode
148+ // which searches in the current space + all default spaces of sections
149+ scope : pointer . siteSectionId
150+ ? { mode : 'current' , siteSpaceId }
151+ : { mode : 'specific' , siteSpaceIds : [ siteSpaceId ] } ,
152+ // We want to break cache for this specific space if the revisionId is different so use it as a cache busting key
120153 cacheBust : revisionId ,
121154 } ) ;
122155}
0 commit comments