From c5110f89bc17290b6e224f9366cfa14dfa431d58 Mon Sep 17 00:00:00 2001 From: reetagithub <51482276+reetagithub@users.noreply.github.com> Date: Thu, 24 Mar 2022 11:18:18 +0200 Subject: [PATCH 01/30] Update fi.json5 Modified some keys to harmonize the translations of term 'administrative'. Also, translated "Administer Workflow" to a verb instead of a noun. --- src/assets/i18n/fi.json5 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/assets/i18n/fi.json5 b/src/assets/i18n/fi.json5 index 02f020a45d..860062fa67 100644 --- a/src/assets/i18n/fi.json5 +++ b/src/assets/i18n/fi.json5 @@ -107,7 +107,7 @@ "admin.registries.bitstream-formats.edit.head": "Tiedostoformaatti: {{ format }}", // "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are hidden from the user, and used for administrative purposes.", - "admin.registries.bitstream-formats.edit.internal.hint": "Sisäisiksi merkittyjä formaatteja käytetään hallinnollisiin tarkoituksiin, ja ne on piilotettu käyttäjiltä.", + "admin.registries.bitstream-formats.edit.internal.hint": "Sisäisiksi merkittyjä formaatteja käytetään ylläpitotarkoituksiin, ja ne on piilotettu käyttäjiltä.", // "admin.registries.bitstream-formats.edit.internal.label": "Internal", "admin.registries.bitstream-formats.edit.internal.label": "Sisäinen", @@ -662,7 +662,7 @@ // "admin.search.breadcrumbs": "Administrative Search", - "admin.search.breadcrumbs": "Hallinnollinen haku", + "admin.search.breadcrumbs": "Ylläpitäjän haku", // "admin.search.collection.edit": "Edit", "admin.search.collection.edit": "Muokkaa", @@ -692,19 +692,19 @@ "admin.search.item.withdraw": "Poista käytöstä", // "admin.search.title": "Administrative Search", - "admin.search.title": "Hallinnollinen haku", + "admin.search.title": "Ylläpitäjän haku", // "administrativeView.search.results.head": "Administrative Search", - "administrativeView.search.results.head": "Hallinnollinen haku", + "administrativeView.search.results.head": "Ylläpitäjän haku", // "admin.workflow.breadcrumbs": "Administer Workflow", - "admin.workflow.breadcrumbs": "Hallinnointityönkulku", + "admin.workflow.breadcrumbs": "Hallinnoi työnkulkua", // "admin.workflow.title": "Administer Workflow", - "admin.workflow.title": "Hallinnointityönkulku", + "admin.workflow.title": "Hallinnoi työnkulkua", // "admin.workflow.item.workflow": "Workflow", "admin.workflow.item.workflow": "Työnkulku", @@ -2954,7 +2954,7 @@ // "menu.section.admin_search": "Admin Search", - "menu.section.admin_search": "Admin-haku", + "menu.section.admin_search": "Ylläpitäjän haku", @@ -3033,7 +3033,7 @@ "menu.section.icon.access_control": "Pääsyoikeudet", // "menu.section.icon.admin_search": "Admin search menu section", - "menu.section.icon.admin_search": "Admin-haku", + "menu.section.icon.admin_search": "Ylläpitäjän haku", // "menu.section.icon.control_panel": "Control Panel menu section", "menu.section.icon.control_panel": "Hallintapaneeli", @@ -3168,7 +3168,7 @@ // "menu.section.workflow": "Administer Workflow", - "menu.section.workflow": "Hallinnointityönkulku", + "menu.section.workflow": "Hallinnoi työnkulkua", // "mydspace.description": "", @@ -5079,7 +5079,7 @@ // "workflowAdmin.search.results.head": "Administer Workflow", - "workflowAdmin.search.results.head": "Hallinnointityönkulku", + "workflowAdmin.search.results.head": "Hallinnoi työnkulkua", From abe1d5c6c7e7385b30665a8640c2a6f0fc29f699 Mon Sep 17 00:00:00 2001 From: Sufiyan Shaikh <“sufiyan.shaikh@4science.com”> Date: Tue, 26 Apr 2022 17:28:54 +0530 Subject: [PATCH 02/30] [DSC-516] Change truncable components in order to show more/less button --- ...-search-result-list-element.component.html | 14 ++- .../truncatable-part.component.html | 8 +- .../truncatable-part.component.scss | 10 ++ .../truncatable-part.component.spec.ts | 78 +++++++++++++++- .../truncatable-part.component.ts | 93 ++++++++++++++++++- .../truncatable/truncatable.component.html | 2 +- .../truncatable/truncatable.component.spec.ts | 11 --- .../truncatable/truncatable.component.ts | 21 +++-- src/assets/i18n/en.json5 | 4 + 9 files changed, 207 insertions(+), 34 deletions(-) diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html index fb0ad21b6e..40f837bcd1 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html @@ -7,13 +7,11 @@ class="lead" [innerHTML]="firstMetadataValue('organization.legalName')"> - - - - - - + + + + diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html index 76595c901f..34227e2583 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html @@ -1,5 +1,11 @@
-
+
+ + + {{ 'item.truncatable-part.show-less' | translate }}
diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss index e69de29bb2..7a1f31f578 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss @@ -0,0 +1,10 @@ +#dontBreakContent:not(.truncated) ~ label{ + display: none; + } + +a { + color: #207698 !important; + text-decoration: none !important; + background-color: transparent !important; + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts index 1b3cdad33e..09109ee400 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts @@ -4,10 +4,16 @@ import { TruncatablePartComponent } from './truncatable-part.component'; import { TruncatableService } from '../truncatable.service'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; +import { getMockTranslateService } from '../../mocks/translate.service.mock'; +import { TranslateLoaderMock } from '../../mocks/translate-loader.mock'; +import { mockTruncatableService } from '../../mocks/mock-trucatable.service'; +import { By } from '@angular/platform-browser'; describe('TruncatablePartComponent', () => { let comp: TruncatablePartComponent; let fixture: ComponentFixture; + let translateService: TranslateService; const id1 = '123'; const id2 = '456'; @@ -22,8 +28,16 @@ describe('TruncatablePartComponent', () => { } }; beforeEach(waitForAsync(() => { + translateService = getMockTranslateService(); TestBed.configureTestingModule({ - imports: [NoopAnimationsModule], + imports: [NoopAnimationsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + ], declarations: [TruncatablePartComponent], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, @@ -52,6 +66,11 @@ describe('TruncatablePartComponent', () => { it('lines should equal minlines', () => { expect((comp as any).lines).toEqual(comp.minLines.toString()); }); + + it('collapseButton should be hidden', () => { + const a = fixture.debugElement.query(By.css('#collapseButton')); + expect(a).toBeNull(); + }); }); describe('When the item is expanded', () => { @@ -72,5 +91,62 @@ describe('TruncatablePartComponent', () => { fixture.detectChanges(); expect((comp as any).lines).toEqual('none'); }); + + it('collapseButton should be shown', () => { + (comp as any).setLines(); + (comp as any).expandable = true; + fixture.detectChanges(); + const a = fixture.debugElement.query(By.css('#collapseButton')); + expect(a).not.toBeNull(); + }); }); }); + +describe('TruncatablePartComponent', () => { + let comp: TruncatablePartComponent; + let fixture: ComponentFixture; + let translateService: TranslateService; + const identifier = '1234567890'; + let truncatableService; + beforeEach(waitForAsync(() => { + translateService = getMockTranslateService(); + TestBed.configureTestingModule({ + imports: [ + NoopAnimationsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + }), + ], + declarations: [TruncatablePartComponent], + providers: [ + { provide: TruncatableService, useValue: mockTruncatableService }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(TruncatablePartComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TruncatablePartComponent); + comp = fixture.componentInstance; // TruncatablePartComponent test instance + comp.id = identifier; + fixture.detectChanges(); + truncatableService = (comp as any).service; + }); + + describe('When toggle is called', () => { + beforeEach(() => { + spyOn(truncatableService, 'toggle'); + comp.toggle(); + }); + + it('should call toggle on the TruncatableService', () => { + expect(truncatableService.toggle).toHaveBeenCalledWith(identifier); + }); + }); + +}); diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index 2a375e95d9..fe8279ee07 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -1,6 +1,8 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, Inject, Input, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; import { TruncatableService } from '../truncatable.service'; import { hasValue } from '../../empty.util'; +import { DOCUMENT, isPlatformBrowser } from '@angular/common'; +import { NativeWindowRef, NativeWindowService } from 'src/app/core/services/window.service'; @Component({ selector: 'ds-truncatable-part', @@ -49,8 +51,34 @@ export class TruncatablePartComponent implements OnInit, OnDestroy { * Subscription to unsubscribe from */ private sub; + /** + * store variable used for local to expand collapse + */ + expand = false; + /** + * variable to check if expandable + */ + expandable = false; + /** + * variable to check if it is a browser + */ + isBrowser: boolean; + /** + * variable which save get observer + */ + observer; + /** + * variable to save content to be observed + */ + observedContent; - public constructor(private service: TruncatableService) { + public constructor( + private service: TruncatableService, + @Inject(DOCUMENT) private document: any, + @Inject(NativeWindowService) private _window: NativeWindowRef, + @Inject(PLATFORM_ID) platformId: object + ) { + this.isBrowser = isPlatformBrowser(platformId); } /** @@ -67,12 +95,70 @@ export class TruncatablePartComponent implements OnInit, OnDestroy { this.sub = this.service.isCollapsed(this.id).subscribe((collapsed: boolean) => { if (collapsed) { this.lines = this.minLines.toString(); + this.expand = false; } else { this.lines = this.maxLines < 0 ? 'none' : this.maxLines.toString(); + this.expand = true; } }); } + ngAfterContentChecked() { + if (this.isBrowser) { + if (this.observer && this.observedContent) { + this.toUnobserve(); + } + this.toObserve(); + } + } + + /** + * Function to get data to be observed + */ + toObserve() { + this.observedContent = this.document.querySelectorAll('#dontBreakContent'); + this.observer = new (this._window.nativeWindow as any).ResizeObserver(entries => { + // tslint:disable-next-line:prefer-const + for (let entry of entries) { + if (!entry.target.classList.contains('notruncatable')) { + if (entry.target.scrollHeight > entry.contentRect.height) { + if (entry.target.children.length > 0) { + if (entry.target.children[0].offsetHeight > entry.contentRect.height) { + entry.target.classList.add('truncated'); + } else { + entry.target.classList.remove('truncated'); + } + } else { + entry.target.classList.add('truncated'); + } + } else { + entry.target.classList.remove('truncated'); + } + } + } + }); + this.observedContent.forEach(p => { + this.observer.observe(p); + }); + } + + /** + * Function to remove data which is observed + */ + toUnobserve() { + this.observedContent.forEach(p => { + this.observer.unobserve(p); + }); + } + + /** + * Expands the truncatable when it's collapsed, collapses it when it's expanded + */ + public toggle() { + this.service.toggle(this.id); + this.expandable = !this.expandable; + } + /** * Unsubscribe from the subscription */ @@ -80,5 +166,8 @@ export class TruncatablePartComponent implements OnInit, OnDestroy { if (hasValue(this.sub)) { this.sub.unsubscribe(); } + if (this.isBrowser) { + this.toUnobserve(); + } } } diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html index b524e5e754..342e79f638 100644 --- a/src/app/shared/truncatable/truncatable.component.html +++ b/src/app/shared/truncatable/truncatable.component.html @@ -1,3 +1,3 @@ -
+
diff --git a/src/app/shared/truncatable/truncatable.component.spec.ts b/src/app/shared/truncatable/truncatable.component.spec.ts index b539ab0d56..29100e50d2 100644 --- a/src/app/shared/truncatable/truncatable.component.spec.ts +++ b/src/app/shared/truncatable/truncatable.component.spec.ts @@ -70,15 +70,4 @@ describe('TruncatableComponent', () => { }); }); - describe('When toggle is called', () => { - beforeEach(() => { - spyOn(truncatableService, 'toggle'); - comp.toggle(); - }); - - it('should call toggle on the TruncatableService', () => { - expect(truncatableService.toggle).toHaveBeenCalledWith(identifier); - }); - }); - }); diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index e22ce4441e..61ec9c422a 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -1,6 +1,4 @@ -import { - Component, Input -} from '@angular/core'; +import { AfterViewChecked, Component, ElementRef, Input, OnInit } from '@angular/core'; import { TruncatableService } from './truncatable.service'; @Component({ @@ -13,7 +11,7 @@ import { TruncatableService } from './truncatable.service'; /** * Component that represents a section with one or more truncatable parts that all listen to this state */ -export class TruncatableComponent { +export class TruncatableComponent implements OnInit, AfterViewChecked { /** * Is true when all truncatable parts in this truncatable should be expanded on loading */ @@ -29,7 +27,7 @@ export class TruncatableComponent { */ @Input() onHover = false; - public constructor(private service: TruncatableService) { + public constructor(private service: TruncatableService, private el: ElementRef,) { } /** @@ -61,11 +59,14 @@ export class TruncatableComponent { } } - /** - * Expands the truncatable when it's collapsed, collapses it when it's expanded - */ - public toggle() { - this.service.toggle(this.id); + ngAfterViewChecked() { + const truncatedElements = this.el.nativeElement.querySelectorAll('.truncated'); + if (truncatedElements?.length > 1) { + for (let i = 0; i < (truncatedElements.length - 1); i++) { + truncatedElements[i].classList.remove('truncated'); + truncatedElements[i].classList.add('notruncatable'); + } + } } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index c3c68a6882..12de3ffdea 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2056,6 +2056,10 @@ "item.search.title": "Item Search", + "item.truncatable-part.show-more": "Show more", + + "item.truncatable-part.show-less": "Collapse", + "item.page.abstract": "Abstract", From 0812377b58c88f552677d3e4868fa21382a5d680 Mon Sep 17 00:00:00 2001 From: Sufiyan Shaikh <“sufiyan.shaikh@4science.com”> Date: Wed, 27 Apr 2022 11:50:53 +0530 Subject: [PATCH 03/30] [DSC-516] Test cases changes --- ...item-admin-search-result-grid-element.component.spec.ts | 2 ++ .../truncatable-part/truncatable-part.component.spec.ts | 7 +++++-- .../truncatable-part/truncatable-part.component.ts | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts index dedada5f5f..148cfb13cb 100644 --- a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts +++ b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts @@ -18,6 +18,7 @@ import { ItemAdminSearchResultGridElementComponent } from './item-admin-search-r import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils'; import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock'; import { ThemeService } from '../../../../../shared/theme-support/theme.service'; +import { NativeWindowRef, NativeWindowService } from '../../../../../core/services/window.service'; describe('ItemAdminSearchResultGridElementComponent', () => { let component: ItemAdminSearchResultGridElementComponent; @@ -52,6 +53,7 @@ describe('ItemAdminSearchResultGridElementComponent', () => { SharedModule ], providers: [ + { provide: NativeWindowService, useValue: new NativeWindowRef() }, { provide: TruncatableService, useValue: mockTruncatableService }, { provide: BitstreamDataService, useValue: mockBitstreamDataService }, { provide: ThemeService, useValue: mockThemeService }, diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts index 09109ee400..09d603e6b7 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts @@ -9,6 +9,7 @@ import { getMockTranslateService } from '../../mocks/translate.service.mock'; import { TranslateLoaderMock } from '../../mocks/translate-loader.mock'; import { mockTruncatableService } from '../../mocks/mock-trucatable.service'; import { By } from '@angular/platform-browser'; +import { NativeWindowRef, NativeWindowService } from '../../../core/services/window.service'; describe('TruncatablePartComponent', () => { let comp: TruncatablePartComponent; @@ -29,7 +30,7 @@ describe('TruncatablePartComponent', () => { }; beforeEach(waitForAsync(() => { translateService = getMockTranslateService(); - TestBed.configureTestingModule({ + void TestBed.configureTestingModule({ imports: [NoopAnimationsModule, TranslateModule.forRoot({ loader: { @@ -40,6 +41,7 @@ describe('TruncatablePartComponent', () => { ], declarations: [TruncatablePartComponent], providers: [ + { provide: NativeWindowService, useValue: new NativeWindowRef() }, { provide: TruncatableService, useValue: truncatableServiceStub }, ], schemas: [NO_ERRORS_SCHEMA] @@ -110,7 +112,7 @@ describe('TruncatablePartComponent', () => { let truncatableService; beforeEach(waitForAsync(() => { translateService = getMockTranslateService(); - TestBed.configureTestingModule({ + void TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, TranslateModule.forRoot({ @@ -122,6 +124,7 @@ describe('TruncatablePartComponent', () => { ], declarations: [TruncatablePartComponent], providers: [ + { provide: NativeWindowService, useValue: new NativeWindowRef() }, { provide: TruncatableService, useValue: mockTruncatableService }, ], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index fe8279ee07..7fe36e950a 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, Input, OnDestroy, OnInit, PLATFORM_ID } from '@angul import { TruncatableService } from '../truncatable.service'; import { hasValue } from '../../empty.util'; import { DOCUMENT, isPlatformBrowser } from '@angular/common'; -import { NativeWindowRef, NativeWindowService } from 'src/app/core/services/window.service'; +import { NativeWindowRef, NativeWindowService } from '../../../core/services/window.service'; @Component({ selector: 'ds-truncatable-part', From aaa166593e8fb2a2f082808934a0ad95c890d639 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 27 Apr 2022 18:59:29 +0200 Subject: [PATCH 04/30] [DSC-516] Fix accessibility issues --- .../truncatable-part.component.html | 16 +++++++--------- .../truncatable-part.component.scss | 15 ++++++--------- .../truncatable-part.component.spec.ts | 4 ++-- .../truncatable-part.component.ts | 11 +++++------ 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html index 34227e2583..cb9f529f99 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html @@ -1,11 +1,9 @@
-
- -
- - - {{ 'item.truncatable-part.show-less' | translate }} +
+ +
+ +
diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss index 7a1f31f578..f67d343cd6 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss @@ -1,10 +1,7 @@ -#dontBreakContent:not(.truncated) ~ label{ - display: none; - } +.content:not(.truncated) ~ button.expandButton { + display: none; +} -a { - color: #207698 !important; - text-decoration: none !important; - background-color: transparent !important; - cursor: pointer; -} \ No newline at end of file +.btn:focus { + box-shadow: none !important; +} diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts index 09d603e6b7..08d3e18117 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts @@ -70,7 +70,7 @@ describe('TruncatablePartComponent', () => { }); it('collapseButton should be hidden', () => { - const a = fixture.debugElement.query(By.css('#collapseButton')); + const a = fixture.debugElement.query(By.css('.collapseButton')); expect(a).toBeNull(); }); }); @@ -98,7 +98,7 @@ describe('TruncatablePartComponent', () => { (comp as any).setLines(); (comp as any).expandable = true; fixture.detectChanges(); - const a = fixture.debugElement.query(By.css('#collapseButton')); + const a = fixture.debugElement.query(By.css('.collapseButton')); expect(a).not.toBeNull(); }); }); diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index 7fe36e950a..0bfcf25d39 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, Input, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; +import { AfterContentChecked, Component, Inject, Input, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; import { TruncatableService } from '../truncatable.service'; import { hasValue } from '../../empty.util'; import { DOCUMENT, isPlatformBrowser } from '@angular/common'; @@ -14,7 +14,7 @@ import { NativeWindowRef, NativeWindowService } from '../../../core/services/win * Component that truncates/clamps a piece of text * It needs a TruncatableComponent parent to identify it's current state */ -export class TruncatablePartComponent implements OnInit, OnDestroy { +export class TruncatablePartComponent implements AfterContentChecked, OnInit, OnDestroy { /** * Number of lines shown when the part is collapsed */ @@ -116,10 +116,9 @@ export class TruncatablePartComponent implements OnInit, OnDestroy { * Function to get data to be observed */ toObserve() { - this.observedContent = this.document.querySelectorAll('#dontBreakContent'); - this.observer = new (this._window.nativeWindow as any).ResizeObserver(entries => { - // tslint:disable-next-line:prefer-const - for (let entry of entries) { + this.observedContent = this.document.querySelectorAll('.content'); + this.observer = new (this._window.nativeWindow as any).ResizeObserver((entries) => { + for (let entry of entries) { if (!entry.target.classList.contains('notruncatable')) { if (entry.target.scrollHeight > entry.contentRect.height) { if (entry.target.children.length > 0) { From d15277849b7ead1acb703c2da146363022e096dc Mon Sep 17 00:00:00 2001 From: Alisa Ismailati Date: Sat, 7 May 2022 16:21:08 +0200 Subject: [PATCH 05/30] [CST-5677] Item authorization page --- .../edit-item-page/edit-item-page.module.ts | 5 +- .../item-authorizations.component.html | 36 +++- .../item-authorizations.component.scss | 4 + .../item-authorizations.component.ts | 183 +++++++++++++++--- .../resource-policies.component.html | 13 +- .../resource-policies.component.ts | 6 + 6 files changed, 207 insertions(+), 40 deletions(-) create mode 100644 src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.scss diff --git a/src/app/item-page/edit-item-page/edit-item-page.module.ts b/src/app/item-page/edit-item-page/edit-item-page.module.ts index 97901bd7c8..cf4a3de74b 100644 --- a/src/app/item-page/edit-item-page/edit-item-page.module.ts +++ b/src/app/item-page/edit-item-page/edit-item-page.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgbTooltipModule, NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { SharedModule } from '../../shared/shared.module'; import { EditItemPageRoutingModule } from './edit-item-page.routing.module'; @@ -48,7 +48,8 @@ import { ResourcePoliciesModule } from '../../shared/resource-policies/resource- EditItemPageRoutingModule, SearchPageModule, DragDropModule, - ResourcePoliciesModule + ResourcePoliciesModule, + NgbModule ], declarations: [ EditItemPageComponent, diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.html b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.html index 71aa7b44de..d4af1b4d2b 100644 --- a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.html +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.html @@ -1,13 +1,33 @@
- - - - - + + + + + + +
+
+ +
+
+ + + +
+ +
+
+
+
+ +
- diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.scss b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.scss new file mode 100644 index 0000000000..c3694e6784 --- /dev/null +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.scss @@ -0,0 +1,4 @@ +.auth-bitstream-container { + margin-top: -1em; + margin-bottom: 1.5em; +} diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index 76597a135b..f3313d4cef 100644 --- a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -1,3 +1,5 @@ +import { isEqual } from 'lodash'; +import { DSONameService } from './../../../core/breadcrumbs/dso-name.service'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @@ -25,7 +27,8 @@ interface BundleBitstreamsMapEntry { @Component({ selector: 'ds-item-authorizations', - templateUrl: './item-authorizations.component.html' + templateUrl: './item-authorizations.component.html', + styleUrls:['./item-authorizations.component.scss'] }) /** * Component that handles the item Authorizations @@ -36,14 +39,20 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * A map that contains all bitstream of the item's bundles * @type {Observable>>>} */ - public bundleBitstreamsMap: Map>> = new Map>>(); + public bundleBitstreamsMap: Map = new Map(); /** - * The list of bundle for the item + * The list of all bundles for the item * @type {Observable>} */ private bundles$: BehaviorSubject = new BehaviorSubject([]); + /** + * The list of bundles to be displayed in the template + * @type {BehaviorSubject} + */ + bundlesToShow$: BehaviorSubject = new BehaviorSubject([]); + /** * The target editing item * @type {Observable} @@ -56,6 +65,37 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { */ private subs: Subscription[] = []; + /** + * The size of the bundles to be loaded on demand + * @type {number} + */ + bunblesPerPage = 6; + + /** + * The number of current page + * @type {number} + */ + bunblesPageSize = 1; + + /** + * The flag to show or not the 'Load more' button + * based on the condition if all the bundles are loaded or not + * @type {boolean} + */ + allBundlesLoaded = false; + + /** + * Initial size of loaded bitstreams + * The size of incrementation used in bitstream pagination + */ + bitstreamSize = 4; + + /** + * The size of the loaded bitstremas at a certain moment + * @private + */ + private bitstreamPageSize = 4; + /** * Initialize instance variables * @@ -64,7 +104,8 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { */ constructor( private linkService: LinkService, - private route: ActivatedRoute + private route: ActivatedRoute, + private nameService: DSONameService ) { } @@ -72,16 +113,53 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * Initialize the component, setting up the bundle and bitstream within the item */ ngOnInit(): void { + this.getBundlesPerItem(); + } + + /** + * Return the item's UUID + */ + getItemUUID(): Observable { + return this.item$.pipe( + map((item: Item) => item.id), + first((UUID: string) => isNotEmpty(UUID)) + ); + } + + /** + * Return the item's name + */ + getItemName(): Observable { + return this.item$.pipe( + map((item: Item) => this.nameService.getName(item)) + ); + } + + /** + * Return all item's bundles + * + * @return an observable that emits all item's bundles + */ + getItemBundles(): Observable { + return this.bundles$.asObservable(); + } + + /** + * Get all bundles per item + * and all the bitstreams per bundle + * @param page number of current page + */ + getBundlesPerItem(page: number = 1) { this.item$ = this.route.data.pipe( map((data) => data.dso), getFirstSucceededRemoteDataWithNotEmptyPayload(), map((item: Item) => this.linkService.resolveLink( item, - followLink('bundles', {}, followLink('bitstreams')) + followLink('bundles', {findListOptions: {currentPage : page, elementsPerPage: this.bunblesPerPage}}, followLink('bitstreams')) )) ) as Observable; - const bundles$: Observable> = this.item$.pipe( + const bundles$: Observable> = this.item$.pipe( filter((item: Item) => isNotEmpty(item.bundles)), mergeMap((item: Item) => item.bundles), getFirstSucceededRemoteDataWithNotEmptyPayload(), @@ -96,37 +174,40 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { take(1), map((list: PaginatedList) => list.page) ).subscribe((bundles: Bundle[]) => { - this.bundles$.next(bundles); + if (isEqual(bundles.length,0) || bundles.length < this.bunblesPerPage) { + this.allBundlesLoaded = true; + } + if (isEqual(page, 1)) { + this.bundles$.next(bundles); + this.bundlesToShow$.next(bundles); + } else { + this.bundlesToShow$.next(this.bundles$.getValue().concat(bundles)); + this.bundles$.next(this.bundles$.getValue().concat(bundles)); + } }), bundles$.pipe( take(1), mergeMap((list: PaginatedList) => list.page), map((bundle: Bundle) => ({ id: bundle.id, bitstreams: this.getBundleBitstreams(bundle) })) ).subscribe((entry: BundleBitstreamsMapEntry) => { - this.bundleBitstreamsMap.set(entry.id, entry.bitstreams); + let bitstreamMapValues: BitstreamMapValue = { + isCollapsed: true, + allBitstreamsLoaded: false, + bitstreams: null + }; + let bits = entry.bitstreams.pipe( + map((b: PaginatedList) => { + bitstreamMapValues.allBitstreamsLoaded = b?.page.length < this.bitstreamSize ; + let firstLoaded = [...b.page.slice(0, this.bitstreamSize)]; + return firstLoaded; + }) + ); + bitstreamMapValues.bitstreams = bits; + this.bundleBitstreamsMap.set(entry.id, bitstreamMapValues); }) ); } - /** - * Return the item's UUID - */ - getItemUUID(): Observable { - return this.item$.pipe( - map((item: Item) => item.id), - first((UUID: string) => isNotEmpty(UUID)) - ); - } - - /** - * Return all item's bundles - * - * @return an observable that emits all item's bundles - */ - getItemBundles(): Observable { - return this.bundles$.asObservable(); - } - /** * Return all bundle's bitstreams * @@ -142,6 +223,48 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { ); } + /** + * Changes the collapsible state of the area that contains the bitstream list + * @param bundleId Id of bundle responsible for the requested bitstreams + */ + collapseArea(bundleId: string) { + this.bundleBitstreamsMap.get(bundleId).isCollapsed = !this.bundleBitstreamsMap.get(bundleId).isCollapsed; + } + + /** + * Loads as much bundles as initial value of bundleSize to be displayed + */ + onBunbleLoad(){ + this.bunblesPageSize ++; + this.getBundlesPerItem(this.bunblesPageSize); + } + + /** + * Calculates the bitstreams that are going to be loaded on demand, + * based on the number configured on this.bitstreamSize. + * @param bundle parent of bitstreams that are requested to be shown + * @returns Subscription + */ + onBitstreamsLoad(bundle: Bundle) { + return this.getBundleBitstreams(bundle).pipe( + map((res: PaginatedList) => { + let nextBitstreams = res?.page.slice(this.bitstreamPageSize, this.bitstreamPageSize + this.bitstreamSize); + let bitstreamsToShow = this.bundleBitstreamsMap.get(bundle.id).bitstreams.pipe( + map((existingBits: Bitstream[])=> { + return [... existingBits, ...nextBitstreams]; + }) + ); + this.bitstreamPageSize = this.bitstreamPageSize + this.bitstreamSize; + let bitstreamMapValues: BitstreamMapValue = { + bitstreams: bitstreamsToShow , + isCollapsed: this.bundleBitstreamsMap.get(bundle.id).isCollapsed, + allBitstreamsLoaded: res?.page.length <= this.bitstreamPageSize + }; + this.bundleBitstreamsMap.set(bundle.id, bitstreamMapValues); + }) + ).subscribe(); + } + /** * Unsubscribe from all subscriptions */ @@ -151,3 +274,9 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { .forEach((subscription) => subscription.unsubscribe()); } } + +export interface BitstreamMapValue { + bitstreams: Observable; + isCollapsed: boolean; + allBitstreamsLoaded: boolean; +} diff --git a/src/app/shared/resource-policies/resource-policies.component.html b/src/app/shared/resource-policies/resource-policies.component.html index 0a1ccf7952..5d11ac81f2 100644 --- a/src/app/shared/resource-policies/resource-policies.component.html +++ b/src/app/shared/resource-policies/resource-policies.component.html @@ -4,9 +4,16 @@
- {{ 'resource-policies.table.headers.title.for.' + resourceType | translate }} {{resourceUUID}} + + {{ 'resource-policies.table.headers.title.for.' + resourceType | translate }} + + {{resourceName}} + + ({{resourceUUID}}) + +
- -
@@ -21,13 +21,13 @@ [resourceName]="bitstream.name">
- +
- +
diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index f3313d4cef..a833b90b20 100644 --- a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -45,13 +45,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * The list of all bundles for the item * @type {Observable>} */ - private bundles$: BehaviorSubject = new BehaviorSubject([]); - - /** - * The list of bundles to be displayed in the template - * @type {BehaviorSubject} - */ - bundlesToShow$: BehaviorSubject = new BehaviorSubject([]); + bundles$: BehaviorSubject = new BehaviorSubject([]); /** * The target editing item @@ -69,13 +63,13 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * The size of the bundles to be loaded on demand * @type {number} */ - bunblesPerPage = 6; + bunblesPerPage = 1; /** * The number of current page * @type {number} */ - bunblesPageSize = 1; + bunblesPageSize = 6; /** * The flag to show or not the 'Load more' button @@ -179,9 +173,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { } if (isEqual(page, 1)) { this.bundles$.next(bundles); - this.bundlesToShow$.next(bundles); } else { - this.bundlesToShow$.next(this.bundles$.getValue().concat(bundles)); this.bundles$.next(this.bundles$.getValue().concat(bundles)); } }), diff --git a/src/app/shared/resource-policies/resource-policies.component.html b/src/app/shared/resource-policies/resource-policies.component.html index 5d11ac81f2..d1fd9266b1 100644 --- a/src/app/shared/resource-policies/resource-policies.component.html +++ b/src/app/shared/resource-policies/resource-policies.component.html @@ -6,7 +6,6 @@
{{ 'resource-policies.table.headers.title.for.' + resourceType | translate }} - {{resourceName}} ({{resourceUUID}}) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 76f4f538ea..cef52fde9c 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -848,6 +848,12 @@ "collection.edit.tabs.authorizations.title": "Collection Edit - Authorizations", + "collection.edit.item.authorizations.load-bundle-button": "Load more bundles", + + "collection.edit.item.authorizations.load-more-button": "Load more", + + "collection.edit.item.authorizations.show-bitstreams-button": "Show all Bitstreams' Policies for Bundle", + "collection.edit.tabs.metadata.head": "Edit Metadata", "collection.edit.tabs.metadata.title": "Collection Edit - Metadata", From 6cd41be3b80278fd086ffbf6ad7ad023a5aa3e67 Mon Sep 17 00:00:00 2001 From: Alisa Ismailati Date: Mon, 9 May 2022 12:01:46 +0200 Subject: [PATCH 07/30] [CST-5677] Changed bunblesPerPage value --- .../item-authorizations/item-authorizations.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index a833b90b20..f018d1c642 100644 --- a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -63,7 +63,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * The size of the bundles to be loaded on demand * @type {number} */ - bunblesPerPage = 1; + bunblesPerPage = 6; /** * The number of current page From 32d7fca27af3d92eda08c998414a2927fb4ad2c3 Mon Sep 17 00:00:00 2001 From: Alisa Ismailati Date: Mon, 9 May 2022 12:02:50 +0200 Subject: [PATCH 08/30] [CST-5677] Changed bunblesPageSize value --- .../item-authorizations/item-authorizations.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index f018d1c642..3a7a7d95f2 100644 --- a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -69,7 +69,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * The number of current page * @type {number} */ - bunblesPageSize = 6; + bunblesPageSize = 1; /** * The flag to show or not the 'Load more' button From d54f959613a60ed2fd411777338072d00d014440 Mon Sep 17 00:00:00 2001 From: Sufiyan Shaikh Date: Wed, 25 May 2022 17:02:11 +0530 Subject: [PATCH 09/30] [DSC-516] Author show more button fixed --- .../truncatable-part.component.ts | 20 +++++++++---------- .../truncatable/truncatable.component.ts | 6 +++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index 0bfcf25d39..2c3cb925cd 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -116,23 +116,21 @@ export class TruncatablePartComponent implements AfterContentChecked, OnInit, On * Function to get data to be observed */ toObserve() { - this.observedContent = this.document.querySelectorAll('.content'); + this.observedContent = this.document.querySelectorAll('.content:not(.notruncatable)'); this.observer = new (this._window.nativeWindow as any).ResizeObserver((entries) => { for (let entry of entries) { - if (!entry.target.classList.contains('notruncatable')) { - if (entry.target.scrollHeight > entry.contentRect.height) { - if (entry.target.children.length > 0) { - if (entry.target.children[0].offsetHeight > entry.contentRect.height) { - entry.target.classList.add('truncated'); - } else { - entry.target.classList.remove('truncated'); - } - } else { + if (entry.target.scrollHeight > entry.contentRect.height) { + if (entry.target.children.length > 0) { + if (entry.target.children[entry.target.children.length - 1].offsetHeight > entry.contentRect.height) { entry.target.classList.add('truncated'); + } else { + entry.target.classList.remove('truncated'); } } else { - entry.target.classList.remove('truncated'); + entry.target.classList.add('truncated'); } + } else { + entry.target.classList.remove('truncated'); } } }); diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index 61ec9c422a..3f3b91b018 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -1,4 +1,4 @@ -import { AfterViewChecked, Component, ElementRef, Input, OnInit } from '@angular/core'; +import { AfterContentChecked, Component, ElementRef, Input, OnInit } from '@angular/core'; import { TruncatableService } from './truncatable.service'; @Component({ @@ -11,7 +11,7 @@ import { TruncatableService } from './truncatable.service'; /** * Component that represents a section with one or more truncatable parts that all listen to this state */ -export class TruncatableComponent implements OnInit, AfterViewChecked { +export class TruncatableComponent implements OnInit, AfterContentChecked { /** * Is true when all truncatable parts in this truncatable should be expanded on loading */ @@ -59,7 +59,7 @@ export class TruncatableComponent implements OnInit, AfterViewChecked { } } - ngAfterViewChecked() { + ngAfterContentChecked() { const truncatedElements = this.el.nativeElement.querySelectorAll('.truncated'); if (truncatedElements?.length > 1) { for (let i = 0; i < (truncatedElements.length - 1); i++) { From 5810309ff85f6a318139041bfd4b3330b3328444 Mon Sep 17 00:00:00 2001 From: Sufiyan Shaikh Date: Thu, 26 May 2022 14:43:41 +0530 Subject: [PATCH 10/30] [DSC-516] Performance improvement --- .../truncatable-part.component.html | 2 +- .../truncatable-part.component.ts | 99 ++++++------------- 2 files changed, 32 insertions(+), 69 deletions(-) diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html index cb9f529f99..83ca72e84a 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html @@ -1,5 +1,5 @@
-
+
+
diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index 3a7a7d95f2..eab14824ff 100644 --- a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -63,13 +63,13 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * The size of the bundles to be loaded on demand * @type {number} */ - bunblesPerPage = 6; + bundlesPerPage = 6; /** * The number of current page * @type {number} */ - bunblesPageSize = 1; + bundlesPageSize = 1; /** * The flag to show or not the 'Load more' button @@ -149,7 +149,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { getFirstSucceededRemoteDataWithNotEmptyPayload(), map((item: Item) => this.linkService.resolveLink( item, - followLink('bundles', {findListOptions: {currentPage : page, elementsPerPage: this.bunblesPerPage}}, followLink('bitstreams')) + followLink('bundles', {findListOptions: {currentPage : page, elementsPerPage: this.bundlesPerPage}}, followLink('bitstreams')) )) ) as Observable; @@ -168,7 +168,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { take(1), map((list: PaginatedList) => list.page) ).subscribe((bundles: Bundle[]) => { - if (isEqual(bundles.length,0) || bundles.length < this.bunblesPerPage) { + if (isEqual(bundles.length,0) || bundles.length < this.bundlesPerPage) { this.allBundlesLoaded = true; } if (isEqual(page, 1)) { @@ -226,9 +226,9 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { /** * Loads as much bundles as initial value of bundleSize to be displayed */ - onBunbleLoad(){ - this.bunblesPageSize ++; - this.getBundlesPerItem(this.bunblesPageSize); + onBundleLoad(){ + this.bundlesPageSize ++; + this.getBundlesPerItem(this.bundlesPageSize); } /** From 3c3a679ef7aca3a3156a019b427003aaf87d1577 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Thu, 9 Jun 2022 18:08:24 +0200 Subject: [PATCH 22/30] [CST-5677] Label fixed --- src/assets/i18n/en.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 1652ce4be8..e733654d94 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -866,7 +866,7 @@ "collection.edit.item.authorizations.load-more-button": "Load more", - "collection.edit.item.authorizations.show-bitstreams-button": "Show all Bitstreams' Policies for Bundle", + "collection.edit.item.authorizations.show-bitstreams-button": "Show bitstream policies for bundle", "collection.edit.tabs.metadata.head": "Edit Metadata", @@ -3662,7 +3662,7 @@ "submission.import-external.preview.title.OrgUnit": "Organizational Unit Preview", "submission.import-external.preview.title.Person": "Person Preview", - + "submission.import-external.preview.title.Project": "Project Preview", "submission.import-external.preview.subtitle": "The metadata below was imported from an external source. It will be pre-filled when you start the submission.", From fca8c223e7898635c05abf95f06d8e2d77a6df47 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Thu, 9 Jun 2022 18:49:44 +0200 Subject: [PATCH 23/30] [CST-5677] Empty subscription fixed --- .../item-authorizations.component.ts | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index eab14824ff..8ed2f9a12e 100644 --- a/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -1,5 +1,5 @@ import { isEqual } from 'lodash'; -import { DSONameService } from './../../../core/breadcrumbs/dso-name.service'; +import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @@ -8,7 +8,8 @@ import { catchError, filter, first, map, mergeMap, take } from 'rxjs/operators'; import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model'; import { - getFirstSucceededRemoteDataPayload, getFirstSucceededRemoteDataWithNotEmptyPayload, + getFirstSucceededRemoteDataPayload, + getFirstSucceededRemoteDataWithNotEmptyPayload, } from '../../../core/shared/operators'; import { Item } from '../../../core/shared/item.model'; import { followLink } from '../../../shared/utils/follow-link-config.model'; @@ -95,6 +96,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * * @param {LinkService} linkService * @param {ActivatedRoute} route + * @param nameService */ constructor( private linkService: LinkService, @@ -187,14 +189,12 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { allBitstreamsLoaded: false, bitstreams: null }; - let bits = entry.bitstreams.pipe( + bitstreamMapValues.bitstreams = entry.bitstreams.pipe( map((b: PaginatedList) => { - bitstreamMapValues.allBitstreamsLoaded = b?.page.length < this.bitstreamSize ; - let firstLoaded = [...b.page.slice(0, this.bitstreamSize)]; - return firstLoaded; + bitstreamMapValues.allBitstreamsLoaded = b?.page.length < this.bitstreamSize; + return [...b.page.slice(0, this.bitstreamSize)]; }) ); - bitstreamMapValues.bitstreams = bits; this.bundleBitstreamsMap.set(entry.id, bitstreamMapValues); }) ); @@ -238,23 +238,21 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { * @returns Subscription */ onBitstreamsLoad(bundle: Bundle) { - return this.getBundleBitstreams(bundle).pipe( - map((res: PaginatedList) => { - let nextBitstreams = res?.page.slice(this.bitstreamPageSize, this.bitstreamPageSize + this.bitstreamSize); - let bitstreamsToShow = this.bundleBitstreamsMap.get(bundle.id).bitstreams.pipe( - map((existingBits: Bitstream[])=> { - return [... existingBits, ...nextBitstreams]; - }) - ); - this.bitstreamPageSize = this.bitstreamPageSize + this.bitstreamSize; - let bitstreamMapValues: BitstreamMapValue = { - bitstreams: bitstreamsToShow , - isCollapsed: this.bundleBitstreamsMap.get(bundle.id).isCollapsed, - allBitstreamsLoaded: res?.page.length <= this.bitstreamPageSize - }; - this.bundleBitstreamsMap.set(bundle.id, bitstreamMapValues); - }) - ).subscribe(); + return this.getBundleBitstreams(bundle).subscribe((res: PaginatedList) => { + let nextBitstreams = res?.page.slice(this.bitstreamPageSize, this.bitstreamPageSize + this.bitstreamSize); + let bitstreamsToShow = this.bundleBitstreamsMap.get(bundle.id).bitstreams.pipe( + map((existingBits: Bitstream[])=> { + return [... existingBits, ...nextBitstreams]; + }) + ); + this.bitstreamPageSize = this.bitstreamPageSize + this.bitstreamSize; + let bitstreamMapValues: BitstreamMapValue = { + bitstreams: bitstreamsToShow , + isCollapsed: this.bundleBitstreamsMap.get(bundle.id).isCollapsed, + allBitstreamsLoaded: res?.page.length <= this.bitstreamPageSize + }; + this.bundleBitstreamsMap.set(bundle.id, bitstreamMapValues); + }); } /** From 4c19d3a02750767729b6cb93cf55ed9f2b6cd02f Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Thu, 9 Jun 2022 18:50:59 +0200 Subject: [PATCH 24/30] [CST-5677] `@types/node-sass` removed --- package.json | 3 +-- yarn.lock | 7 ------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/package.json b/package.json index 1ac3c95799..9bdf984cf1 100644 --- a/package.json +++ b/package.json @@ -151,7 +151,6 @@ "@types/js-cookie": "2.2.6", "@types/lodash": "^4.14.165", "@types/node": "^14.14.9", - "@types/node-sass": "^4.11.2", "@typescript-eslint/eslint-plugin": "5.11.0", "@typescript-eslint/parser": "5.11.0", "axe-core": "^4.3.3", @@ -211,4 +210,4 @@ "webpack-cli": "^4.2.0", "webpack-dev-server": "^4.5.0" } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index b11284c4f1..3fe250768d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2304,13 +2304,6 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== -"@types/node-sass@^4.11.2": - version "4.11.2" - resolved "https://registry.yarnpkg.com/@types/node-sass/-/node-sass-4.11.2.tgz#ecdaa44a1ba8847bf7dea2aadbfe33a91a263514" - integrity sha512-pOFlTw/OtZda4e+yMjq6/QYuvY0RDMQ+mxXdWj7rfSyf18V8hS4SfgurO+MasAkQsv6Wt6edOGlwh5QqJml9gw== - dependencies: - "@types/node" "*" - "@types/node@*", "@types/node@>=10.0.0": version "17.0.21" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" From 0fbe9731cbd1f9b742bffebc486d0e5924997316 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 9 Jun 2022 19:19:02 +0200 Subject: [PATCH 25/30] added browse.back.all-results --- src/assets/i18n/de.json5 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index edbbf9b8a8..3472f2ea15 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -895,6 +895,8 @@ "bitstream.edit.title": "Datei bearbeiten", + // "browse.back.all-results": "All browse results", + "browse.back.all-results": "Filter zurücksetzen", // "browse.comcol.by.author": "By Author", "browse.comcol.by.author": "Nach Autor:in", From eca0526cced4ca92d8cf2360e4e804310dd8f67c Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 9 Jun 2022 19:27:26 +0200 Subject: [PATCH 26/30] added missing sort order related translation keys --- src/assets/i18n/de.json5 | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index 3472f2ea15..5b748c7e1c 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -4539,10 +4539,29 @@ // "sorting.dc.title.DESC": "Title Descending", "sorting.dc.title.DESC": "Titel absteigend", - // "sorting.score.DESC": "Relevance", - "sorting.score.DESC": "Relevanz", - + // "sorting.score.ASC": "Least Relevant", + "sorting.score.ASC": "Relevanz aufsteigend", + + // "sorting.score.DESC": "Most Relevant", + "sorting.score.DESC": "Relevanz absteigend", + + // "sorting.dc.date.issued.ASC": "Date Issued Ascending", + "sorting.dc.date.issued.ASC": "Erscheinungsdatum aufsteigend", + + // "sorting.dc.date.issued.DESC": "Date Issued Descending", + "sorting.dc.date.issued.DESC": "Erscheinungsdatum absteigend", + // "sorting.dc.date.accessioned.ASC": "Accessioned Date Ascending", + "sorting.dc.date.accessioned.ASC": "Freischaltungsdatum aufsteigend", + + // "sorting.dc.date.accessioned.DESC": "Accessioned Date Descending", + "sorting.dc.date.accessioned.DESC": "Freischaltungsdatum absteigend", + + // "sorting.lastModified.ASC": "Last modified Ascending", + "sorting.lastModified.ASC": "Änderungsdatum aufsteigend", + + // "sorting.lastModified.DESC": "Last modified Descending", + "sorting.lastModified.DESC": "Änderungsdatum absteigend", // "statistics.title": "Statistics", "statistics.title": "Statistiken", From a4699d0fafa1f473b82b2f1bc17706b17cd99c3c Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 9 Jun 2022 19:32:39 +0200 Subject: [PATCH 27/30] added missing key search.form.scope.all --- src/assets/i18n/de.json5 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index 5b748c7e1c..f4fbc8c320 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -4477,8 +4477,10 @@ // "search.form.search_mydspace": "Search MyDSpace", "search.form.search_mydspace": "Suche im persönlichen Arbeitsbereich", - - + // "search.form.scope.all": "All of DSpace", + "search.form.scope.all": "Alles durchsuchen", + + // "search.results.head": "Search Results", "search.results.head": "Suchergebnisse", @@ -4491,7 +4493,11 @@ // "search.results.empty": "Your search returned no results.", "search.results.empty": "Ihre Suche führte zu keinem Ergebnis.", - + // "search.results.view-result": "View", + "search.results.view-result": "Anzeigen", + + // "default.search.results.head": "Search Results", + "default.search.results.head": "Suchergebnisse", // "search.sidebar.close": "Back to results", "search.sidebar.close": "Zurück zu den Ergebnissen", From fa5dc5ccf0b285cd5a89ca676bf61747fd5c13e3 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Thu, 9 Jun 2022 19:35:46 +0200 Subject: [PATCH 28/30] added several missing dso-selector.set-scope.* keys --- src/assets/i18n/de.json5 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index f4fbc8c320..23ab3a29e5 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -1784,6 +1784,18 @@ // "dso-selector.placeholder": "Search for a {{ type }}", "dso-selector.placeholder": "Suche nach {{ type }}", + // "dso-selector.select.collection.head": "Select a collection", + "dso-selector.select.collection.head": "Sammlung auswählen", + + // "dso-selector.set-scope.community.head": "Select a search scope", + "dso-selector.set-scope.community.head": "Suchbereich auswählen", + + // "dso-selector.set-scope.community.button": "Search all of DSpace", + "dso-selector.set-scope.community.button": "Alles durchsuchen", + + // "dso-selector.set-scope.community.input-header": "Search for a community or collection", + "dso-selector.set-scope.community.input-header": "Suche Bereich oder Sammlung", + // "confirmation-modal.export-metadata.header": "Export metadata for {{ dsoName }}", From 06d07dc1df76fc89fe16a82c222ae9722a3de508 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 13 Jun 2022 17:41:51 +0200 Subject: [PATCH 29/30] [DSC-516] Fix issue with sidebar search list element --- ...sidebar-search-list-element.component.html | 6 +-- .../truncatable-part.component.ts | 44 +++++++++++-------- .../truncatable/truncatable.component.ts | 22 +++++++--- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html index 3f93caa278..6a13b7e362 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.html @@ -1,13 +1,13 @@ - +
- +
- +
diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index e73823fa7e..790bd5985d 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -40,6 +40,12 @@ export class TruncatablePartComponent implements AfterViewChecked, OnInit, OnDes @Input() background = 'default'; + /** + * A boolean representing if to show or not the show/collapse toggle. + * This value must have the same value as the parent TruncatableComponent + */ + @Input() showToggle = true; + /** * The view on the truncatable part */ @@ -103,28 +109,30 @@ export class TruncatablePartComponent implements AfterViewChecked, OnInit, OnDes * check for the truncate element */ public truncateElement() { - const entry = this.content.nativeElement; - if (entry.scrollHeight > entry.offsetHeight) { - if (entry.children.length > 0) { - if (entry.children[entry.children.length - 1].offsetHeight > entry.offsetHeight) { - entry.classList.add('truncated'); - entry.classList.remove('removeFaded'); + if (this.showToggle) { + const entry = this.content.nativeElement; + if (entry.scrollHeight > entry.offsetHeight) { + if (entry.children.length > 0) { + if (entry.children[entry.children.length - 1].offsetHeight > entry.offsetHeight) { + entry.classList.add('truncated'); + entry.classList.remove('removeFaded'); + } else { + entry.classList.remove('truncated'); + entry.classList.add('removeFaded'); + } } else { - entry.classList.remove('truncated'); - entry.classList.add('removeFaded'); + if (entry.innerText.length > 0) { + entry.classList.add('truncated'); + entry.classList.remove('removeFaded'); + } else { + entry.classList.remove('truncated'); + entry.classList.add('removeFaded'); + } } } else { - if (entry.innerText.length > 0) { - entry.classList.add('truncated'); - entry.classList.remove('removeFaded'); - } else { - entry.classList.remove('truncated'); - entry.classList.add('removeFaded'); - } + entry.classList.remove('truncated'); + entry.classList.add('removeFaded'); } - } else { - entry.classList.remove('truncated'); - entry.classList.add('removeFaded'); } } diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index 71f99ecd4f..8fca300cd4 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -27,6 +27,12 @@ export class TruncatableComponent implements OnInit, AfterViewChecked { */ @Input() onHover = false; + /** + * A boolean representing if to show or not the show/collapse toggle + * This value must have the same value as the children TruncatablePartComponent + */ + @Input() showToggle = true; + public constructor(private service: TruncatableService, private el: ElementRef,) { } @@ -60,14 +66,16 @@ export class TruncatableComponent implements OnInit, AfterViewChecked { } ngAfterViewChecked() { - const truncatedElements = this.el.nativeElement.querySelectorAll('.truncated'); - if (truncatedElements?.length > 0) { - const truncateElements = this.el.nativeElement.querySelectorAll('.dont-break-out'); - for (let i = 0; i < (truncateElements.length - 1); i++) { - truncateElements[i].classList.remove('truncated'); - truncateElements[i].classList.add('notruncatable'); + if (this.showToggle) { + const truncatedElements = this.el.nativeElement.querySelectorAll('.truncated'); + if (truncatedElements?.length > 0) { + const truncateElements = this.el.nativeElement.querySelectorAll('.dont-break-out'); + for (let i = 0; i < (truncateElements.length - 1); i++) { + truncateElements[i].classList.remove('truncated'); + truncateElements[i].classList.add('notruncatable'); + } + truncateElements[truncateElements.length - 1].classList.add('truncated'); } - truncateElements[truncateElements.length - 1].classList.add('truncated'); } } From da45ff2d83b1c227fec820c6f8416daf88ecd360 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 15 Jun 2022 10:26:13 -0500 Subject: [PATCH 30/30] Ensure CI docker backend always runs DB migrations, even when out of order. --- docker/db.entities.yml | 4 ++-- docker/docker-compose-ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/db.entities.yml b/docker/db.entities.yml index d1dfdf4a26..6473bf2e38 100644 --- a/docker/db.entities.yml +++ b/docker/db.entities.yml @@ -25,7 +25,7 @@ services: ### OVERRIDE default 'entrypoint' in 'docker-compose-rest.yml' #### # Ensure that the database is ready BEFORE starting tomcat # 1. While a TCP connection to dspacedb port 5432 is not available, continue to sleep - # 2. Then, run database migration to init database tables + # 2. Then, run database migration to init database tables (including any out-of-order ignored migrations, if any) # 3. (Custom for Entities) enable Entity-specific collection submission mappings in item-submission.xml # This 'sed' command inserts the sample configurations specific to the Entities data set, see: # https://github.com/DSpace/DSpace/blob/main/dspace/config/item-submission.xml#L36-L49 @@ -35,7 +35,7 @@ services: - '-c' - | while (! /dev/null 2>&1; do sleep 1; done; - /dspace/bin/dspace database migrate + /dspace/bin/dspace database migrate ignored sed -i '/name-map collection-handle="default".*/a \\n \ \ \ diff --git a/docker/docker-compose-ci.yml b/docker/docker-compose-ci.yml index 3bd8f52630..dbe9500499 100644 --- a/docker/docker-compose-ci.yml +++ b/docker/docker-compose-ci.yml @@ -46,14 +46,14 @@ services: - solr_configs:/dspace/solr # Ensure that the database is ready BEFORE starting tomcat # 1. While a TCP connection to dspacedb port 5432 is not available, continue to sleep - # 2. Then, run database migration to init database tables + # 2. Then, run database migration to init database tables (including any out-of-order ignored migrations, if any) # 3. Finally, start Tomcat entrypoint: - /bin/bash - '-c' - | while (! /dev/null 2>&1; do sleep 1; done; - /dspace/bin/dspace database migrate + /dspace/bin/dspace database migrate ignored catalina.sh run # DSpace database container # NOTE: This is customized to use our loadsql image, so that we are using a database with existing test data