@internetarchive/collection-browser 1.14.17-alpha.4 → 1.14.17-alpha.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/src/collection-browser.d.ts +6 -13
- package/dist/src/collection-browser.js +56 -30
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/data-source/collection-browser-data-source-interface.d.ts +194 -0
- package/dist/src/data-source/collection-browser-data-source-interface.js +2 -0
- package/dist/src/data-source/collection-browser-data-source-interface.js.map +1 -0
- package/dist/src/data-source/collection-browser-data-source.d.ts +62 -174
- package/dist/src/data-source/collection-browser-data-source.js +185 -64
- package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
- package/dist/src/data-source/collection-browser-query-state.d.ts +42 -0
- package/dist/src/data-source/collection-browser-query-state.js +2 -0
- package/dist/src/data-source/collection-browser-query-state.js.map +1 -0
- package/dist/src/data-source/models.d.ts +1 -39
- package/dist/src/data-source/models.js.map +1 -1
- package/dist/src/models.d.ts +3 -2
- package/dist/src/models.js +24 -22
- package/dist/src/models.js.map +1 -1
- package/dist/src/sort-filter-bar/sort-filter-bar.js +1 -0
- package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
- package/dist/src/tiles/grid/item-tile.d.ts +1 -0
- package/dist/src/tiles/grid/item-tile.js +28 -1
- package/dist/src/tiles/grid/item-tile.js.map +1 -1
- package/dist/src/tiles/grid/tile-stats.js +13 -8
- package/dist/src/tiles/grid/tile-stats.js.map +1 -1
- package/dist/src/tiles/item-image.d.ts +3 -0
- package/dist/src/tiles/item-image.js +30 -2
- package/dist/src/tiles/item-image.js.map +1 -1
- package/dist/src/tiles/list/tile-list.d.ts +1 -0
- package/dist/src/tiles/list/tile-list.js +30 -1
- package/dist/src/tiles/list/tile-list.js.map +1 -1
- package/dist/src/tiles/tile-dispatcher.js +3 -2
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/src/tiles/tile-display-value-provider.d.ts +5 -1
- package/dist/src/tiles/tile-display-value-provider.js +15 -1
- package/dist/src/tiles/tile-display-value-provider.js.map +1 -1
- package/dist/test/collection-browser.test.js +2 -6
- package/dist/test/collection-browser.test.js.map +1 -1
- package/index.ts +3 -5
- package/package.json +2 -2
- package/src/collection-browser.ts +70 -49
- package/src/data-source/collection-browser-data-source-interface.ts +245 -0
- package/src/data-source/collection-browser-data-source.ts +237 -281
- package/src/data-source/collection-browser-query-state.ts +53 -0
- package/src/data-source/models.ts +0 -47
- package/src/models.ts +7 -3
- package/src/sort-filter-bar/sort-filter-bar.ts +1 -0
- package/src/tiles/grid/item-tile.ts +36 -1
- package/src/tiles/grid/tile-stats.ts +12 -7
- package/src/tiles/item-image.ts +28 -0
- package/src/tiles/list/tile-list.ts +37 -1
- package/src/tiles/tile-dispatcher.ts +2 -1
- package/src/tiles/tile-display-value-provider.ts +19 -1
- package/test/collection-browser.test.ts +2 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ReactiveControllerHost } from 'lit';
|
|
2
2
|
import {
|
|
3
3
|
AccountExtraInfo,
|
|
4
4
|
Aggregation,
|
|
@@ -20,283 +20,120 @@ import {
|
|
|
20
20
|
PrefixFilterCounts,
|
|
21
21
|
RequestKind,
|
|
22
22
|
} from '../models';
|
|
23
|
-
import type {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
PageSpecifierParams,
|
|
27
|
-
} from './models';
|
|
23
|
+
import type { PageSpecifierParams } from './models';
|
|
24
|
+
import type { CollectionBrowserDataSourceInterface } from './collection-browser-data-source-interface';
|
|
25
|
+
import type { CollectionBrowserSearchInterface } from './collection-browser-query-state';
|
|
28
26
|
import { sha1 } from '../utils/sha1';
|
|
29
27
|
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*/
|
|
35
|
-
readonly size: number;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Whether the host has a valid set of properties for performing a search.
|
|
39
|
-
* For instance, on the search page this requires a valid search service and a
|
|
40
|
-
* non-empty query, while collection pages allow searching with an empty query
|
|
41
|
-
* for MDS but not FTS.
|
|
42
|
-
*/
|
|
43
|
-
readonly canPerformSearch: boolean;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Whether the end of the set of results for the current query state has been
|
|
47
|
-
* encountered (i.e., the last page of results).
|
|
48
|
-
*/
|
|
49
|
-
readonly endOfDataReached: boolean;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* A string key compactly representing the current full search state, which can
|
|
53
|
-
* be used to determine, e.g., when a new search is required or whether an arriving
|
|
54
|
-
* response is outdated.
|
|
55
|
-
*/
|
|
56
|
-
readonly pageFetchQueryKey: string;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Similar to `pageFetchQueryKey`, but excluding properties that do not affect
|
|
60
|
-
* the validity of a set of facets (e.g., sort).
|
|
61
|
-
*/
|
|
62
|
-
readonly facetFetchQueryKey: string;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* An object representing any collection- or profile-specific properties to be passed along
|
|
66
|
-
* to the search service, specifying the exact page/tab to fetch results for.
|
|
67
|
-
*/
|
|
68
|
-
readonly pageSpecifierParams: PageSpecifierParams | null;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* A FilterMap object representing all filters applied to the current search,
|
|
72
|
-
* including any facets, letter filters, and date ranges.
|
|
73
|
-
*/
|
|
74
|
-
readonly filterMap: FilterMap;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* The full set of aggregations retrieved for the current search.
|
|
78
|
-
*/
|
|
79
|
-
readonly aggregations?: Record<string, Aggregation>;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* The `year_histogram` aggregation retrieved for the current search.
|
|
83
|
-
*/
|
|
84
|
-
readonly yearHistogramAggregation?: Aggregation;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* A map from collection identifiers that appear on hits or aggregations for the
|
|
88
|
-
* current search, to their human-readable collection titles.
|
|
89
|
-
*/
|
|
90
|
-
readonly collectionTitles: CollectionTitles;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* The "extra info" package provided by the PPS for collection pages, including details
|
|
94
|
-
* used to populate the target collection header & About tab content.
|
|
95
|
-
*/
|
|
96
|
-
readonly collectionExtraInfo?: CollectionExtraInfo;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* The "extra info" package provided by the PPS for profile pages, including details
|
|
100
|
-
* used to populate the profile header.
|
|
101
|
-
*/
|
|
102
|
-
readonly accountExtraInfo?: AccountExtraInfo;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* The set of requested page elements for profile pages, if applicable. These represent
|
|
106
|
-
* any content specific to the current profile tab.
|
|
107
|
-
*/
|
|
108
|
-
readonly pageElements?: PageElementMap;
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* An array of the current target collection's parent collections. Should include *all*
|
|
112
|
-
* ancestors in the collection hierarchy, not just the immediate parent.
|
|
113
|
-
*/
|
|
114
|
-
readonly parentCollections?: string[];
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* An object storing result counts for the current search bucketed by letter prefix.
|
|
118
|
-
* Keys are the result field on which the prefixes are considered (e.g., title/creator)
|
|
119
|
-
* and values are a Record mapping letters to their counts.
|
|
120
|
-
*/
|
|
121
|
-
readonly prefixFilterCountMap: Partial<
|
|
122
|
-
Record<PrefixFilterType, PrefixFilterCounts>
|
|
123
|
-
>;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* An array of all the tile models whose management checkboxes are checked
|
|
127
|
-
*/
|
|
128
|
-
readonly checkedTileModels: TileModel[];
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* An array of all the tile models whose management checkboxes are unchecked
|
|
132
|
-
*/
|
|
133
|
-
readonly uncheckedTileModels: TileModel[];
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Resets the data source to its empty state, with no result pages, aggregations, etc.
|
|
137
|
-
*/
|
|
138
|
-
reset(): void;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Adds the given page of tile models to the data source.
|
|
142
|
-
* If the given page number already exists, that page will be overwritten.
|
|
143
|
-
* @param pageNum Which page number to add (indexed starting from 1)
|
|
144
|
-
* @param pageTiles The array of tile models for the new page
|
|
145
|
-
*/
|
|
146
|
-
addPage(pageNum: number, pageTiles: TileModel[]): void;
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Returns the given page of tile models from the data source.
|
|
150
|
-
* @param pageNum Which page number to get (indexed starting from 1)
|
|
151
|
-
*/
|
|
152
|
-
getPage(pageNum: number): TileModel[];
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Returns the full set of paged tile models stored in this data source.
|
|
156
|
-
*/
|
|
157
|
-
getAllPages(): Record<string, TileModel[]>;
|
|
28
|
+
export class CollectionBrowserDataSource
|
|
29
|
+
implements CollectionBrowserDataSourceInterface
|
|
30
|
+
{
|
|
31
|
+
private pages: Record<string, TileModel[]> = {};
|
|
158
32
|
|
|
159
|
-
|
|
160
|
-
* Whether the data source contains any tiles for the given page number.
|
|
161
|
-
* @param pageNum Which page number to query (indexed starting from 1)
|
|
162
|
-
*/
|
|
163
|
-
hasPage(pageNum: number): boolean;
|
|
33
|
+
private offset = 0;
|
|
164
34
|
|
|
165
|
-
|
|
166
|
-
* Returns the single tile model appearing at the given index in the
|
|
167
|
-
* data source, with respect to the current page size. Returns `undefined` if
|
|
168
|
-
* the corresponding page is not present on the data source or if it does not
|
|
169
|
-
* contain a tile model at the corresponding index.
|
|
170
|
-
* @param index The 0-based index (within the full data source) of the tile to get
|
|
171
|
-
*/
|
|
172
|
-
getTileModelAt(index: number): TileModel | undefined;
|
|
35
|
+
private numTileModels = 0;
|
|
173
36
|
|
|
174
37
|
/**
|
|
175
|
-
*
|
|
176
|
-
* or -1 if the given tile model is not present.
|
|
177
|
-
* @param tile The tile model to search for in the data source
|
|
38
|
+
* A set of fetch IDs that are valid for the current query state
|
|
178
39
|
*/
|
|
179
|
-
|
|
40
|
+
private fetchesInProgress = new Set<string>();
|
|
180
41
|
|
|
181
42
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* @param numInitialPages How many pages should be batched together on an initial fetch
|
|
43
|
+
* A record of the query key used for the last search.
|
|
44
|
+
* If this changes, we need to load new results.
|
|
185
45
|
*/
|
|
186
|
-
|
|
46
|
+
private previousQueryKey: string = '';
|
|
187
47
|
|
|
188
|
-
|
|
189
|
-
* Requests that the data source update its prefix bucket result counts for the given
|
|
190
|
-
* type of prefix filter.
|
|
191
|
-
* @param filterType Which prefixable field to update the buckets for (e.g., title/creator)
|
|
192
|
-
*/
|
|
193
|
-
updatePrefixFilterCounts(filterType: PrefixFilterType): Promise<void>;
|
|
48
|
+
private searchResultsLoading = false;
|
|
194
49
|
|
|
195
|
-
|
|
196
|
-
* Changes the page size used by the data source, discarding any previously-fetched pages.
|
|
197
|
-
*
|
|
198
|
-
* **Note: this operation will reset any data stored in the data source!**
|
|
199
|
-
* @param pageSize
|
|
200
|
-
*/
|
|
201
|
-
setPageSize(pageSize: number): void;
|
|
50
|
+
private facetsLoading = false;
|
|
202
51
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
* reset & new fetches.
|
|
206
|
-
*/
|
|
207
|
-
handleQueryChange(): void;
|
|
52
|
+
// TEMP for ease of debugging
|
|
53
|
+
private id = Math.random();
|
|
208
54
|
|
|
209
55
|
/**
|
|
210
|
-
*
|
|
211
|
-
* source.
|
|
212
|
-
* @param callback A callback function to apply on each tile model, as with Array.map
|
|
56
|
+
* @inheritdoc
|
|
213
57
|
*/
|
|
214
|
-
|
|
215
|
-
callback: (model: TileModel, index: number, array: TileModel[]) => TileModel
|
|
216
|
-
): void;
|
|
58
|
+
totalResults = 0;
|
|
217
59
|
|
|
218
60
|
/**
|
|
219
|
-
*
|
|
61
|
+
* @inheritdoc
|
|
220
62
|
*/
|
|
221
|
-
|
|
63
|
+
endOfDataReached = false;
|
|
222
64
|
|
|
223
65
|
/**
|
|
224
|
-
*
|
|
66
|
+
* @inheritdoc
|
|
225
67
|
*/
|
|
226
|
-
|
|
68
|
+
queryInitialized = false;
|
|
227
69
|
|
|
228
70
|
/**
|
|
229
|
-
*
|
|
230
|
-
* of the data source to account for any new gaps in the data.
|
|
71
|
+
* @inheritdoc
|
|
231
72
|
*/
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export class CollectionBrowserDataSource
|
|
236
|
-
implements CollectionBrowserDataSourceInterface
|
|
237
|
-
{
|
|
238
|
-
private pages: Record<string, TileModel[]> = {};
|
|
239
|
-
|
|
240
|
-
private offset = 0;
|
|
241
|
-
|
|
242
|
-
private numTileModels = 0;
|
|
73
|
+
aggregations?: Record<string, Aggregation>;
|
|
243
74
|
|
|
244
75
|
/**
|
|
245
|
-
*
|
|
76
|
+
* @inheritdoc
|
|
246
77
|
*/
|
|
247
|
-
|
|
78
|
+
yearHistogramAggregation?: Aggregation;
|
|
248
79
|
|
|
249
80
|
/**
|
|
250
81
|
* @inheritdoc
|
|
251
82
|
*/
|
|
252
|
-
|
|
83
|
+
collectionTitles = new Map<string, string>();
|
|
253
84
|
|
|
254
85
|
/**
|
|
255
86
|
* @inheritdoc
|
|
256
87
|
*/
|
|
257
|
-
|
|
88
|
+
collectionExtraInfo?: CollectionExtraInfo;
|
|
258
89
|
|
|
259
90
|
/**
|
|
260
91
|
* @inheritdoc
|
|
261
92
|
*/
|
|
262
|
-
|
|
93
|
+
accountExtraInfo?: AccountExtraInfo;
|
|
263
94
|
|
|
264
95
|
/**
|
|
265
96
|
* @inheritdoc
|
|
266
97
|
*/
|
|
267
|
-
|
|
98
|
+
pageElements?: PageElementMap;
|
|
268
99
|
|
|
269
100
|
/**
|
|
270
101
|
* @inheritdoc
|
|
271
102
|
*/
|
|
272
|
-
|
|
103
|
+
parentCollections?: string[] = [];
|
|
273
104
|
|
|
274
105
|
/**
|
|
275
106
|
* @inheritdoc
|
|
276
107
|
*/
|
|
277
|
-
|
|
108
|
+
prefixFilterCountMap: Partial<Record<PrefixFilterType, PrefixFilterCounts>> =
|
|
109
|
+
{};
|
|
278
110
|
|
|
279
111
|
/**
|
|
280
112
|
* @inheritdoc
|
|
281
113
|
*/
|
|
282
|
-
|
|
114
|
+
queryErrorMessage?: string;
|
|
283
115
|
|
|
284
116
|
/**
|
|
285
|
-
*
|
|
117
|
+
* Internal property to store the `resolve` function for the most recent
|
|
118
|
+
* `initialSearchComplete` promise, allowing us to resolve it at the appropriate time.
|
|
286
119
|
*/
|
|
287
|
-
|
|
120
|
+
private _initialSearchCompleteResolver!: (val: boolean) => void;
|
|
288
121
|
|
|
289
122
|
/**
|
|
290
|
-
*
|
|
123
|
+
* Internal property to store the private value backing the `initialSearchComplete` getter.
|
|
291
124
|
*/
|
|
292
|
-
|
|
125
|
+
private _initialSearchCompletePromise: Promise<boolean> = new Promise(res => {
|
|
126
|
+
this._initialSearchCompleteResolver = res;
|
|
127
|
+
});
|
|
293
128
|
|
|
294
129
|
/**
|
|
295
130
|
* @inheritdoc
|
|
296
131
|
*/
|
|
297
|
-
|
|
298
|
-
|
|
132
|
+
get initialSearchComplete(): Promise<boolean> {
|
|
133
|
+
return this._initialSearchCompletePromise;
|
|
134
|
+
}
|
|
299
135
|
|
|
136
|
+
// eslint-disable-next-line no-useless-constructor
|
|
300
137
|
constructor(
|
|
301
138
|
/** The host element to which this controller should attach listeners */
|
|
302
139
|
private readonly host: ReactiveControllerHost &
|
|
@@ -304,7 +141,56 @@ export class CollectionBrowserDataSource
|
|
|
304
141
|
/** Default size of result pages */
|
|
305
142
|
private pageSize: number
|
|
306
143
|
) {
|
|
307
|
-
|
|
144
|
+
// Just setting some property values
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
hostConnected(): void {
|
|
148
|
+
console.log('hostConnected', this.id);
|
|
149
|
+
this.setSearchResultsLoading(this.searchResultsLoading);
|
|
150
|
+
this.setFacetsLoading(this.facetsLoading);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
hostUpdate(): void {
|
|
154
|
+
console.log(
|
|
155
|
+
'hostUpdate',
|
|
156
|
+
this.id,
|
|
157
|
+
this.previousQueryKey,
|
|
158
|
+
this.pageFetchQueryKey
|
|
159
|
+
);
|
|
160
|
+
// This reactive controller hook is run whenever the host component (collection-browser) performs an update.
|
|
161
|
+
// We check whether the host's state has changed in a way which should trigger a reset & new results fetch.
|
|
162
|
+
|
|
163
|
+
// Only the currently-installed data source should react to the update
|
|
164
|
+
if (!this.activeOnHost) return;
|
|
165
|
+
|
|
166
|
+
// Copy loading states onto the host
|
|
167
|
+
this.setSearchResultsLoading(this.searchResultsLoading);
|
|
168
|
+
this.setFacetsLoading(this.facetsLoading);
|
|
169
|
+
|
|
170
|
+
// Can't perform searches without a search service
|
|
171
|
+
if (!this.host.searchService) return;
|
|
172
|
+
|
|
173
|
+
// We should only reset if part of the full query state has changed
|
|
174
|
+
const queryKeyChanged = this.pageFetchQueryKey !== this.previousQueryKey;
|
|
175
|
+
console.log('query keys', this.pageFetchQueryKey, this.previousQueryKey);
|
|
176
|
+
if (!queryKeyChanged) return;
|
|
177
|
+
|
|
178
|
+
// We should only reset if either:
|
|
179
|
+
// (a) our state permits a valid search, or
|
|
180
|
+
// (b) we have a blank query that we want to show empty results for
|
|
181
|
+
const shouldShowEmptyQueryResults =
|
|
182
|
+
this.host.clearResultsOnEmptyQuery && this.host.baseQuery === '';
|
|
183
|
+
if (!(this.canPerformSearch || shouldShowEmptyQueryResults)) return;
|
|
184
|
+
|
|
185
|
+
if (this.activeOnHost) this.host.emitQueryStateChanged();
|
|
186
|
+
this.handleQueryChange();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Returns whether this data source is the one currently installed on the host component.
|
|
191
|
+
*/
|
|
192
|
+
private get activeOnHost(): boolean {
|
|
193
|
+
return this.host.dataSource === this;
|
|
308
194
|
}
|
|
309
195
|
|
|
310
196
|
/**
|
|
@@ -318,20 +204,27 @@ export class CollectionBrowserDataSource
|
|
|
318
204
|
* @inheritdoc
|
|
319
205
|
*/
|
|
320
206
|
reset(): void {
|
|
207
|
+
console.log('resetting data source', this.id);
|
|
321
208
|
this.pages = {};
|
|
322
209
|
this.aggregations = {};
|
|
323
210
|
this.yearHistogramAggregation = undefined;
|
|
324
|
-
this.pageFetchesInProgress = {};
|
|
325
211
|
this.pageElements = undefined;
|
|
326
212
|
this.parentCollections = [];
|
|
327
213
|
this.prefixFilterCountMap = {};
|
|
214
|
+
this.queryErrorMessage = undefined;
|
|
328
215
|
|
|
329
216
|
this.offset = 0;
|
|
330
217
|
this.numTileModels = 0;
|
|
331
218
|
this.totalResults = 0;
|
|
332
219
|
this.endOfDataReached = false;
|
|
220
|
+
this.queryInitialized = false;
|
|
333
221
|
|
|
334
|
-
|
|
222
|
+
// Invalidate any fetches in progress
|
|
223
|
+
this.fetchesInProgress.clear();
|
|
224
|
+
console.log('fetches cleared - size =', this.fetchesInProgress.size);
|
|
225
|
+
|
|
226
|
+
if (this.activeOnHost) this.host.setTotalResultCount(0);
|
|
227
|
+
this.requestHostUpdate();
|
|
335
228
|
}
|
|
336
229
|
|
|
337
230
|
/**
|
|
@@ -340,7 +233,7 @@ export class CollectionBrowserDataSource
|
|
|
340
233
|
addPage(pageNum: number, pageTiles: TileModel[]): void {
|
|
341
234
|
this.pages[pageNum] = pageTiles;
|
|
342
235
|
this.numTileModels += pageTiles.length;
|
|
343
|
-
this.
|
|
236
|
+
this.requestHostUpdate();
|
|
344
237
|
}
|
|
345
238
|
|
|
346
239
|
/**
|
|
@@ -393,10 +286,21 @@ export class CollectionBrowserDataSource
|
|
|
393
286
|
*/
|
|
394
287
|
async handleQueryChange(): Promise<void> {
|
|
395
288
|
this.reset();
|
|
289
|
+
|
|
290
|
+
// Reset the `initialSearchComplete` promise with a new value for the imminent search
|
|
291
|
+
this._initialSearchCompletePromise = new Promise(res => {
|
|
292
|
+
this._initialSearchCompleteResolver = res;
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Fire the initial page & facet requests
|
|
296
|
+
this.queryInitialized = true;
|
|
396
297
|
await Promise.all([
|
|
397
298
|
this.doInitialPageFetch(),
|
|
398
299
|
this.host.suppressFacets ? null : this.fetchFacets(),
|
|
399
300
|
]);
|
|
301
|
+
|
|
302
|
+
// Resolve the `initialSearchComplete` promise for this search
|
|
303
|
+
this._initialSearchCompleteResolver(true);
|
|
400
304
|
}
|
|
401
305
|
|
|
402
306
|
/**
|
|
@@ -413,8 +317,8 @@ export class CollectionBrowserDataSource
|
|
|
413
317
|
),
|
|
414
318
|
])
|
|
415
319
|
);
|
|
416
|
-
this.
|
|
417
|
-
this.
|
|
320
|
+
this.requestHostUpdate();
|
|
321
|
+
this.refreshVisibleResults();
|
|
418
322
|
}
|
|
419
323
|
|
|
420
324
|
/**
|
|
@@ -479,8 +383,8 @@ export class CollectionBrowserDataSource
|
|
|
479
383
|
// Swap in the new pages
|
|
480
384
|
this.pages = newPages;
|
|
481
385
|
this.numTileModels -= numChecked;
|
|
482
|
-
this.
|
|
483
|
-
this.
|
|
386
|
+
this.requestHostUpdate();
|
|
387
|
+
this.refreshVisibleResults();
|
|
484
388
|
};
|
|
485
389
|
|
|
486
390
|
/**
|
|
@@ -514,8 +418,6 @@ export class CollectionBrowserDataSource
|
|
|
514
418
|
);
|
|
515
419
|
}
|
|
516
420
|
|
|
517
|
-
// DATA FETCHES
|
|
518
|
-
|
|
519
421
|
/**
|
|
520
422
|
* @inheritdoc
|
|
521
423
|
*/
|
|
@@ -538,6 +440,47 @@ export class CollectionBrowserDataSource
|
|
|
538
440
|
);
|
|
539
441
|
}
|
|
540
442
|
|
|
443
|
+
/**
|
|
444
|
+
* Sets the state for whether the initial set of search results for the
|
|
445
|
+
* current query is loading
|
|
446
|
+
*/
|
|
447
|
+
private setSearchResultsLoading(loading: boolean): void {
|
|
448
|
+
this.searchResultsLoading = loading;
|
|
449
|
+
if (this.activeOnHost) {
|
|
450
|
+
this.host.setSearchResultsLoading(loading);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Sets the state for whether the facets for a query is loading
|
|
456
|
+
*/
|
|
457
|
+
private setFacetsLoading(loading: boolean): void {
|
|
458
|
+
this.facetsLoading = loading;
|
|
459
|
+
if (this.activeOnHost) {
|
|
460
|
+
this.host.setFacetsLoading(loading);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Requests that the host perform an update, provided this data
|
|
466
|
+
* source is actively installed on it.
|
|
467
|
+
*/
|
|
468
|
+
private requestHostUpdate(): void {
|
|
469
|
+
if (this.activeOnHost) {
|
|
470
|
+
this.host.requestUpdate();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Requests that the host refresh its visible tiles, provided this
|
|
476
|
+
* data source is actively installed on it.
|
|
477
|
+
*/
|
|
478
|
+
private refreshVisibleResults(): void {
|
|
479
|
+
if (this.activeOnHost) {
|
|
480
|
+
this.host.refreshVisibleResults();
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
541
484
|
/**
|
|
542
485
|
* The query key is a string that uniquely identifies the current search.
|
|
543
486
|
* It consists of:
|
|
@@ -549,15 +492,15 @@ export class CollectionBrowserDataSource
|
|
|
549
492
|
* - Any currently-applied prefix filters
|
|
550
493
|
* - The current sort options
|
|
551
494
|
*
|
|
552
|
-
* This lets us keep track of queries so we don't persist data that's
|
|
553
|
-
* no longer relevant.
|
|
495
|
+
* This lets us internally keep track of queries so we don't persist data that's
|
|
496
|
+
* no longer relevant. Not meant to be human-readable.
|
|
554
497
|
*/
|
|
555
498
|
get pageFetchQueryKey(): string {
|
|
556
|
-
const profileKey =
|
|
499
|
+
const profileKey = `pf;${this.host.withinProfile}--pe;${this.host.profileElement}`;
|
|
557
500
|
const pageTarget = this.host.withinCollection ?? profileKey;
|
|
558
501
|
const sortField = this.host.sortParam?.field ?? 'none';
|
|
559
502
|
const sortDirection = this.host.sortParam?.direction ?? 'none';
|
|
560
|
-
return
|
|
503
|
+
return `fq:${this.fullQuery}-pt:${pageTarget}-st:${this.host.searchType}-sf:${sortField}-sd:${sortDirection}`;
|
|
561
504
|
}
|
|
562
505
|
|
|
563
506
|
/**
|
|
@@ -833,10 +776,14 @@ export class CollectionBrowserDataSource
|
|
|
833
776
|
* the current search state.
|
|
834
777
|
*/
|
|
835
778
|
private async fetchFacets(): Promise<void> {
|
|
779
|
+
console.log('fetchFacets', this.id, this.host.profileElement);
|
|
836
780
|
const trimmedQuery = this.host.baseQuery?.trim();
|
|
837
781
|
if (!this.canPerformSearch) return;
|
|
782
|
+
console.log('will actually fetch facets');
|
|
838
783
|
|
|
839
784
|
const { facetFetchQueryKey } = this;
|
|
785
|
+
if (this.fetchesInProgress.has(facetFetchQueryKey)) return;
|
|
786
|
+
this.fetchesInProgress.add(facetFetchQueryKey);
|
|
840
787
|
|
|
841
788
|
const sortParams = this.host.sortParam ? [this.host.sortParam] : [];
|
|
842
789
|
const params: SearchParams = {
|
|
@@ -854,7 +801,7 @@ export class CollectionBrowserDataSource
|
|
|
854
801
|
'aggregations'
|
|
855
802
|
);
|
|
856
803
|
|
|
857
|
-
this.
|
|
804
|
+
this.setFacetsLoading(true);
|
|
858
805
|
const searchResponse = await this.host.searchService?.search(
|
|
859
806
|
params,
|
|
860
807
|
this.host.searchType
|
|
@@ -865,8 +812,16 @@ export class CollectionBrowserDataSource
|
|
|
865
812
|
// If so, we just want to discard this set of aggregations because they are
|
|
866
813
|
// likely no longer valid for the newer query.
|
|
867
814
|
const queryChangedSinceFetch =
|
|
868
|
-
|
|
869
|
-
|
|
815
|
+
!this.fetchesInProgress.has(facetFetchQueryKey);
|
|
816
|
+
this.fetchesInProgress.delete(facetFetchQueryKey);
|
|
817
|
+
if (queryChangedSinceFetch) {
|
|
818
|
+
console.log(
|
|
819
|
+
'facet query has changed since fetch, returning. new/old:',
|
|
820
|
+
this.facetFetchQueryKey,
|
|
821
|
+
facetFetchQueryKey
|
|
822
|
+
);
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
870
825
|
|
|
871
826
|
if (!success) {
|
|
872
827
|
const errorMsg = searchResponse?.error?.message;
|
|
@@ -880,6 +835,7 @@ export class CollectionBrowserDataSource
|
|
|
880
835
|
);
|
|
881
836
|
}
|
|
882
837
|
|
|
838
|
+
this.setFacetsLoading(false);
|
|
883
839
|
return;
|
|
884
840
|
}
|
|
885
841
|
|
|
@@ -895,18 +851,17 @@ export class CollectionBrowserDataSource
|
|
|
895
851
|
this.yearHistogramAggregation =
|
|
896
852
|
success?.response?.aggregations?.year_histogram;
|
|
897
853
|
|
|
898
|
-
this.
|
|
899
|
-
this.
|
|
854
|
+
this.setFacetsLoading(false);
|
|
855
|
+
this.requestHostUpdate();
|
|
900
856
|
}
|
|
901
857
|
|
|
902
858
|
/**
|
|
903
859
|
* Performs the initial page fetch(es) for the current search state.
|
|
904
860
|
*/
|
|
905
861
|
private async doInitialPageFetch(): Promise<void> {
|
|
906
|
-
this.
|
|
862
|
+
this.setSearchResultsLoading(true);
|
|
907
863
|
// Try to batch 2 initial page requests when possible
|
|
908
864
|
await this.fetchPage(this.host.initialPageNumber, 2);
|
|
909
|
-
this.host.setSearchResultsLoading(false);
|
|
910
865
|
}
|
|
911
866
|
|
|
912
867
|
/**
|
|
@@ -918,14 +873,6 @@ export class CollectionBrowserDataSource
|
|
|
918
873
|
* if `pageNumber != 1`, defaulting to a single page.
|
|
919
874
|
*/
|
|
920
875
|
async fetchPage(pageNumber: number, numInitialPages = 1): Promise<void> {
|
|
921
|
-
console.log(
|
|
922
|
-
`fetchPage(${pageNumber})`,
|
|
923
|
-
this.canPerformSearch,
|
|
924
|
-
this.hasPage(pageNumber),
|
|
925
|
-
this.endOfDataReached,
|
|
926
|
-
this.host.baseQuery,
|
|
927
|
-
JSON.stringify(this.host.selectedFacets)
|
|
928
|
-
);
|
|
929
876
|
const trimmedQuery = this.host.baseQuery?.trim();
|
|
930
877
|
if (!this.canPerformSearch) return;
|
|
931
878
|
|
|
@@ -941,18 +888,31 @@ export class CollectionBrowserDataSource
|
|
|
941
888
|
|
|
942
889
|
// if a fetch is already in progress for this query and page, don't fetch again
|
|
943
890
|
const { pageFetchQueryKey } = this;
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
891
|
+
const currentPageKey = `${pageFetchQueryKey}-p:${pageNumber}`;
|
|
892
|
+
console.log(
|
|
893
|
+
'page fetch key',
|
|
894
|
+
currentPageKey,
|
|
895
|
+
this.fetchesInProgress.has(currentPageKey)
|
|
896
|
+
);
|
|
897
|
+
if (this.fetchesInProgress.has(currentPageKey)) return;
|
|
898
|
+
// const pageFetches =
|
|
899
|
+
// this.fetchesInProgress[pageFetchQueryKey] ?? new Set();
|
|
900
|
+
// if (pageFetches.has(pageNumber)) return;
|
|
901
|
+
|
|
952
902
|
for (let i = 0; i < numPages; i += 1) {
|
|
953
|
-
|
|
903
|
+
this.fetchesInProgress.add(`${pageFetchQueryKey}-p:${pageNumber + i}`);
|
|
954
904
|
}
|
|
955
|
-
|
|
905
|
+
console.log(
|
|
906
|
+
`fetchPage(${pageNumber})`,
|
|
907
|
+
this.id,
|
|
908
|
+
this.canPerformSearch,
|
|
909
|
+
this.hasPage(pageNumber),
|
|
910
|
+
this.endOfDataReached,
|
|
911
|
+
this.host.baseQuery,
|
|
912
|
+
JSON.stringify(this.host.selectedFacets),
|
|
913
|
+
this.pageFetchQueryKey
|
|
914
|
+
);
|
|
915
|
+
this.previousQueryKey = pageFetchQueryKey;
|
|
956
916
|
|
|
957
917
|
const sortParams = this.host.sortParam ? [this.host.sortParam] : [];
|
|
958
918
|
const params: SearchParams = {
|
|
@@ -974,42 +934,45 @@ export class CollectionBrowserDataSource
|
|
|
974
934
|
console.log('=== RECEIVED PAGE RESPONSE IN CB === ');
|
|
975
935
|
const success = searchResponse?.success;
|
|
976
936
|
|
|
977
|
-
// This is checking to see if the
|
|
978
|
-
// If so, we just want to discard the
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
937
|
+
// This is checking to see if the fetch has been invalidated since it was fired off.
|
|
938
|
+
// If so, we just want to discard the response since it is for an obsolete query state.
|
|
939
|
+
console.log(
|
|
940
|
+
'after page fetch key:',
|
|
941
|
+
currentPageKey,
|
|
942
|
+
this.fetchesInProgress.has(currentPageKey)
|
|
943
|
+
);
|
|
944
|
+
if (!this.fetchesInProgress.has(currentPageKey)) return;
|
|
945
|
+
for (let i = 0; i < numPages; i += 1) {
|
|
946
|
+
this.fetchesInProgress.delete(`${pageFetchQueryKey}-p:${pageNumber + i}`);
|
|
947
|
+
}
|
|
982
948
|
|
|
983
949
|
if (!success) {
|
|
984
950
|
const errorMsg = searchResponse?.error?.message;
|
|
985
951
|
const detailMsg = searchResponse?.error?.details?.message;
|
|
986
952
|
|
|
987
|
-
this.
|
|
953
|
+
this.queryErrorMessage = `${errorMsg ?? ''}${
|
|
988
954
|
detailMsg ? `; ${detailMsg}` : ''
|
|
989
955
|
}`;
|
|
990
956
|
|
|
991
|
-
if (!this.
|
|
992
|
-
this.
|
|
993
|
-
'Missing or malformed response from backend';
|
|
957
|
+
if (!this.queryErrorMessage) {
|
|
958
|
+
this.queryErrorMessage = 'Missing or malformed response from backend';
|
|
994
959
|
// @ts-ignore: Property 'Sentry' does not exist on type 'Window & typeof globalThis'
|
|
995
960
|
window?.Sentry?.captureMessage?.(this.queryErrorMessage, 'error');
|
|
996
961
|
}
|
|
997
962
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
this.host.setSearchResultsLoading(false);
|
|
1003
|
-
this.host.requestUpdate();
|
|
963
|
+
this.setSearchResultsLoading(false);
|
|
964
|
+
this.requestHostUpdate();
|
|
1004
965
|
return;
|
|
1005
966
|
}
|
|
1006
967
|
|
|
1007
968
|
this.totalResults = success.response.totalResults - this.offset;
|
|
1008
|
-
|
|
969
|
+
if (this.activeOnHost) {
|
|
970
|
+
this.host.setTotalResultCount(this.totalResults);
|
|
1009
971
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
972
|
+
// display event to offshoot when result count is zero.
|
|
973
|
+
if (this.totalResults === 0) {
|
|
974
|
+
this.host.emitEmptyResults();
|
|
975
|
+
}
|
|
1013
976
|
}
|
|
1014
977
|
|
|
1015
978
|
if (this.host.withinCollection) {
|
|
@@ -1071,14 +1034,11 @@ export class CollectionBrowserDataSource
|
|
|
1071
1034
|
if (resultCountDiscrepancy > 0) {
|
|
1072
1035
|
console.log('End of data reached');
|
|
1073
1036
|
this.endOfDataReached = true;
|
|
1074
|
-
this.host.setTileCount(this.totalResults);
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
for (let i = 0; i < numPages; i += 1) {
|
|
1078
|
-
this.pageFetchesInProgress[pageFetchQueryKey]?.delete(pageNumber + i);
|
|
1037
|
+
if (this.activeOnHost) this.host.setTileCount(this.totalResults);
|
|
1079
1038
|
}
|
|
1080
1039
|
|
|
1081
|
-
this.
|
|
1040
|
+
this.setSearchResultsLoading(false);
|
|
1041
|
+
this.requestHostUpdate();
|
|
1082
1042
|
}
|
|
1083
1043
|
|
|
1084
1044
|
/**
|
|
@@ -1091,10 +1051,6 @@ export class CollectionBrowserDataSource
|
|
|
1091
1051
|
pageNumber: number,
|
|
1092
1052
|
results: SearchResult[]
|
|
1093
1053
|
): void {
|
|
1094
|
-
// copy our existing datasource so when we set it below, it gets set
|
|
1095
|
-
// instead of modifying the existing dataSource since object changes
|
|
1096
|
-
// don't trigger a re-render
|
|
1097
|
-
// const datasource = { ...this.dataSource };
|
|
1098
1054
|
const tiles: TileModel[] = [];
|
|
1099
1055
|
results?.forEach(result => {
|
|
1100
1056
|
if (!result.identifier) return;
|
|
@@ -1104,7 +1060,7 @@ export class CollectionBrowserDataSource
|
|
|
1104
1060
|
const visiblePages = this.host.currentVisiblePageNumbers;
|
|
1105
1061
|
const needsReload = visiblePages.includes(pageNumber);
|
|
1106
1062
|
if (needsReload) {
|
|
1107
|
-
this.
|
|
1063
|
+
this.refreshVisibleResults();
|
|
1108
1064
|
}
|
|
1109
1065
|
}
|
|
1110
1066
|
|
|
@@ -1168,6 +1124,6 @@ export class CollectionBrowserDataSource
|
|
|
1168
1124
|
{}
|
|
1169
1125
|
);
|
|
1170
1126
|
|
|
1171
|
-
this.
|
|
1127
|
+
this.requestHostUpdate();
|
|
1172
1128
|
}
|
|
1173
1129
|
}
|