@internetarchive/collection-browser 2.10.1-alpha-webdev7479.10 → 2.12.0

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.
Files changed (44) hide show
  1. package/dist/src/assets/img/icons/close-circle-dark.d.ts +2 -0
  2. package/dist/src/assets/img/icons/close-circle-dark.js +5 -0
  3. package/dist/src/assets/img/icons/close-circle-dark.js.map +1 -0
  4. package/dist/src/collection-browser.d.ts +8 -0
  5. package/dist/src/collection-browser.js +33 -7
  6. package/dist/src/collection-browser.js.map +1 -1
  7. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.js +1 -1
  8. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.js.map +1 -1
  9. package/dist/src/collection-facets/smart-facets/smart-facet-bar.d.ts +3 -2
  10. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +36 -13
  11. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  12. package/dist/src/collection-facets/smart-facets/smart-facet-button.js +26 -10
  13. package/dist/src/collection-facets/smart-facets/smart-facet-button.js.map +1 -1
  14. package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js +19 -9
  15. package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js.map +1 -1
  16. package/dist/src/data-source/collection-browser-data-source.js +4 -5
  17. package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
  18. package/dist/src/tiles/grid/tile-stats.js +2 -2
  19. package/dist/src/tiles/grid/tile-stats.js.map +1 -1
  20. package/dist/test/collection-browser.test.js +55 -1
  21. package/dist/test/collection-browser.test.js.map +1 -1
  22. package/dist/test/mocks/mock-search-responses.d.ts +1 -0
  23. package/dist/test/mocks/mock-search-responses.js +46 -0
  24. package/dist/test/mocks/mock-search-responses.js.map +1 -1
  25. package/dist/test/mocks/mock-search-service.js +2 -1
  26. package/dist/test/mocks/mock-search-service.js.map +1 -1
  27. package/dist/test/restoration-state-handler.test.js +40 -0
  28. package/dist/test/restoration-state-handler.test.js.map +1 -1
  29. package/dist/test/tile-stats.test.js +39 -13
  30. package/dist/test/tile-stats.test.js.map +1 -1
  31. package/package.json +2 -2
  32. package/src/assets/img/icons/close-circle-dark.ts +5 -0
  33. package/src/collection-browser.ts +35 -7
  34. package/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.ts +4 -1
  35. package/src/collection-facets/smart-facets/smart-facet-bar.ts +38 -16
  36. package/src/collection-facets/smart-facets/smart-facet-button.ts +27 -10
  37. package/src/collection-facets/smart-facets/smart-facet-dropdown.ts +21 -10
  38. package/src/data-source/collection-browser-data-source.ts +8 -5
  39. package/src/tiles/grid/tile-stats.ts +2 -2
  40. package/test/collection-browser.test.ts +81 -1
  41. package/test/mocks/mock-search-responses.ts +50 -0
  42. package/test/mocks/mock-search-service.ts +2 -0
  43. package/test/restoration-state-handler.test.ts +59 -0
  44. package/test/tile-stats.test.ts +51 -13
@@ -369,6 +369,50 @@ describe('Collection Browser', () => {
369
369
  ).to.contains('Results');
370
370
  });
371
371
 
