11import { search as unifiedSearch } from './UnifiedSearchService.js'
22
3- type SearchItemStatus = 'loading' | 'loaded' | 'failed' | 'blocked'
3+ type CategorySearchStatus = 'loading' | 'loaded' | 'failed' | 'blocked'
44
55export const REVEAL_INTERVAL = 1500 // milliseconds
66
7- type CategorySearchItem = {
8- status : SearchItemStatus
7+ type CategorySearchState = {
8+ status : CategorySearchStatus
99 entries : unknown [ ]
1010 cursor : string | null
1111 hasMore : boolean
@@ -18,10 +18,10 @@ type CategorySearchItem = {
1818 */
1919export class UnifiedSearchController {
2020 private query : string = ''
21- private searchItems : Record < string , CategorySearchItem > = { }
22- private requestId : number = 0
21+ private searchStates : Record < string , CategorySearchState > = { }
22+ private searchGeneration : number = 0
2323 private revealTimer : ReturnType < typeof setTimeout > | null = null
24- private searchAbortHandlers : ( ( ) => void ) [ ] = [ ]
24+ private pendingCancels : ( ( ) => void ) [ ] = [ ]
2525
2626 /**
2727 * Start a search. Cancels and replaces any search already in flight.
@@ -31,15 +31,15 @@ export class UnifiedSearchController {
3131 */
3232 search ( query : string , categories : string [ ] ) : void {
3333 this . cancelPendingRequests ( )
34- this . searchItems = { }
35- this . requestId ++
36- const dispatchId = this . requestId
34+ this . searchStates = { }
35+ this . searchGeneration ++
36+ const generation = this . searchGeneration
3737 this . query = query
3838
3939 this . startRevealTimer ( )
4040
4141 categories . forEach ( ( category ) => {
42- this . searchItems [ category ] = {
42+ this . searchStates [ category ] = {
4343 status : 'loading' ,
4444 entries : [ ] ,
4545 cursor : null ,
@@ -52,16 +52,16 @@ export class UnifiedSearchController {
5252 cursor : null ,
5353 } )
5454
55- this . searchAbortHandlers . push ( cancel )
55+ this . pendingCancels . push ( cancel )
5656
5757 request ( ) . then ( ( response ) => {
58- if ( this . requestId !== dispatchId ) {
58+ if ( this . searchGeneration !== generation ) {
5959 // A new search has been started, ignore this result
6060 return
6161 }
6262
6363 const { entries, cursor, hasMore } = response . data . ocs . data
64- this . searchItems [ category ] = {
64+ this . searchStates [ category ] = {
6565 status : 'loaded' ,
6666 entries,
6767 cursor,
@@ -71,10 +71,10 @@ export class UnifiedSearchController {
7171
7272 this . reconcileCategoryStatuses ( categories )
7373 } ) . catch ( ( ) => {
74- if ( this . requestId !== dispatchId ) {
74+ if ( this . searchGeneration !== generation ) {
7575 return
7676 }
77- this . searchItems [ category ] = {
77+ this . searchStates [ category ] = {
7878 status : 'failed' ,
7979 entries : [ ] ,
8080 cursor : null ,
@@ -94,47 +94,47 @@ export class UnifiedSearchController {
9494 * @param category the category id to page
9595 */
9696 loadMore ( category : string ) : void {
97- const dispatchId = this . requestId
98- const categoryItem = this . searchItems [ category ]
99- if ( ! categoryItem || ! categoryItem . hasMore || categoryItem . status !== 'loaded' ) {
97+ const generation = this . searchGeneration
98+ const categoryState = this . searchStates [ category ]
99+ if ( ! categoryState || ! categoryState . hasMore || categoryState . status !== 'loaded' ) {
100100 return
101101 }
102- categoryItem . status = 'loading'
103- categoryItem . loadMoreFailed = false
102+ categoryState . status = 'loading'
103+ categoryState . loadMoreFailed = false
104104
105105 const { request, cancel } = unifiedSearch ( {
106106 type : category ,
107107 query : this . query ,
108- cursor : categoryItem . cursor ,
108+ cursor : categoryState . cursor ,
109109 } )
110110
111- this . searchAbortHandlers . push ( cancel )
111+ this . pendingCancels . push ( cancel )
112112
113113 request ( ) . then ( ( response ) => {
114- if ( this . requestId !== dispatchId ) {
114+ if ( this . searchGeneration !== generation ) {
115115 return
116116 }
117117 const { entries, cursor, hasMore } = response . data . ocs . data
118- categoryItem . entries . push ( ...entries )
119- categoryItem . cursor = cursor
120- categoryItem . hasMore = hasMore
121- categoryItem . status = 'loaded'
118+ categoryState . entries . push ( ...entries )
119+ categoryState . cursor = cursor
120+ categoryState . hasMore = hasMore
121+ categoryState . status = 'loaded'
122122 } ) . catch ( ( ) => {
123- if ( this . requestId !== dispatchId ) {
123+ if ( this . searchGeneration !== generation ) {
124124 return
125125 }
126- categoryItem . status = 'loaded'
127- categoryItem . loadMoreFailed = true
126+ categoryState . status = 'loaded'
127+ categoryState . loadMoreFailed = true
128128 } )
129129 }
130130
131131 /**
132132 * A shallow copy of the current per-category state, safe to read for rendering.
133133 *
134- * @return the current search items keyed by category id
134+ * @return the current search states keyed by category id
135135 */
136- getSnapshot ( ) : Record < string , CategorySearchItem > {
137- return { ...this . searchItems }
136+ getSnapshot ( ) : Record < string , CategorySearchState > {
137+ return { ...this . searchStates }
138138 }
139139
140140 /**
@@ -147,18 +147,18 @@ export class UnifiedSearchController {
147147
148148 private reconcileCategoryStatuses ( categories : string [ ] ) : void {
149149 categories . forEach ( ( category ) => {
150- if ( [ 'loading' , 'failed' ] . includes ( this . searchItems [ category ] . status ) ) {
150+ if ( [ 'loading' , 'failed' ] . includes ( this . searchStates [ category ] . status ) ) {
151151 return
152152 }
153- this . searchItems [ category ] . status = this . categoryShouldBlock ( category , categories ) ? 'blocked' : 'loaded'
153+ this . searchStates [ category ] . status = this . shouldBlockCategory ( category , categories ) ? 'blocked' : 'loaded'
154154 } )
155155 }
156156
157157 private startRevealTimer ( ) : void {
158158 this . stopRevealTimer ( )
159159 this . revealTimer = setTimeout ( ( ) => {
160- const categories = Object . keys ( this . searchItems )
161- const hasPendingCategories = categories . some ( ( category ) => [ 'loading' , 'blocked' ] . includes ( this . searchItems [ category ] . status ) )
160+ const categories = Object . keys ( this . searchStates )
161+ const hasPendingCategories = categories . some ( ( category ) => [ 'loading' , 'blocked' ] . includes ( this . searchStates [ category ] . status ) )
162162 this . unblockAllCategories ( categories )
163163 if ( hasPendingCategories ) {
164164 this . startRevealTimer ( )
@@ -174,27 +174,26 @@ export class UnifiedSearchController {
174174 }
175175
176176 private cancelPendingRequests ( ) : void {
177- this . searchAbortHandlers . forEach ( ( cancel ) => cancel ( ) )
178- this . searchAbortHandlers = [ ]
177+ this . pendingCancels . forEach ( ( cancel ) => cancel ( ) )
178+ this . pendingCancels = [ ]
179179 }
180180
181181 private unblockAllCategories ( categories : string [ ] ) : void {
182182 categories . forEach ( ( category ) => {
183- if ( this . searchItems [ category ] . status === 'blocked' ) {
184- this . searchItems [ category ] . status = 'loaded'
183+ if ( this . searchStates [ category ] . status === 'blocked' ) {
184+ this . searchStates [ category ] . status = 'loaded'
185185 }
186186 } )
187187 }
188188
189- private categoryShouldBlock ( category : string , categories : string [ ] ) : boolean {
190- const categoryItem = this . searchItems [ category ]
191- if ( ! categoryItem ) {
189+ private shouldBlockCategory ( category : string , categories : string [ ] ) : boolean {
190+ if ( ! this . searchStates [ category ] ) {
192191 return false
193192 }
194193
195194 return categories . slice ( 0 , categories . indexOf ( category ) ) . some ( ( c ) => {
196- const item = this . searchItems [ c ]
197- return item && [ 'loading' , 'blocked' ] . includes ( item . status )
195+ const categoryState = this . searchStates [ c ]
196+ return categoryState && [ 'loading' , 'blocked' ] . includes ( categoryState . status )
198197 } )
199198 }
200199}
0 commit comments