@internetarchive/collection-browser 2.7.6-alpha2 → 2.7.6-alpha3

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/src/app-root.ts CHANGED
@@ -485,20 +485,13 @@ export class AppRoot extends LitElement {
485
485
  .modalManager=${this.modalManager}
486
486
  .analyticsHandler=${this.analyticsHandler}
487
487
  .pageContext=${'search'}
488
- .activeTabId=${'uploads'}
488
+ .activeTabId=${''}
489
489
  @visiblePageChanged=${this.visiblePageChanged}
490
490
  @baseQueryChanged=${this.baseQueryChanged}
491
491
  @searchTypeChanged=${this.searchTypeChanged}
492
492
  @manageModeChanged=${this.manageModeChanged}
493
- @itemRemovalRequested=${(e: CustomEvent) => {
494
- setTimeout(() => {
495
- console.log('itemRemovalRequested: ', e.detail.items);
496
- this.collectionBrowser.isItemDeleted = false;
497
- this.collectionBrowser.isManageView = false;
498
- }, 1200);
499
- }}
500
- @itemManagerRequested=${(e: CustomEvent) =>
501
- console.log('itemManagerRequested: ', e.detail.items)}
493
+ @itemRemovalRequested=${this.handleItemRemovalRequest}
494
+ @itemManagerRequested=${this.handleItemManagerRequest}
502
495
  >
503
496
  ${this.toggleSlots
504
497
  ? html`<div slot="sortbar-left-slot">Sort Slot</div>`
@@ -713,6 +706,35 @@ export class AppRoot extends LitElement {
713
706
  if (manageCheckbox) manageCheckbox.checked = e.detail;
714
707
  }
715
708
 
709
+ /**
710
+ * Handler for item removal
711
+ */
712
+ private handleItemRemovalRequest(e: CustomEvent) {
713
+ setTimeout(() => {
714
+ console.log('itemRemovalRequested: ', e.detail.items);
715
+
716
+ // execute item-removal-service, and response is successfully deleted
717
+ const status = false;
718
+
719
+ if (status) {
720
+ // looking for success?
721
+ this.collectionBrowser.isManageView = false;
722
+ this.modalManager?.closeModal();
723
+ this.modalManager?.classList.remove('remove-items');
724
+ } else {
725
+ // looking for failure?
726
+ this.collectionBrowser.hasItemsDeleted = false;
727
+ }
728
+ }, 2000); // let's wait to see processing modal
729
+ }
730
+
731
+ /**
732
+ * Handler when item manage requested
733
+ */
734
+ private handleItemManagerRequest(e: CustomEvent) {
735
+ console.log('itemManagerRequested: ', e.detail.items);
736
+ }
737
+
716
738
  /**
717
739
  * Handler for when the dev panel's "Enable manage mode" checkbox is changed.
718
740
  */
@@ -721,7 +743,7 @@ export class AppRoot extends LitElement {
721
743
  this.collectionBrowser.isManageView = target.checked;
722
744
  this.collectionBrowser.manageViewLabel =
723
745
  'Select items to remove (customizable texts)';
724
- this.collectionBrowser.isItemDeleted = true;
746
+ this.collectionBrowser.hasItemsDeleted = true;
725
747
  }
726
748
 
727
749
  /**
@@ -44,6 +44,7 @@ import {
44
44
  SORT_OPTIONS,
45
45
  defaultProfileElementSorts,
46
46
  FacetLoadStrategy,
47
+ ManageableItem,
47
48
  } from './models';
48
49
  import {
49
50
  RestorationStateHandlerInterface,
@@ -244,9 +245,9 @@ export class CollectionBrowser
244
245
  /**
245
246
  * If item management UI active
246
247
  */
247
- @property({ type: Boolean }) isManageView = true;
248
+ @property({ type: Boolean }) isManageView = false;
248
249
 
249
- @property({ type: Boolean }) isItemDeleted = true;
250
+ @property({ type: Boolean }) hasItemsDeleted = true;
250
251
 
251
252
  @property({ type: String }) manageViewLabel = 'Select items to remove';
252
253
 
@@ -782,10 +783,10 @@ export class CollectionBrowser
782
783
  .label=${this.manageViewLabel}
783
784
  .modalManager=${this.modalManager}
784
785
  .selectedItems=${this.dataSource.checkedTileModels}
786
+ .hasItemsDeleted=${this.hasItemsDeleted}
785
787
  showSelectAll
786
788
  showUnselectAll
787
- ?isItemDeleted=${this.isItemDeleted}
788
- ?showManageButton=${this.pageContext === 'search'}
789
+ ?showItemManageButton=${this.pageContext === 'search'}
789
790
  ?removeAllowed=${this.dataSource.checkedTileModels.length !== 0}
790
791
  @removeItems=${this.handleRemoveItems}
791
792
  @manageItems=${this.handleManageItems}
@@ -804,14 +805,16 @@ export class CollectionBrowser
804
805
  * Emits an `itemRemovalRequested` event with all checked tile models.
805
806
  */
806
807
  private handleRemoveItems(): void {
808
+ this.hasItemsDeleted = true;
809
+
807
810
  this.dispatchEvent(
808
- new CustomEvent<{ items: String }>('itemRemovalRequested', {
811
+ new CustomEvent<{ items: ManageableItem[] }>('itemRemovalRequested', {
809
812
  detail: {
810
813
  items: this.dataSource.checkedTileModels.map(model => {
811
814
  const cloned = model.clone();
812
815
  cloned.dateStr = formatDate(model.datePublished, 'long');
813
- return cloned.identifier;
814
- }).join(','),
816
+ return cloned as ManageableItem;
817
+ }),
815
818
  },
816
819
  })
817
820
  );
@@ -822,12 +825,11 @@ export class CollectionBrowser
822
825
  */
823
826
  private handleManageItems(): void {
824
827
  this.dispatchEvent(
825
- new CustomEvent<{ items: String }>('itemManagerRequested', {
828
+ new CustomEvent<{ items: ManageableItem[] }>('itemManagerRequested', {
826
829
  detail: {
827
- items: this.dataSource.checkedTileModels
828
- .map(item => item.identifier)
829
- .filter(Boolean)
830
- .join(','),
830
+ items: this.dataSource.checkedTileModels.map(
831
+ model => model as ManageableItem
832
+ ),
831
833
  },
832
834
  })
833
835
  );
@@ -13,15 +13,10 @@ import {
13
13
  ModalConfig,
14
14
  type ModalManagerInterface,
15
15
  } from '@internetarchive/modal-manager';
16
+ import type { ManageableItem } from '../models';
16
17
  import iaButtonStyle from '../styles/ia-button';
17
18
  import './remove-items-modal-content';
18
19
 
19
- export interface ManageableItem {
20
- identifier: string;
21
- title?: string;
22
- dateStr?: string;
23
- }
24
-
25
20
  @customElement('manage-bar')
26
21
  export class ManageBar extends LitElement {
27
22
  /**
@@ -55,14 +50,14 @@ export class ManageBar extends LitElement {
55
50
  @property({ type: Boolean }) showUnselectAll = false;
56
51
 
57
52
  /**
58
- * Item removal failure message, if any
53
+ * Whether item has deleted or not (default true)
59
54
  */
60
- @property({ type: Boolean }) isItemDeleted = true;
55
+ @property({ type: Boolean }) hasItemsDeleted = true;
61
56
 
62
57
  /**
63
58
  * Whether to show "Item Manager the items" button (default false)
64
59
  */
65
- @property({ type: Boolean }) showManageButton = false;
60
+ @property({ type: Boolean }) showItemManageButton = false;
66
61
 
67
62
  /**
68
63
  * Whether to active delete button for selectable items
@@ -70,14 +65,8 @@ export class ManageBar extends LitElement {
70
65
  @property({ type: Boolean }) removeAllowed = false;
71
66
 
72
67
  updated(changed: PropertyValues): void {
73
- if (changed.has('isItemDeleted')) {
74
- console.log(this.isItemDeleted)
75
- if (this.isItemDeleted === false) {
76
- this.showRemoveItemsErrorModal();
77
- } else {
78
- this.modalManager?.closeModal();
79
- this.modalManager?.classList.remove('remove-items');
80
- }
68
+ if (changed.has('hasItemsDeleted') && !this.hasItemsDeleted) {
69
+ this.showRemoveItemsErrorModal();
81
70
  }
82
71
  }
83
72
 
@@ -97,7 +86,7 @@ export class ManageBar extends LitElement {
97
86
  ${msg('Remove selected items')}
98
87
  </button>
99
88
  ${when(
100
- this.showManageButton,
89
+ this.showItemManageButton,
101
90
  () => html` <button
102
91
  class="ia-button warning"
103
92
  ?disabled=${!this.removeAllowed}
@@ -135,10 +124,6 @@ export class ManageBar extends LitElement {
135
124
  this.dispatchEvent(new CustomEvent('cancel'));
136
125
  }
137
126
 
138
- /**
139
- * Shows a modal dialog confirming the list of items to be removed
140
- * @param items Which items to list in the modal
141
- */
142
127
  private removeItemsClicked(): void {
143
128
  this.showRemoveItemsProcessingModal();
144
129
  this.dispatchEvent(new CustomEvent('removeItems'));
@@ -232,7 +217,7 @@ export class ManageBar extends LitElement {
232
217
  closeOnBackdropClick: true,
233
218
  title: html`${msg('Error: unable to remove items')}`,
234
219
  message: html`${msg(
235
- 'An error occurred while removing items. Please try again in a few minutes.',
220
+ 'An error occurred while removing items. Please try again in a few minutes.'
236
221
  )}`,
237
222
  });
238
223
 
@@ -2,12 +2,7 @@ import { LitElement, html, css, nothing, TemplateResult, CSSResult } from 'lit';
2
2
  import { customElement, property } from 'lit/decorators.js';
3
3
  import { msg } from '@lit/localize';
4
4
  import { map } from 'lit/directives/map.js';
5
-
6
- export interface ManageableItem {
7
- identifier: string;
8
- title?: string;
9
- date?: string;
10
- }
5
+ import type { ManageableItem } from '../models';
11
6
 
12
7
  @customElement('remove-items-modal-content')
13
8
  export class RemoveItemsModalContent extends LitElement {
package/src/models.ts CHANGED
@@ -675,3 +675,13 @@ export const suppressedCollections: Record<string, boolean> = {
675
675
  americana: true,
676
676
  toronto: true,
677
677
  };
678
+
679
+ /**
680
+ * A record of manageable item
681
+ */
682
+ export interface ManageableItem {
683
+ identifier: string;
684
+ title?: string;
685
+ dateStr?: string;
686
+ date?: string;
687
+ }
@@ -2,9 +2,14 @@
2
2
  import { expect, fixture } from '@open-wc/testing';
3
3
  import { html } from 'lit';
4
4
  import Sinon from 'sinon';
5
- import type { ManageBar } from '../../src/manage/manage-bar';
6
-
7
5
  import '../../src/manage/manage-bar';
6
+ import {
7
+ ModalManager,
8
+ ModalManagerInterface,
9
+ } from '@internetarchive/modal-manager';
10
+ import '@internetarchive/modal-manager';
11
+ import { msg } from '@lit/localize';
12
+ import type { ManageBar } from '../../src/manage/manage-bar';
8
13
 
9
14
  describe('Manage bar', () => {
10
15
  it('renders basic component', async () => {
@@ -38,7 +43,7 @@ describe('Manage bar', () => {
38
43
 
39
44
  it('render item manager button for /search/ page', async () => {
40
45
  const el = await fixture<ManageBar>(
41
- html`<manage-bar .pageContext=${'search'}></manage-bar>`
46
+ html`<manage-bar showItemManageButton></manage-bar>`
42
47
  );
43
48
  expect(el.shadowRoot?.querySelector('.ia-button.warning')).to.exist;
44
49
  });
@@ -84,21 +89,6 @@ describe('Manage bar', () => {
84
89
  expect(spy.callCount).to.equal(1);
85
90
  });
86
91
 
87
- it('emits event when Remove Items button clicked', async () => {
88
- const spy = Sinon.spy();
89
- const el = await fixture<ManageBar>(
90
- html`<manage-bar @removeItems=${spy} removeAllowed></manage-bar>`
91
- );
92
-
93
- const removeItemsBtn = el.shadowRoot?.querySelector(
94
- '.ia-button.danger'
95
- ) as HTMLButtonElement;
96
- expect(removeItemsBtn).to.exist;
97
-
98
- removeItemsBtn.click();
99
- expect(spy.callCount).to.equal(1);
100
- });
101
-
102
92
  it('emits event when Select All button clicked', async () => {
103
93
  const spy = Sinon.spy();
104
94
  const el = await fixture<ManageBar>(
@@ -128,4 +118,37 @@ describe('Manage bar', () => {
128
118
  unselectAllBtn.click();
129
119
  expect(spy.callCount).to.equal(1);
130
120
  });
121
+
122
+ it('opens the remove items modal when showRemoveItemsModal is clicked', async () => {
123
+ const el = await fixture<ManageBar>(html`
124
+ <manage-bar
125
+ .modalManager=${new ModalManager()}
126
+ .selectedItems=${[{ identifier: '1', title: 'Item 1' }]}
127
+ removeAllowed
128
+ ></manage-bar>
129
+ `);
130
+ await el.updateComplete;
131
+
132
+ const removeButton = el.shadowRoot?.querySelector(
133
+ '.ia-button.danger'
134
+ ) as HTMLButtonElement;
135
+ expect(removeButton).to.exist;
136
+
137
+ const showModalSpy = Sinon.spy(
138
+ el.modalManager as ModalManagerInterface,
139
+ 'showModal'
140
+ );
141
+
142
+ await el.updateComplete;
143
+ removeButton?.click();
144
+
145
+ console.log(showModalSpy.args[0][0].config.title?.values[0]);
146
+
147
+ expect(showModalSpy.callCount).to.equal(1);
148
+ expect(el.modalManager?.classList.contains('remove-items')).to.be;
149
+ expect(showModalSpy.args[0][0].config.title?.values[0]).to.equal(
150
+ msg('Are you sure you want to remove these items?')
151
+ );
152
+ expect(showModalSpy.args[0][0].customModalContent).to.exist;
153
+ });
131
154
  });
@@ -0,0 +1,82 @@
1
+ /* eslint-disable import/no-duplicates */
2
+ import { expect, fixture } from '@open-wc/testing';
3
+ import { html } from 'lit';
4
+ import Sinon from 'sinon';
5
+ import type { ManageableItem } from '../../src/models';
6
+ import type { RemoveItemsModalContent } from '../../src/manage/remove-items-modal-content';
7
+ import '../../src/manage/remove-items-modal-content';
8
+
9
+ describe('RemoveItemsModalContent', () => {
10
+ const items: ManageableItem[] = [
11
+ { identifier: '1', title: 'Item 1', date: '2022-01-01' },
12
+ { identifier: '2', title: 'Item 2', date: '2022-01-02' },
13
+ ];
14
+
15
+ it('renders basic component', async () => {
16
+ const el = await fixture<RemoveItemsModalContent>(html`
17
+ <remove-items-modal-content
18
+ .items=${items}
19
+ .message=${''}
20
+ ></remove-items-modal-content>
21
+ `);
22
+
23
+ expect(el.shadowRoot?.querySelector('ul')).to.exist;
24
+ expect(el.shadowRoot?.querySelector('.button-bar')).to.exist;
25
+ expect(el.shadowRoot?.querySelector('.remove-items-btn')).to.exist;
26
+ });
27
+
28
+ it('renders list of items', async () => {
29
+ const el = await fixture<RemoveItemsModalContent>(html`
30
+ <remove-items-modal-content
31
+ .items=${items}
32
+ .message=${''}
33
+ ></remove-items-modal-content>
34
+ `);
35
+
36
+ const listItems = el.shadowRoot?.querySelectorAll('li');
37
+ expect(listItems).to.have.lengthOf(2);
38
+
39
+ listItems?.forEach((item, index) => {
40
+ expect(item.querySelector('.item-title')?.textContent).to.equal(
41
+ items[index].title
42
+ );
43
+ expect(item.querySelector('.item-date')?.textContent).to.equal(
44
+ items[index].date
45
+ );
46
+ });
47
+ });
48
+
49
+ it('renders message', async () => {
50
+ const message = 'This is a test message';
51
+ const el = await fixture<RemoveItemsModalContent>(html`
52
+ <remove-items-modal-content
53
+ .items=${[]}
54
+ .message=${message}
55
+ ></remove-items-modal-content>
56
+ `);
57
+
58
+ expect(el.shadowRoot?.querySelector('.message')?.textContent).to.equal(
59
+ message
60
+ );
61
+ });
62
+
63
+ it('dispatches confirm event when remove items button is clicked', async () => {
64
+ const el = await fixture<RemoveItemsModalContent>(html`
65
+ <remove-items-modal-content
66
+ .items=${items}
67
+ .message=${''}
68
+ ></remove-items-modal-content>
69
+ `);
70
+
71
+ const spy = Sinon.spy();
72
+ el.addEventListener('confirm', spy);
73
+
74
+ const button = el.shadowRoot?.querySelector(
75
+ '.remove-items-btn'
76
+ ) as HTMLInputElement;
77
+ button?.click();
78
+
79
+ expect(spy.calledOnce).to.be.true;
80
+ expect(spy.args[0][0].detail.items).to.deep.equal(items);
81
+ });
82
+ });