372
+ it('queries the search service with a radio search', async () => {
373
+ const searchService = new MockSearchService();
374
+
375
+ const el = await fixture<CollectionBrowser>(
376
+ html` <collection-browser .searchService=${searchService}>
377
+ </collection-browser>`,
378
+ );
379
+
380
+ el.searchType = SearchType.RADIO;
381
+ await el.updateComplete;
382
+
383
+ el.baseQuery = 'collection:foo';
384
+ await el.updateComplete;
385
+ await el.initialSearchComplete;
386
+
387
+ expect(searchService.searchParams?.query).to.equal('collection:foo');
388
+ expect(searchService.searchType).to.equal(SearchType.RADIO);
389
+ expect(
390
+ el.shadowRoot?.querySelector('#big-results-label')?.textContent,
391
+ ).to.contains('Results');
392
+ });
393
+
394
+ it('queries the search service with a TV search', async () => {
395
+ const searchService = new MockSearchService();
396
+
397
+ const el = await fixture<CollectionBrowser>(
398
+ html` <collection-browser .searchService=${searchService}>
399
+ </collection-browser>`,
400
+ );
401
+
402
+ el.searchType = SearchType.TV;
403
+ await el.updateComplete;
404
+
405
+ el.baseQuery = 'collection:foo';
406
+ await el.updateComplete;
407
+ await el.initialSearchComplete;
408
+
409
+ expect(searchService.searchParams?.query).to.equal('collection:foo');
410
+ expect(searchService.searchType).to.equal(SearchType.TV);
411
+ expect(
412
+ el.shadowRoot?.querySelector('#big-results-label')?.textContent,
413
+ ).to.contains('Results');
414
+ });
415
+
372
416
  it('queries the search service with facets selected/negated', async () => {
373
417
  const searchService = new MockSearchService();
374
418
  const selectedFacets: SelectedFacets = {
@@ -1306,6 +1350,23 @@ describe('Collection Browser', () => {
1306
1350
  expect(el.dataSource.parentCollections).to.deep.equal(['foo', 'bar']);
1307
1351
  });
1308
1352
 
1353
+ it('recognizes TV collections', async () => {
1354
+ const searchService = new MockSearchService();
1355
+ const el = await fixture<CollectionBrowser>(
1356
+ html`<collection-browser
1357
+ .searchService=${searchService}
1358
+ .withinCollection=${'TV-FOO'}
1359
+ ></collection-browser>`,
1360
+ );
1361
+
1362
+ el.baseQuery = 'tv-collection';
1363
+ await el.updateComplete;
1364
+ await el.initialSearchComplete;
1365
+ await aTimeout(0);
1366
+
1367
+ expect(el.isTVCollection).to.be.true;
1368
+ });
1369
+
1309
1370
  it('refreshes when certain properties change - with some analytics event sampling', async () => {
1310
1371
  const mockAnalyticsHandler = new MockAnalyticsHandler();
1311
1372
  const searchService = new MockSearchService();
@@ -1512,7 +1573,7 @@ describe('Collection Browser', () => {
1512
1573
  expect(el.withinProfile).to.equal('@foobar');
1513
1574
  expect(el.profileElement).to.equal('uploads');
1514
1575
  expect(el.baseQuery).to.equal('foo');
1515
- expect(el.searchType).to.equal(SearchType.METADATA);
1576
+ expect(el.searchType).to.equal(SearchType.DEFAULT);
1516
1577
  expect(el.selectedFacets?.mediatype?.data?.state).to.equal('hidden');
1517
1578
  expect(el.selectedFacets?.subject?.baz?.state).to.equal('selected');
1518
1579
  expect(el.selectedTitleFilter).to.equal('X');
@@ -2044,4 +2105,23 @@ describe('Collection Browser', () => {
2044
2105
  const initialResults = el.dataSource.getAllPages();
2045
2106
  expect(Object.keys(initialResults).length).to.deep.equal(numberOfPages);
2046
2107
  });
2108
+
2109
+ it('renders provided results header instead of default, when showing smart results', async () => {
2110
+ const searchService = new MockSearchService();
2111
+
2112
+ const el = await fixture<CollectionBrowser>(
2113
+ html`<collection-browser
2114
+ showSmartResults
2115
+ .searchService=${searchService}
2116
+ .resultsHeader=${'Foo Bar'}
2117
+ ></collection-browser>`,
2118
+ );
2119
+
2120
+ el.baseQuery = 'foo';
2121
+ await el.updateComplete;
2122
+ await nextTick();
2123
+
2124
+ const header = el.shadowRoot?.querySelector('.results-section-heading');
2125
+ expect(header?.textContent?.trim()).to.equal('Foo Bar');
2126
+ });
2047
2127
  });
@@ -98,12 +98,14 @@ export const getMockSuccessManyFields: () => Result<
98
98
  mediatype: 'texts',
99
99
  num_favorites: 12,
100
100
  num_reviews: 23,
101
+ num_clips: 34,
101
102
  source: 'foo bar',
102
103
  subject: ['baz', 'quux'],
103
104
  title: 'Foo Bar',
104
105
  volume: 2,
105
106
  week: 50,
106
107
  __href__: 'https://archive.org/details/foo',
108
+ __img__: '//services/img/foo',
107
109
  },
108
110
  }),
109
111
  ],
@@ -897,6 +899,54 @@ export const getMockSuccessWithParentCollections: () => Result<
897
899
  },
898
900
  });
899
901
 
902
+ export const getMockSuccessForTvCollection: () => Result<
903
+ SearchResponse,
904
+ SearchServiceError
905
+ > = () => ({
906
+ success: {
907
+ request: {
908
+ kind: 'hits',
909
+ clientParameters: {
910
+ user_query: 'tv-collection',
911
+ sort: [],
912
+ },
913
+ backendRequests: {
914
+ primary: {
915
+ kind: 'hits',
916
+ finalized_parameters: {
917
+ user_query: 'tv-collection',
918
+ sort: [],
919
+ },
920
+ },
921
+ },
922
+ },
923
+ rawResponse: {},
924
+ sessionContext: {},
925
+ response: {
926
+ totalResults: 1,
927
+ returnedCount: 1,
928
+ results: [
929
+ new ItemHit({
930
+ fields: {
931
+ identifier: 'foo',
932
+ title: 'Foo',
933
+ },
934
+ }),
935
+ ],
936
+ collectionExtraInfo: {
937
+ public_metadata: {
938
+ identifier: 'TV-FOO',
939
+ collection: ['tvarchive'],
940
+ },
941
+ },
942
+ },
943
+ responseHeader: {
944
+ succeeded: true,
945
+ query_time: 0,
946
+ },
947
+ },
948
+ });
949
+
900
950
  export const getMockSuccessWithWebArchiveHits: () => Result<
