@internetarchive/collection-browser 1.2.0 → 1.2.1-alpha.2
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/src/collection-browser.d.ts +34 -0
- package/dist/src/collection-browser.js +82 -2
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/sort-filter-bar/sort-filter-bar.js +15 -0
- package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
- package/dist/src/tiles/list/tile-list.js +1 -1
- package/dist/src/tiles/list/tile-list.js.map +1 -1
- package/dist/src/utils/sha1.d.ts +2 -0
- package/dist/src/utils/sha1.js +9 -0
- package/dist/src/utils/sha1.js.map +1 -0
- package/dist/test/collection-browser.test.js +25 -10
- package/dist/test/collection-browser.test.js.map +1 -1
- package/package.json +3 -3
- package/src/collection-browser.ts +111 -2
- package/src/sort-filter-bar/sort-filter-bar.ts +15 -0
- package/src/tiles/list/tile-list.ts +1 -1
- package/src/utils/sha1.ts +9 -0
- package/test/collection-browser.test.ts +25 -10
|
@@ -107,6 +107,13 @@ export declare class CollectionBrowser extends LitElement implements InfiniteScr
|
|
|
107
107
|
*/
|
|
108
108
|
private dataSource;
|
|
109
109
|
private infiniteScroller;
|
|
110
|
+
private sessionIdGenPromise?;
|
|
111
|
+
/**
|
|
112
|
+
* Returns a promise resolving to a unique string that persists for the current browser session.
|
|
113
|
+
* Used in generating unique IDs for search requests, so that multiple requests coming from the
|
|
114
|
+
* same browser session can be identified.
|
|
115
|
+
*/
|
|
116
|
+
private getSessionId;
|
|
110
117
|
/**
|
|
111
118
|
* Go to the given page of results
|
|
112
119
|
*
|
|
@@ -268,6 +275,23 @@ export declare class CollectionBrowser extends LitElement implements InfiniteScr
|
|
|
268
275
|
private initialQueryChangeHappened;
|
|
269
276
|
private historyPopOccurred;
|
|
270
277
|
private previousQueryKey?;
|
|
278
|
+
/**
|
|
279
|
+
* Internal property to store the `resolve` function for the most recent
|
|
280
|
+
* `initialSearchComplete` promise, allowing us to resolve it at the appropriate time.
|
|
281
|
+
*/
|
|
282
|
+
private _initialSearchCompleteResolver;
|
|
283
|
+
/**
|
|
284
|
+
* Internal property to store the private value backing the `initialSearchComplete` getter.
|
|
285
|
+
*/
|
|
286
|
+
private _initialSearchCompletePromise;
|
|
287
|
+
/**
|
|
288
|
+
* A Promise which, after each query change, resolves once the fetches for the initial
|
|
289
|
+
* search have completed. Waits for *both* the hits and aggregations fetches to finish.
|
|
290
|
+
*
|
|
291
|
+
* Ensure you await this component's `updateComplete` promise before awaiting this
|
|
292
|
+
* one, to ensure you do not await an obsolete promise from the previous update.
|
|
293
|
+
*/
|
|
294
|
+
get initialSearchComplete(): Promise<boolean>;
|
|
271
295
|
private handleQueryChange;
|
|
272
296
|
private setupStateRestorationObserver;
|
|
273
297
|
private boundNavigationHandler?;
|
|
@@ -276,6 +300,16 @@ export declare class CollectionBrowser extends LitElement implements InfiniteScr
|
|
|
276
300
|
private persistState;
|
|
277
301
|
private doInitialPageFetch;
|
|
278
302
|
private emitSearchResultsLoadingChanged;
|
|
303
|
+
/**
|
|
304
|
+
* Produces a compact unique ID for a search request that can help with debugging
|
|
305
|
+
* on the backend by making related requests easier to trace through different services.
|
|
306
|
+
* (e.g., tying the hits/aggregations requests for the same page back to a single hash).
|
|
307
|
+
*
|
|
308
|
+
* @param params The search service parameters for the request
|
|
309
|
+
* @param kind The kind of request (hits-only, aggregations-only, or both)
|
|
310
|
+
* @returns A Promise resolving to the uid to apply to the request
|
|
311
|
+
*/
|
|
312
|
+
private requestUID;
|
|
279
313
|
/**
|
|
280
314
|
* Constructs a search service FilterMap object from the combination of
|
|
281
315
|
* all the currently-applied filters. This includes any facets, letter
|
|
@@ -17,6 +17,7 @@ import chevronIcon from './assets/img/icons/chevron';
|
|
|
17
17
|
import './empty-placeholder';
|
|
18
18
|
import { analyticsActions, analyticsCategories, } from './utils/analytics-events';
|
|
19
19
|
import { srOnlyStyle } from './styles/sr-only';
|
|
20
|
+
import { sha1 } from './utils/sha1';
|
|
20
21
|
let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
21
22
|
constructor() {
|
|
22
23
|
super(...arguments);
|
|
@@ -114,6 +115,12 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
114
115
|
// so this keeps track of whether we've already set the initial query
|
|
115
116
|
this.initialQueryChangeHappened = false;
|
|
116
117
|
this.historyPopOccurred = false;
|
|
118
|
+
/**
|
|
119
|
+
* Internal property to store the private value backing the `initialSearchComplete` getter.
|
|
120
|
+
*/
|
|
121
|
+
this._initialSearchCompletePromise = new Promise(res => {
|
|
122
|
+
this._initialSearchCompleteResolver = res;
|
|
123
|
+
});
|
|
117
124
|
// this maps the query to the pages being fetched for that query
|
|
118
125
|
this.pageFetchesInProgress = {};
|
|
119
126
|
}
|
|
@@ -145,6 +152,32 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
145
152
|
get estimatedTileCount() {
|
|
146
153
|
return this.pagesToRender * this.pageSize;
|
|
147
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Returns a promise resolving to a unique string that persists for the current browser session.
|
|
157
|
+
* Used in generating unique IDs for search requests, so that multiple requests coming from the
|
|
158
|
+
* same browser session can be identified.
|
|
159
|
+
*/
|
|
160
|
+
async getSessionId() {
|
|
161
|
+
try {
|
|
162
|
+
const storedSessionId = sessionStorage === null || sessionStorage === void 0 ? void 0 : sessionStorage.getItem('cb-session');
|
|
163
|
+
if (storedSessionId) {
|
|
164
|
+
return storedSessionId;
|
|
165
|
+
}
|
|
166
|
+
// If we enter this method a second time while a first session ID is already being generated,
|
|
167
|
+
// ensure we produce the same ID from both calls instead of generating another one.
|
|
168
|
+
if (this.sessionIdGenPromise) {
|
|
169
|
+
return this.sessionIdGenPromise;
|
|
170
|
+
}
|
|
171
|
+
this.sessionIdGenPromise = sha1(Math.random().toString());
|
|
172
|
+
const newSessionId = await this.sessionIdGenPromise;
|
|
173
|
+
sessionStorage === null || sessionStorage === void 0 ? void 0 : sessionStorage.setItem('cb-session', newSessionId);
|
|
174
|
+
return newSessionId;
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
// Either we can't generate the hash or we're restricted from accessing sessionStorage
|
|
178
|
+
return '';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
148
181
|
/**
|
|
149
182
|
* Go to the given page of results
|
|
150
183
|
*
|
|
@@ -807,6 +840,16 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
807
840
|
});
|
|
808
841
|
this.dispatchEvent(event);
|
|
809
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* A Promise which, after each query change, resolves once the fetches for the initial
|
|
845
|
+
* search have completed. Waits for *both* the hits and aggregations fetches to finish.
|
|
846
|
+
*
|
|
847
|
+
* Ensure you await this component's `updateComplete` promise before awaiting this
|
|
848
|
+
* one, to ensure you do not await an obsolete promise from the previous update.
|
|
849
|
+
*/
|
|
850
|
+
get initialSearchComplete() {
|
|
851
|
+
return this._initialSearchCompletePromise;
|
|
852
|
+
}
|
|
810
853
|
async handleQueryChange() {
|
|
811
854
|
// only reset if the query has actually changed
|
|
812
855
|
if (!this.searchService || this.pageFetchQueryKey === this.previousQueryKey)
|
|
@@ -839,7 +882,14 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
839
882
|
this.persistState();
|
|
840
883
|
}
|
|
841
884
|
this.historyPopOccurred = false;
|
|
885
|
+
// Reset the `initialSearchComplete` promise with a new value for the imminent search
|
|
886
|
+
this._initialSearchCompletePromise = new Promise(res => {
|
|
887
|
+
this._initialSearchCompleteResolver = res;
|
|
888
|
+
});
|
|
889
|
+
// Fire the initial page and facets requests
|
|
842
890
|
await Promise.all([this.doInitialPageFetch(), this.fetchFacets()]);
|
|
891
|
+
// Resolve the `initialSearchComplete` promise for this search
|
|
892
|
+
this._initialSearchCompleteResolver(true);
|
|
843
893
|
}
|
|
844
894
|
setupStateRestorationObserver() {
|
|
845
895
|
if (this.boundNavigationHandler)
|
|
@@ -904,6 +954,33 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
904
954
|
},
|
|
905
955
|
}));
|
|
906
956
|
}
|
|
957
|
+
/**
|
|
958
|
+
* Produces a compact unique ID for a search request that can help with debugging
|
|
959
|
+
* on the backend by making related requests easier to trace through different services.
|
|
960
|
+
* (e.g., tying the hits/aggregations requests for the same page back to a single hash).
|
|
961
|
+
*
|
|
962
|
+
* @param params The search service parameters for the request
|
|
963
|
+
* @param kind The kind of request (hits-only, aggregations-only, or both)
|
|
964
|
+
* @returns A Promise resolving to the uid to apply to the request
|
|
965
|
+
*/
|
|
966
|
+
async requestUID(params, kind) {
|
|
967
|
+
var _a;
|
|
968
|
+
const paramsToHash = JSON.stringify({
|
|
969
|
+
pageType: params.pageType,
|
|
970
|
+
pageTarget: params.pageTarget,
|
|
971
|
+
query: params.query,
|
|
972
|
+
fields: params.fields,
|
|
973
|
+
filters: params.filters,
|
|
974
|
+
sort: params.sort,
|
|
975
|
+
searchType: this.searchType,
|
|
976
|
+
});
|
|
977
|
+
const fullQueryHash = (await sha1(paramsToHash)).slice(0, 20); // First 80 bits of SHA-1 are plenty for this
|
|
978
|
+
const sessionId = (await this.getSessionId()).slice(0, 20); // Likewise
|
|
979
|
+
const page = (_a = params.page) !== null && _a !== void 0 ? _a : 0;
|
|
980
|
+
const kindPrefix = kind.charAt(0); // f = full, h = hits, a = aggregations
|
|
981
|
+
const currentTime = Date.now();
|
|
982
|
+
return `R:${fullQueryHash}-S:${sessionId}-P:${page}-K:${kindPrefix}-T:${currentTime}`;
|
|
983
|
+
}
|
|
907
984
|
/**
|
|
908
985
|
* Constructs a search service FilterMap object from the combination of
|
|
909
986
|
* all the currently-applied filters. This includes any facets, letter
|
|
@@ -1063,6 +1140,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
1063
1140
|
if (!this.searchService)
|
|
1064
1141
|
return;
|
|
1065
1142
|
const { facetFetchQueryKey } = this;
|
|
1143
|
+
const sortParams = this.sortParam ? [this.sortParam] : [];
|
|
1066
1144
|
const params = {
|
|
1067
1145
|
query: trimmedQuery,
|
|
1068
1146
|
rows: 0,
|
|
@@ -1071,8 +1149,8 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
1071
1149
|
aggregationsSize: 10,
|
|
1072
1150
|
// Note: we don't need an aggregations param to fetch the default aggregations from the PPS.
|
|
1073
1151
|
// The default aggregations for the search_results page type should be what we need here.
|
|
1074
|
-
uid: this.facetFetchQueryKey,
|
|
1075
1152
|
};
|
|
1153
|
+
params.uid = await this.requestUID({ ...params, sort: sortParams }, 'aggregations');
|
|
1076
1154
|
this.facetsLoading = true;
|
|
1077
1155
|
const searchResponse = await this.searchService.search(params, this.searchType);
|
|
1078
1156
|
const success = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success;
|
|
@@ -1192,8 +1270,8 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
1192
1270
|
sort: sortParams,
|
|
1193
1271
|
filters: this.filterMap,
|
|
1194
1272
|
aggregations: { omit: true },
|
|
1195
|
-
uid: this.pageFetchQueryKey,
|
|
1196
1273
|
};
|
|
1274
|
+
params.uid = await this.requestUID(params, 'hits');
|
|
1197
1275
|
const searchResponse = await this.searchService.search(params, this.searchType);
|
|
1198
1276
|
const success = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success;
|
|
1199
1277
|
// This is checking to see if the query has changed since the data was fetched.
|
|
@@ -1351,6 +1429,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
1351
1429
|
if (!trimmedQuery)
|
|
1352
1430
|
return [];
|
|
1353
1431
|
const filterAggregationKey = prefixFilterAggregationKeys[filterType];
|
|
1432
|
+
const sortParams = this.sortParam ? [this.sortParam] : [];
|
|
1354
1433
|
const params = {
|
|
1355
1434
|
query: trimmedQuery,
|
|
1356
1435
|
rows: 0,
|
|
@@ -1360,6 +1439,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
1360
1439
|
// Fetch all 26 letter buckets
|
|
1361
1440
|
aggregationsSize: 26,
|
|
1362
1441
|
};
|
|
1442
|
+
params.uid = await this.requestUID({ ...params, sort: sortParams }, 'aggregations');
|
|
1363
1443
|
const searchResponse = await ((_b = this.searchService) === null || _b === void 0 ? void 0 : _b.search(params, this.searchType));
|
|
1364
1444
|
return ((_g = (_f = (_e = (_d = (_c = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.aggregations) === null || _e === void 0 ? void 0 : _e[filterAggregationKey]) === null || _f === void 0 ? void 0 : _f.buckets) !== null && _g !== void 0 ? _g : []);
|
|
1365
1445
|
}
|