901
951
  SearchResponse,
902
952
  SearchServiceError
@@ -26,6 +26,7 @@ import {
26
26
  getMockSuccessWithConciseDefaultSort,
27
27
  getMockSuccessWithDefaultFavSort,
28
28
  getMockSuccessWithParentCollections,
29
+ getMockSuccessForTvCollection,
29
30
  getMockSuccessManyFields,
30
31
  getMockSuccessNoResults,
31
32
  getMockSuccessWithWebArchiveHits,
@@ -51,6 +52,7 @@ const responses: Record<
51
52
  'default-sort-concise': getMockSuccessWithConciseDefaultSort,
52
53
  'fav-sort': getMockSuccessWithDefaultFavSort,
53
54
  'parent-collections': getMockSuccessWithParentCollections,
55
+ 'tv-collection': getMockSuccessForTvCollection,
54
56
  'web-archive': getMockSuccessWithWebArchiveHits,
55
57
  'more-facets': getMockSuccessWithManyAggregations,
56
58
  'many-fields': getMockSuccessManyFields,
@@ -48,6 +48,39 @@ describe('Restoration state handler', () => {
48
48
  expect(restorationState.searchType).to.equal(SearchType.FULLTEXT);
49
49
  });
50
50
 
51
+ it('should restore radio search type from URL', async () => {
52
+ const handler = new RestorationStateHandler({ context: 'search' });
53
+
54
+ const url = new URL(window.location.href);
55
+ url.search = '?sin=RADIO';
56
+ window.history.replaceState({ path: url.href }, '', url.href);
57
+
58
+ const restorationState = handler.getRestorationState();
59
+ expect(restorationState.searchType).to.equal(SearchType.RADIO);
60
+ });
61
+
62
+ it('should restore TV search type from URL', async () => {
63
+ const handler = new RestorationStateHandler({ context: 'search' });
64
+
65
+ const url = new URL(window.location.href);
66
+ url.search = '?sin=TV';
67
+ window.history.replaceState({ path: url.href }, '', url.href);
68
+
69
+ const restorationState = handler.getRestorationState();
70
+ expect(restorationState.searchType).to.equal(SearchType.TV);
71
+ });
72
+
73
+ it('should restore metadata search type from URL', async () => {
74
+ const handler = new RestorationStateHandler({ context: 'search' });
75
+
76
+ const url = new URL(window.location.href);
77
+ url.search = '?sin=MD';
78
+ window.history.replaceState({ path: url.href }, '', url.href);
79
+
80
+ const restorationState = handler.getRestorationState();
81
+ expect(restorationState.searchType).to.equal(SearchType.METADATA);
82
+ });
83
+
51
84
  it('should restore page number from URL', async () => {
52
85
  const handler = new RestorationStateHandler({ context: 'search' });
53
86
 
@@ -364,6 +397,32 @@ describe('Restoration state handler', () => {
364
397
  expect(window.location.search).to.equal('');
365
398
  });
366
399
 
400
+ it('should persist metadata search type only when option is true', async () => {
401
+ const url = new URL(window.location.href);
402
+ url.search = '?sin=';
403
+ window.history.replaceState({ path: url.href }, '', url.href);
404
+
405
+ const handler = new RestorationStateHandler({ context: 'search' });
406
+
407
+ handler.persistState(
408
+ {
409
+ selectedFacets: getDefaultSelectedFacets(),
410
+ searchType: SearchType.METADATA,
411
+ },
412
+ { persistMetadataSearchType: false },
413
+ );
414
+ expect(window.location.search).to.equal('');
415
+
416
+ handler.persistState(
417
+ {
418
+ selectedFacets: getDefaultSelectedFacets(),
419
+ searchType: SearchType.METADATA,
420
+ },
421
+ { persistMetadataSearchType: true },
422
+ );
423
+ expect(window.location.search).to.equal('?sin=MD');
424
+ });
425
+
367
426
  it('round trip load/persist should erase numbers in square brackets', async () => {
368
427
  const handler = new RestorationStateHandler({ context: 'search' });
369
428
 
@@ -17,7 +17,7 @@ describe('Tile Stats', () => {
17
17
  expect(statsRowCount).to.equal(4);
18
18
  });
19
19
 
20
- it('should render component with value', async () => {
20
+ it('should render component with values', async () => {
21
21
  const el = await fixture<TileStats>(html`
22
22
  <tile-stats
23
23
  .mediatype=${'account'}
@@ -48,9 +48,47 @@ describe('Tile Stats', () => {
48
48
  ?.textContent?.trim();
49
49
 
50
50
  expect(mediatypeStat).to.exist;
51
- expect(itemStatCount).to.match(/Uploads:\s+1/);
52
- expect(favoritesStatCount).to.match(/Favorites:\s+2/);
53
- expect(reviewsStatCount).to.match(/Reviews:\s+3/);
51
+ expect(itemStatCount).to.match(/uploads:\s+1/);
52
+ expect(favoritesStatCount).to.match(/favorites:\s+2/);
53
+ expect(reviewsStatCount).to.match(/reviews:\s+3/);
54
+ });
55
+
56
+ it('should render component with tv clips', async () => {
57
+ const el = await fixture<TileStats>(html`
58
+ <tile-stats
59
+ showTvClips
60
+ .mediatype=${'texts'}
61
+ .viewCount=${1}
62
+ .favCount=${2}
63
+ .commentCount=${3}
64
+ .tvClipCount=${4}
65
+ >
66
+ </tile-stats>
67
+ `);
68
+
69
+ const statsRow = el.shadowRoot?.querySelector('#stats-row');
70
+
71
+ const mediatypeStat = statsRow?.children.item(0);
72
+ // get second column item in stats row
73
+ const itemStatCount = statsRow?.children
74
+ .item(1)
75
+ ?.querySelector('.status-text')
76
+ ?.textContent?.trim();
77
+ // get third column item in stats row
78
+ const favoritesStatCount = statsRow?.children
79
+ .item(2)
80
+ ?.querySelector('.status-text')
81
+ ?.textContent?.trim();
82
+ // get fourth column item in stats row
83
+ const clipsStatCount = statsRow?.children
84
+ .item(3)
85
+ ?.querySelector('.status-text')
86
+ ?.textContent?.trim();
87
+
88
+ expect(mediatypeStat).to.exist;
89
+ expect(itemStatCount).to.match(/views:\s+1/);
90
+ expect(favoritesStatCount).to.match(/favorites:\s+2/);
91
+ expect(clipsStatCount).to.match(/clips:\s+4/);
54
92
  });
55
93
 
56
94
  it('should render view count for non-account items', async () => {
@@ -84,9 +122,9 @@ describe('Tile Stats', () => {
84
122
  ?.textContent?.trim();
85
123
 
86
124
  expect(mediatypeStat).to.exist;
87
- expect(viewStatCount).to.match(/Views:\s+4/);
88
- expect(favoritesStatCount).to.match(/Favorites:\s+5/);
89
- expect(reviewsStatCount).to.match(/Reviews:\s+6/);
125
+ expect(viewStatCount).to.match(/views:\s+4/);
126
+ expect(favoritesStatCount).to.match(/favorites:\s+5/);
127
+ expect(reviewsStatCount).to.match(/reviews:\s+6/);
90
128
  });
91
129
 
92
130
  it('handles missing counts gracefully', async () => {
@@ -115,9 +153,9 @@ describe('Tile Stats', () => {
115
153
  ?.textContent?.trim();
116
154
 
117
155
  expect(mediatypeStat).to.exist;
118
- expect(viewStatCount).to.match(/Views:\s+0/);
119
- expect(favoritesStatCount).to.match(/Favorites:\s+5/);
120
- expect(reviewsStatCount).to.match(/Reviews:\s+6/);
156
+ expect(viewStatCount).to.match(/views:\s+0/);
157
+ expect(favoritesStatCount).to.match(/favorites:\s+5/);
158
+ expect(reviewsStatCount).to.match(/reviews:\s+6/);
121
159
  });
122
160
 
123
161
  it('handles missing counts gracefully for accounts', async () => {
@@ -146,8 +184,8 @@ describe('Tile Stats', () => {
146
184
  ?.textContent?.trim();
147
185
 
148
186
  expect(mediatypeStat).to.exist;
149
- expect(itemStatCount).to.match(/Uploads:\s+0/);
150
- expect(favoritesStatCount).to.match(/Favorites:\s+5/);
151
- expect(reviewsStatCount).to.match(/Reviews:\s+6/);
187
+ expect(itemStatCount).to.match(/uploads:\s+0/);
188
+ expect(favoritesStatCount).to.match(/favorites:\s+5/);
189
+ expect(reviewsStatCount).to.match(/reviews:\s+6/);
152
190
  });
153
191
  });