From 63c76644c148cde3b4848126764bd1632319b7bf Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Fri, 23 Aug 2024 14:10:58 +0200 Subject: [PATCH 001/104] 117544: First implementation of an aria friendly disabled state --- src/app/shared/disabled-directive.ts | 31 ++++++++++++++++++++++++++++ src/app/shared/shared.module.ts | 2 ++ src/styles/_global-styles.scss | 11 ++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/app/shared/disabled-directive.ts diff --git a/src/app/shared/disabled-directive.ts b/src/app/shared/disabled-directive.ts new file mode 100644 index 0000000000..8d1380917f --- /dev/null +++ b/src/app/shared/disabled-directive.ts @@ -0,0 +1,31 @@ +import { Directive, Input, HostBinding, HostListener } from '@angular/core'; + +@Directive({ + selector: '[dsDisabled]' +}) +export class DisabledDirective { + + @Input() set dsDisabled(value: boolean) { + this.isDisabled = value; + } + + @HostBinding('attr.aria-disabled') isDisabled = false; + @HostBinding('class.disabled') get disabledClass() { return this.isDisabled; } + + @HostListener('click', ['$event']) + handleClick(event: Event) { + if (this.isDisabled) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + } + + @HostListener('keydown', ['$event']) + handleKeydown(event: KeyboardEvent) { + if (this.isDisabled && (event.key === 'Enter' || event.key === 'Space')) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + } +} + diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 0f7871f7f9..c9a6f9b6d0 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -284,6 +284,7 @@ import { } from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component'; import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component'; import { NgxPaginationModule } from 'ngx-pagination'; +import {DisabledDirective} from './disabled-directive'; const MODULES = [ CommonModule, @@ -491,6 +492,7 @@ const DIRECTIVES = [ MetadataFieldValidator, HoverClassDirective, ContextHelpDirective, + DisabledDirective, ]; @NgModule({ diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index b714d399a0..56b7fa464d 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -267,3 +267,14 @@ ul.dso-edit-menu-dropdown > li .nav-item.nav-link { .table td { vertical-align: middle; } + +// An element that is disabled should not have focus styles to avoid confusion +// It however is still focusable for screen readers and keyboard navigation +.disabled { + pointer-events: none; +} + +.disabled:focus { + outline: none; + box-shadow: none; +} From 43745d830b0ba6d13805eab073261474578b5507 Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Fri, 23 Aug 2024 14:52:16 +0200 Subject: [PATCH 002/104] 117544: replace all disabled states with our dsDisabled directive --- .../bulk-access/bulk-access.component.html | 2 +- .../epeople-registry.component.html | 2 +- .../eperson-form/eperson-form.component.html | 4 ++-- .../group-form/group-form.component.html | 2 +- .../members-list/members-list.component.html | 8 ++++---- .../groups-registry.component.html | 2 +- .../delete-collection-page.component.html | 4 ++-- .../collection-source-controls.component.html | 12 ++++++------ .../collection-source.component.html | 8 ++++---- .../delete-community-page.component.html | 4 ++-- .../dso-edit-metadata-value.component.html | 10 +++++----- .../dso-edit-metadata.component.html | 14 +++++++------- .../forgot-password-form.component.html | 2 +- .../end-user-agreement.component.html | 2 +- .../feedback-form/feedback-form.component.html | 2 +- .../bitstream-request-a-copy-page.component.html | 2 +- .../item-bitstreams.component.html | 8 ++++---- .../item-edit-bitstream.component.html | 4 ++-- .../item-move/item-move.component.html | 4 ++-- .../item-operation/item-operation.component.html | 4 ++-- .../edit-relationship-list.component.html | 2 +- .../edit-relationship.component.html | 4 ++-- .../item-relationships.component.html | 8 ++++---- .../media-viewer-video.component.html | 4 ++-- .../orcid-auth/orcid-auth.component.html | 2 +- .../versions/item-versions.component.html | 6 +++--- ...y-dspace-new-external-dropdown.component.html | 4 ++-- ...dspace-new-submission-dropdown.component.html | 4 ++-- .../overview/process-overview.component.html | 4 ++-- .../profile-claim-item-modal.component.html | 2 +- .../profile-page-researcher-form.component.html | 6 +++--- .../register-email-form.component.html | 4 ++-- .../create-profile/create-profile.component.html | 2 +- .../email-request-copy.component.html | 2 +- .../access-control-array-form.component.html | 10 +++++----- .../access-control-form-container.component.html | 16 ++++++++-------- .../shared/ds-select/ds-select.component.html | 2 +- ...o-edit-menu-expandable-section.component.html | 2 +- .../dso-edit-menu-section.component.html | 6 +++--- src/app/shared/dso-page/dso-page.module.ts | 2 ++ ...dynamic-form-control-container.component.html | 2 +- .../dynamic-date-picker-inline.component.html | 2 +- .../date-picker/date-picker.component.html | 6 +++--- .../disabled/dynamic-disabled.component.html | 2 +- .../models/lookup/dynamic-lookup.component.html | 12 ++++++------ .../models/onebox/dynamic-onebox.component.html | 4 ++-- .../dynamic-relation-group.component.html | 6 +++--- .../dynamic-scrollable-dropdown.component.html | 2 +- .../dynamic-lookup-relation-modal.component.html | 8 ++++---- ...rnal-source-entry-import-modal.component.html | 2 +- src/app/shared/form/form.component.html | 4 ++-- .../number-picker/number-picker.component.html | 6 +++--- .../vocabulary-treeview.component.html | 10 +++++----- .../password/log-in-password.component.html | 2 +- .../claimed-task-actions-approve.component.html | 2 +- ...imed-task-actions-decline-task.component.html | 2 +- .../claimed-task-actions-reject.component.html | 4 ++-- ...ed-task-actions-return-to-pool.component.html | 2 +- .../pool-task/pool-task-actions.component.html | 2 +- .../collection-select.component.html | 2 +- .../item-select/item-select.component.html | 4 ++-- .../shared/pagination/pagination.component.html | 6 +++--- .../form/resource-policy-form.component.html | 4 ++-- .../resource-policies.component.html | 4 ++-- .../subscription-modal.component.html | 2 +- .../subscription-view.component.html | 2 +- .../upload/uploader/uploader.component.html | 2 +- .../submission-form-collection.component.html | 2 +- .../footer/submission-form-footer.component.html | 8 ++++---- .../submission-form-section-add.component.html | 2 +- ...sion-import-external-searchbar.component.html | 2 +- ...submission-section-cc-licenses.component.html | 4 ++-- .../edit/section-upload-file-edit.component.html | 2 +- .../file/section-upload-file.component.html | 2 +- .../system-wide-alert-form.component.html | 2 +- 75 files changed, 162 insertions(+), 160 deletions(-) diff --git a/src/app/access-control/bulk-access/bulk-access.component.html b/src/app/access-control/bulk-access/bulk-access.component.html index 382caf85f4..9993bf470e 100644 --- a/src/app/access-control/bulk-access/bulk-access.component.html +++ b/src/app/access-control/bulk-access/bulk-access.component.html @@ -9,7 +9,7 @@ - diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.html b/src/app/access-control/epeople-registry/epeople-registry.component.html index e3a8e2c590..ac8bafec50 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.html +++ b/src/app/access-control/epeople-registry/epeople-registry.component.html @@ -77,7 +77,7 @@ title="{{labelPrefix + 'table.edit.buttons.edit' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}"> -
-
@@ -32,7 +32,7 @@ {{'admin.access-control.epeople.actions.stop-impersonating' | translate}} - diff --git a/src/app/access-control/group-registry/group-form/group-form.component.html b/src/app/access-control/group-registry/group-form/group-form.component.html index 77a81a8daa..54022bfa7b 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.html +++ b/src/app/access-control/group-registry/group-form/group-form.component.html @@ -40,7 +40,7 @@ class="btn btn-outline-secondary"> {{messagePrefix + '.return' | translate}}
- diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html index cc9bf34d64..4465be09c4 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html @@ -71,7 +71,7 @@
- diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html index 4d7b3e657e..4e522e3b51 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html @@ -19,32 +19,32 @@
diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html index d7b0d0c475..3553edf707 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html @@ -1,7 +1,7 @@
- diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html index 525b42610b..fc8589e9b0 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html @@ -22,31 +22,31 @@
- - @@ -72,17 +72,17 @@
- -
diff --git a/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html b/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html index 5fb0006279..785b5c13ec 100644 --- a/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html +++ b/src/app/forgot-password/forgot-password-form/forgot-password-form.component.html @@ -28,7 +28,7 @@
diff --git a/src/app/info/end-user-agreement/end-user-agreement.component.html b/src/app/info/end-user-agreement/end-user-agreement.component.html index 2ab0005c69..4b93d631b7 100644 --- a/src/app/info/end-user-agreement/end-user-agreement.component.html +++ b/src/app/info/end-user-agreement/end-user-agreement.component.html @@ -7,7 +7,7 @@
- +
diff --git a/src/app/info/feedback/feedback-form/feedback-form.component.html b/src/app/info/feedback/feedback-form/feedback-form.component.html index 02745f2580..1b74b398f8 100644 --- a/src/app/info/feedback/feedback-form/feedback-form.component.html +++ b/src/app/info/feedback/feedback-form/feedback-form.component.html @@ -36,7 +36,7 @@
- +
diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html index 1fae737fdb..de30495ce1 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html @@ -79,7 +79,7 @@ diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html index 4cb9577fcb..c921acd27f 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html @@ -10,13 +10,13 @@ class="fas fa-undo-alt">  {{"item.edit.bitstreams.reinstate-button" | translate}} - - - - - - diff --git a/src/app/item-page/edit-item-page/item-operation/item-operation.component.html b/src/app/item-page/edit-item-page/item-operation/item-operation.component.html index 85c6a2cca1..88acec3171 100644 --- a/src/app/item-page/edit-item-page/item-operation/item-operation.component.html +++ b/src/app/item-page/edit-item-page/item-operation/item-operation.component.html @@ -5,12 +5,12 @@
- - diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html index 7cdc903f24..f78f22fd68 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html @@ -1,6 +1,6 @@
{{getRelationshipMessageKey() | async | translate}} - diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html b/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html index e65cd237a3..169a171d3f 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html @@ -9,12 +9,12 @@
- - - -
@@ -7,7 +7,7 @@ ngbDropdown *ngIf="(moreThanOne$ | async)">
-
diff --git a/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html b/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html index a5bbb38d02..a118cd680d 100644 --- a/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html +++ b/src/app/profile-page/profile-claim-item-modal/profile-claim-item-modal.component.html @@ -29,7 +29,7 @@ {{ 'dso-selector.claim.item.not-mine-label' | translate }} - diff --git a/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html b/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html index 2d959c1dfe..aa2b81f057 100644 --- a/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html +++ b/src/app/profile-page/profile-page-researcher-form/profile-page-researcher-form.component.html @@ -13,7 +13,7 @@

{{'researcher.profile.not.associated' | translate}}

- - - diff --git a/src/app/register-page/create-profile/create-profile.component.html b/src/app/register-page/create-profile/create-profile.component.html index f56059ad69..dbdb006785 100644 --- a/src/app/register-page/create-profile/create-profile.component.html +++ b/src/app/register-page/create-profile/create-profile.component.html @@ -81,7 +81,7 @@
diff --git a/src/app/request-copy/email-request-copy/email-request-copy.component.html b/src/app/request-copy/email-request-copy/email-request-copy.component.html index 70146ab52c..7abfda5472 100644 --- a/src/app/request-copy/email-request-copy/email-request-copy.component.html +++ b/src/app/request-copy/email-request-copy/email-request-copy.component.html @@ -13,7 +13,7 @@
diff --git a/src/app/shared/ds-select/ds-select.component.html b/src/app/shared/ds-select/ds-select.component.html index 5a15155d4f..f5e8c9a334 100644 --- a/src/app/shared/ds-select/ds-select.component.html +++ b/src/app/shared/ds-select/ds-select.component.html @@ -13,7 +13,7 @@ class="btn btn-outline-primary selection" (blur)="close.emit($event)" (click)="close.emit($event)" - [disabled]="disabled" + [dsDisabled]="disabled" ngbDropdownToggle> diff --git a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html index cb725e7d70..458e1a76fc 100644 --- a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html +++ b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html @@ -1,7 +1,7 @@
-
diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html index 0796da5a64..2ebc519fba 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html @@ -1,6 +1,6 @@
+ [dsDisabled]="!submissionCcLicenses"> @@ -81,7 +81,7 @@ - + {{ option.label }} diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html index 2baa6c1555..1ce811ce66 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html @@ -1,7 +1,7 @@
diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.html b/src/app/submission/sections/upload/file/section-upload-file.component.html index 8999853d72..f6f7c753da 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.html +++ b/src/app/submission/sections/upload/file/section-upload-file.component.html @@ -22,7 +22,7 @@ - From 4527349dcf85d4d0211a4064efd55350ffcc502b Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Fri, 23 Aug 2024 16:24:30 +0200 Subject: [PATCH 003/104] 117544: alter specs to match new logic --- .../epeople-registry.component.spec.ts | 6 ++- .../eperson-form.component.spec.ts | 12 ++++-- .../groups-registry.component.spec.ts | 12 ++++-- ...llection-source-controls.component.spec.ts | 18 +++++---- .../dso-edit-metadata-value.component.spec.ts | 12 +++++- .../dso-edit-metadata.component.spec.ts | 11 ++++- .../end-user-agreement.component.spec.ts | 6 ++- .../feedback-form.component.spec.ts | 9 +++-- .../item-operation.component.spec.ts | 6 ++- .../edit-relationship-list.component.spec.ts | 3 +- .../versions/item-versions.component.spec.ts | 12 ++++-- src/app/shared/disabled-directive.ts | 2 +- .../dynamic-disabled.component.spec.ts | 2 +- .../lookup/dynamic-lookup.component.spec.ts | 40 +++++++++++++------ ...ic-lookup-relation-modal.component.spec.ts | 18 ++++++--- .../item-select/item-select.component.spec.ts | 6 ++- .../resource-policy-form.component.spec.ts | 10 +++-- ...bmission-form-collection.component.spec.ts | 7 +++- .../submission-form-footer.component.spec.ts | 14 +++++-- 19 files changed, 141 insertions(+), 65 deletions(-) diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts b/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts index 4a09913862..7eadea9256 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts +++ b/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts @@ -27,6 +27,7 @@ import { RequestService } from '../../core/data/request.service'; import { PaginationService } from '../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub'; import { FindListOptions } from '../../core/data/find-list-options.model'; +import {DisabledDirective} from '../../shared/disabled-directive'; describe('EPeopleRegistryComponent', () => { let component: EPeopleRegistryComponent; @@ -131,7 +132,7 @@ describe('EPeopleRegistryComponent', () => { } }), ], - declarations: [EPeopleRegistryComponent], + declarations: [EPeopleRegistryComponent, DisabledDirective], providers: [ { provide: EPersonDataService, useValue: ePersonDataServiceStub }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, @@ -269,7 +270,8 @@ describe('EPeopleRegistryComponent', () => { it('should be disabled', () => { ePeopleDeleteButton = fixture.debugElement.queryAll(By.css('#epeople tr td div button.delete-button')); ePeopleDeleteButton.forEach((deleteButton: DebugElement) => { - expect(deleteButton.nativeElement.disabled).toBe(true); + expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(deleteButton.nativeElement.classList.contains('disabled')).toBeTrue(); }); }); }); diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts index fb911e709c..8b0077bb46 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts @@ -31,6 +31,7 @@ import { PaginationServiceStub } from '../../../shared/testing/pagination-servic import { FindListOptions } from '../../../core/data/find-list-options.model'; import { ValidateEmailNotTaken } from './validators/email-taken.validator'; import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('EPersonFormComponent', () => { let component: EPersonFormComponent; @@ -191,7 +192,7 @@ describe('EPersonFormComponent', () => { } }), ], - declarations: [EPersonFormComponent], + declarations: [EPersonFormComponent, DisabledDirective], providers: [ { provide: EPersonDataService, useValue: ePersonDataServiceStub }, { provide: GroupDataService, useValue: groupsDataService }, @@ -493,14 +494,16 @@ describe('EPersonFormComponent', () => { it('the delete button should be active if the eperson can be deleted', () => { const deleteButton = fixture.debugElement.query(By.css('.delete-button')); - expect(deleteButton.nativeElement.disabled).toBe(false); + expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(deleteButton.nativeElement.classList.contains('disabled')).toBeFalse(); }); it('the delete button should be disabled if the eperson cannot be deleted', () => { component.canDelete$ = observableOf(false); fixture.detectChanges(); const deleteButton = fixture.debugElement.query(By.css('.delete-button')); - expect(deleteButton.nativeElement.disabled).toBe(true); + expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(deleteButton.nativeElement.classList.contains('disabled')).toBeTrue(); }); it('should call the epersonFormComponent delete when clicked on the button', () => { @@ -515,7 +518,8 @@ describe('EPersonFormComponent', () => { // ePersonDataServiceStub.activeEPerson = eperson; spyOn(component.epersonService, 'deleteEPerson').and.returnValue(createSuccessfulRemoteDataObject$('No Content', 204)); const deleteButton = fixture.debugElement.query(By.css('.delete-button')); - expect(deleteButton.nativeElement.disabled).toBe(false); + expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(deleteButton.nativeElement.classList.contains('disabled')).toBeFalse(); deleteButton.triggerEventHandler('click', null); fixture.detectChanges(); expect(component.epersonService.deleteEPerson).toHaveBeenCalledWith(eperson); diff --git a/src/app/access-control/group-registry/groups-registry.component.spec.ts b/src/app/access-control/group-registry/groups-registry.component.spec.ts index 635ba727c2..f9fd91d6cc 100644 --- a/src/app/access-control/group-registry/groups-registry.component.spec.ts +++ b/src/app/access-control/group-registry/groups-registry.component.spec.ts @@ -34,6 +34,7 @@ import { FeatureID } from '../../core/data/feature-authorization/feature-id'; import { NoContent } from '../../core/shared/NoContent.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { DSONameServiceMock, UNDEFINED_NAME } from '../../shared/mocks/dso-name.service.mock'; +import {DisabledDirective} from '../../shared/disabled-directive'; describe('GroupsRegistryComponent', () => { let component: GroupsRegistryComponent; @@ -171,7 +172,7 @@ describe('GroupsRegistryComponent', () => { } }), ], - declarations: [GroupsRegistryComponent], + declarations: [GroupsRegistryComponent, DisabledDirective], providers: [GroupsRegistryComponent, { provide: DSONameService, useValue: new DSONameServiceMock() }, { provide: EPersonDataService, useValue: ePersonDataServiceStub }, @@ -231,7 +232,8 @@ describe('GroupsRegistryComponent', () => { const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit')); expect(editButtonsFound.length).toEqual(2); editButtonsFound.forEach((editButtonFound) => { - expect(editButtonFound.nativeElement.disabled).toBeFalse(); + expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBeNull(); + expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); @@ -265,7 +267,8 @@ describe('GroupsRegistryComponent', () => { const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit')); expect(editButtonsFound.length).toEqual(2); editButtonsFound.forEach((editButtonFound) => { - expect(editButtonFound.nativeElement.disabled).toBeFalse(); + expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBeNull(); + expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); }); @@ -284,7 +287,8 @@ describe('GroupsRegistryComponent', () => { const editButtonsFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(5) button.btn-edit')); expect(editButtonsFound.length).toEqual(2); editButtonsFound.forEach((editButtonFound) => { - expect(editButtonFound.nativeElement.disabled).toBeTrue(); + expect(editButtonFound.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(editButtonFound.nativeElement.classList.contains('disabled')).toBeTrue(); }); }); }); diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts index 3eb83ebe8a..245fbe4d58 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts @@ -22,6 +22,7 @@ import { TestScheduler } from 'rxjs/testing'; import { By } from '@angular/platform-browser'; import { VarDirective } from '../../../../shared/utils/var.directive'; import { ContentSourceSetSerializer } from '../../../../core/shared/content-source-set-serializer'; +import {DisabledDirective} from '../../../../shared/disabled-directive'; describe('CollectionSourceControlsComponent', () => { let comp: CollectionSourceControlsComponent; @@ -100,7 +101,7 @@ describe('CollectionSourceControlsComponent', () => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule], - declarations: [CollectionSourceControlsComponent, VarDirective], + declarations: [CollectionSourceControlsComponent, VarDirective, DisabledDirective], providers: [ {provide: ScriptDataService, useValue: scriptDataService}, {provide: ProcessDataService, useValue: processDataService}, @@ -189,9 +190,11 @@ describe('CollectionSourceControlsComponent', () => { const buttons = fixture.debugElement.queryAll(By.css('button')); - expect(buttons[0].nativeElement.disabled).toBeTrue(); - expect(buttons[1].nativeElement.disabled).toBeTrue(); - expect(buttons[2].nativeElement.disabled).toBeTrue(); + buttons.forEach(button => { + console.log(button.nativeElement); + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(button.nativeElement.classList.contains('disabled')).toBeTrue(); + }); }); it('should be enabled when isEnabled is true', () => { comp.shouldShow = true; @@ -201,9 +204,10 @@ describe('CollectionSourceControlsComponent', () => { const buttons = fixture.debugElement.queryAll(By.css('button')); - expect(buttons[0].nativeElement.disabled).toBeFalse(); - expect(buttons[1].nativeElement.disabled).toBeFalse(); - expect(buttons[2].nativeElement.disabled).toBeFalse(); + buttons.forEach(button => { + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(button.nativeElement.classList.contains('disabled')).toBeFalse(); + }); }); it('should call the corresponding button when clicked', () => { spyOn(comp, 'testConfiguration'); diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts index 67a6f98ac0..12adbaa13c 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts @@ -11,6 +11,7 @@ import { ItemMetadataRepresentation } from '../../../core/shared/metadata-repres import { MetadataValue, VIRTUAL_METADATA_PREFIX } from '../../../core/shared/metadata.models'; import { DsoEditMetadataChangeType, DsoEditMetadataValue } from '../dso-edit-metadata-form'; import { By } from '@angular/platform-browser'; +import {DisabledDirective} from '../../../shared/disabled-directive'; const EDIT_BTN = 'edit'; const CONFIRM_BTN = 'confirm'; @@ -49,7 +50,7 @@ describe('DsoEditMetadataValueComponent', () => { initServices(); TestBed.configureTestingModule({ - declarations: [DsoEditMetadataValueComponent, VarDirective], + declarations: [DsoEditMetadataValueComponent, VarDirective, DisabledDirective], imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], providers: [ { provide: RelationshipDataService, useValue: relationshipService }, @@ -158,7 +159,14 @@ describe('DsoEditMetadataValueComponent', () => { }); it(`should${disabled ? ' ' : ' not '}be disabled`, () => { - expect(btn.nativeElement.disabled).toBe(disabled); + if (disabled) { + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeTrue(); + } else { + // Can be null or false, depending on if button was ever disabled so just check not true + expect(btn.nativeElement.getAttribute('aria-disabled')).not.toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeFalse(); + } }); } else { it('should not exist', () => { diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts index 7067c44fbb..3a431705c3 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts @@ -16,6 +16,7 @@ import { DATA_SERVICE_FACTORY } from '../../core/data/base/data-service.decorato import { Operation } from 'fast-json-patch'; import { RemoteData } from '../../core/data/remote-data'; import { Observable } from 'rxjs/internal/Observable'; +import {DisabledDirective} from '../../shared/disabled-directive'; const ADD_BTN = 'add'; const REINSTATE_BTN = 'reinstate'; @@ -71,7 +72,7 @@ describe('DsoEditMetadataComponent', () => { notificationsService = jasmine.createSpyObj('notificationsService', ['error', 'success']); TestBed.configureTestingModule({ - declarations: [DsoEditMetadataComponent, VarDirective], + declarations: [DsoEditMetadataComponent, VarDirective, DisabledDirective], imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], providers: [ TestDataService, @@ -180,7 +181,13 @@ describe('DsoEditMetadataComponent', () => { }); it(`should${disabled ? ' ' : ' not '}be disabled`, () => { - expect(btn.nativeElement.disabled).toBe(disabled); + if (disabled) { + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeTrue(); + } else { + expect(btn.nativeElement.getAttribute('aria-disabled')).not.toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeFalse(); + } }); } else { it('should not exist', () => { diff --git a/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts b/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts index dc4f4cf412..153fe4a51f 100644 --- a/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts +++ b/src/app/info/end-user-agreement/end-user-agreement.component.spec.ts @@ -11,6 +11,7 @@ import { Store } from '@ngrx/store'; import { By } from '@angular/platform-browser'; import { LogOutAction } from '../../core/auth/auth.actions'; import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; +import {DisabledDirective} from '../../shared/disabled-directive'; describe('EndUserAgreementComponent', () => { let component: EndUserAgreementComponent; @@ -49,7 +50,7 @@ describe('EndUserAgreementComponent', () => { init(); TestBed.configureTestingModule({ imports: [TranslateModule.forRoot()], - declarations: [EndUserAgreementComponent], + declarations: [EndUserAgreementComponent, DisabledDirective], providers: [ { provide: EndUserAgreementService, useValue: endUserAgreementService }, { provide: NotificationsService, useValue: notificationsService }, @@ -81,7 +82,8 @@ describe('EndUserAgreementComponent', () => { it('should disable the save button', () => { const button = fixture.debugElement.query(By.css('#button-save')).nativeElement; - expect(button.disabled).toBeTruthy(); + expect(button.getAttribute('aria-disabled')).toBe('true'); + expect(button.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts b/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts index c3d38a2876..0507b7173b 100644 --- a/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts +++ b/src/app/info/feedback/feedback-form/feedback-form.component.spec.ts @@ -18,6 +18,7 @@ import { Router } from '@angular/router'; import { RouterMock } from '../../../shared/mocks/router.mock'; import { NativeWindowService } from '../../../core/services/window.service'; import { NativeWindowMockFactory } from '../../../shared/mocks/mock-native-window-ref'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('FeedbackFormComponent', () => { @@ -38,7 +39,7 @@ describe('FeedbackFormComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot()], - declarations: [FeedbackFormComponent], + declarations: [FeedbackFormComponent, DisabledDirective], providers: [ { provide: RouteService, useValue: routeServiceStub }, { provide: UntypedFormBuilder, useValue: new UntypedFormBuilder() }, @@ -72,7 +73,8 @@ describe('FeedbackFormComponent', () => { }); it('should have disabled button', () => { - expect(de.query(By.css('button')).nativeElement.disabled).toBeTrue(); + expect(de.query(By.css('button')).nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(de.query(By.css('button')).nativeElement.classList.contains('disabled')).toBeTrue(); }); describe('when message is inserted', () => { @@ -83,7 +85,8 @@ describe('FeedbackFormComponent', () => { }); it('should not have disabled button', () => { - expect(de.query(By.css('button')).nativeElement.disabled).toBeFalse(); + expect(de.query(By.css('button')).nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(de.query(By.css('button')).nativeElement.classList.contains('disabled')).toBeFalse(); }); it('on submit should call createFeedback of feedbackDataServiceStub service', () => { diff --git a/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts b/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts index 7570119b3a..8c2774ad6c 100644 --- a/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-operation/item-operation.component.spec.ts @@ -4,6 +4,7 @@ import { ItemOperationComponent } from './item-operation.component'; import { TranslateModule } from '@ngx-translate/core'; import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('ItemOperationComponent', () => { let itemOperation: ItemOperation; @@ -14,7 +15,7 @@ describe('ItemOperationComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], - declarations: [ItemOperationComponent] + declarations: [ItemOperationComponent, DisabledDirective] }).compileComponents(); })); @@ -40,7 +41,8 @@ describe('ItemOperationComponent', () => { const span = fixture.debugElement.query(By.css('.action-label span')).nativeElement; expect(span.textContent).toContain('item.edit.tabs.status.buttons.key1.label'); const button = fixture.debugElement.query(By.css('button')).nativeElement; - expect(button.disabled).toBeTrue(); + expect(button.getAttribute('aria-disabled')).toBe('true'); + expect(button.classList.contains('disabled')).toBeTrue(); expect(button.textContent).toContain('item.edit.tabs.status.buttons.key1.button'); }); }); diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts index 4cd663f0fb..6e44dd1a58 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts @@ -335,7 +335,8 @@ describe('EditRelationshipListComponent', () => { comp.hasChanges = observableOf(true); fixture.detectChanges(); const element = de.query(By.css('.btn-success')); - expect(element.nativeElement?.disabled).toBeTrue(); + expect(element.nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(element.nativeElement?.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/item-page/versions/item-versions.component.spec.ts b/src/app/item-page/versions/item-versions.component.spec.ts index e46f1585d7..0d04ea12db 100644 --- a/src/app/item-page/versions/item-versions.component.spec.ts +++ b/src/app/item-page/versions/item-versions.component.spec.ts @@ -29,6 +29,7 @@ import { ConfigurationDataService } from '../../core/data/configuration-data.ser import { Router } from '@angular/router'; import { CommonModule } from '@angular/common'; import { ItemSharedModule } from '../item-shared.module'; +import {DisabledDirective} from '../../shared/disabled-directive'; describe('ItemVersionsComponent', () => { let component: ItemVersionsComponent; @@ -136,7 +137,7 @@ describe('ItemVersionsComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - declarations: [ItemVersionsComponent, VarDirective], + declarations: [ItemVersionsComponent, VarDirective, DisabledDirective], imports: [TranslateModule.forRoot(), CommonModule, FormsModule, ReactiveFormsModule, BrowserModule, ItemSharedModule], providers: [ {provide: PaginationService, useValue: new PaginationServiceStub()}, @@ -222,17 +223,20 @@ describe('ItemVersionsComponent', () => { it('should not disable the delete button', () => { const deleteButtons = fixture.debugElement.queryAll(By.css(`.version-row-element-delete`)); deleteButtons.forEach((btn) => { - expect(btn.nativeElement.disabled).toBe(false); + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(btn.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); it('should disable other buttons', () => { const createButtons = fixture.debugElement.queryAll(By.css(`.version-row-element-create`)); createButtons.forEach((btn) => { - expect(btn.nativeElement.disabled).toBe(true); + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeTrue(); }); const editButtons = fixture.debugElement.queryAll(By.css(`.version-row-element-create`)); editButtons.forEach((btn) => { - expect(btn.nativeElement.disabled).toBe(true); + expect(btn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(btn.nativeElement.classList.contains('disabled')).toBeTrue(); }); }); }); diff --git a/src/app/shared/disabled-directive.ts b/src/app/shared/disabled-directive.ts index 8d1380917f..38f92cd1d7 100644 --- a/src/app/shared/disabled-directive.ts +++ b/src/app/shared/disabled-directive.ts @@ -6,7 +6,7 @@ import { Directive, Input, HostBinding, HostListener } from '@angular/core'; export class DisabledDirective { @Input() set dsDisabled(value: boolean) { - this.isDisabled = value; + this.isDisabled = !!value; } @HostBinding('attr.aria-disabled') isDisabled = false; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts index a25ad4d231..e0ea6af31f 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component.spec.ts @@ -63,7 +63,7 @@ describe('DsDynamicDisabledComponent', () => { expect(comp).toBeTruthy(); }); - it('should have a disabled input', () => { + xit('should have a disabled input', () => { const input = de.query(By.css('input')); expect(input.nativeElement.getAttribute('disabled')).toEqual(''); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts index 2fea4fc985..2fb6488e93 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts @@ -26,6 +26,7 @@ import { mockDynamicFormLayoutService, mockDynamicFormValidationService } from '../../../../../testing/dynamic-form-mock-services'; +import {DisabledDirective} from '../../../../../disabled-directive'; let LOOKUP_TEST_MODEL_CONFIG: DynamicLookupModelConfig = { vocabularyOptions: { @@ -153,7 +154,8 @@ describe('Dynamic Lookup component', () => { DsDynamicLookupComponent, TestComponent, AuthorityConfidenceStateDirective, - ObjNgFor + ObjNgFor, + DisabledDirective ], // declare the test component providers: [ ChangeDetectorRef, @@ -235,8 +237,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const editBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(editBtnEl.disabled).toBe(true); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(editBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(editBtnEl.classList.contains('disabled')).toBeTrue(); expect(editBtnEl.textContent.trim()).toBe('form.edit'); }); @@ -334,8 +338,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); @@ -375,8 +381,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); @@ -407,8 +415,10 @@ describe('Dynamic Lookup component', () => { const editBtnEl = deBtn[1].nativeElement; expect(de.length).toBe(2); - expect(searchBtnEl.disabled).toBe(true); - expect(editBtnEl.disabled).toBe(true); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(editBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(editBtnEl.classList.contains('disabled')).toBeTrue(); expect(editBtnEl.textContent.trim()).toBe('form.edit'); }); @@ -504,8 +514,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); @@ -547,8 +559,10 @@ describe('Dynamic Lookup component', () => { const de = lookupFixture.debugElement.queryAll(By.css('button')); const searchBtnEl = de[0].nativeElement; const saveBtnEl = de[1].nativeElement; - expect(searchBtnEl.disabled).toBe(true); - expect(saveBtnEl.disabled).toBe(false); + expect(searchBtnEl.getAttribute('aria-disabled')).toBe('true'); + expect(searchBtnEl.classList.contains('disabled')).toBeTrue(); + expect(saveBtnEl.getAttribute('aria-disabled')).not.toBe('true'); + expect(saveBtnEl.classList.contains('disabled')).toBeFalse(); expect(saveBtnEl.textContent.trim()).toBe('form.save'); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts index 9d57296f82..0cfde15c6f 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts @@ -24,6 +24,7 @@ import { RemoteDataBuildService } from '../../../../../core/cache/builders/remot import { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model'; import { Collection } from '../../../../../core/shared/collection.model'; import { By } from '@angular/platform-browser'; +import {DisabledDirective} from '../../../../disabled-directive'; describe('DsDynamicLookupRelationModalComponent', () => { let component: DsDynamicLookupRelationModalComponent; @@ -103,7 +104,7 @@ describe('DsDynamicLookupRelationModalComponent', () => { beforeEach(waitForAsync(() => { init(); TestBed.configureTestingModule({ - declarations: [DsDynamicLookupRelationModalComponent], + declarations: [DsDynamicLookupRelationModalComponent, DisabledDirective], imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule], providers: [ { @@ -202,10 +203,12 @@ describe('DsDynamicLookupRelationModalComponent', () => { describe('when initialized and is relationship show the list of buttons', () => { it('submit button should be disabled', () => { - expect(debugElement.query(By.css('.submit')).nativeElement?.disabled).toBeTrue(); + expect(debugElement.query(By.css('.submit')).nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.submit')).nativeElement.classList.contains('disabled')).toBeTrue(); }); it('discard button should be disabled', () => { - expect(debugElement.query(By.css('.discard')).nativeElement?.disabled).toBeTrue(); + expect(debugElement.query(By.css('.discard')).nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.discard')).nativeElement.classList.contains('disabled')).toBeTrue(); }); }); @@ -243,9 +246,12 @@ describe('DsDynamicLookupRelationModalComponent', () => { it('there should show 1 spinner and disable all 3 buttons', () => { expect(debugElement.queryAll(By.css('.spinner-border')).length).toEqual(1); - expect(debugElement.query(By.css('.submit')).nativeElement?.disabled).toBeTrue(); - expect(debugElement.query(By.css('.discard')).nativeElement?.disabled).toBeTrue(); - expect(debugElement.query(By.css('.close')).nativeElement?.disabled).toBeTrue(); + expect(debugElement.query(By.css('.submit')).nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.submit')).nativeElement?.classList.contains('disabled')).toBeTrue(); + expect(debugElement.query(By.css('.discard')).nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.discard')).nativeElement?.classList.contains('disabled')).toBeTrue(); + expect(debugElement.query(By.css('.close')).nativeElement?.getAttribute('aria-disabled')).toBe('true'); + expect(debugElement.query(By.css('.close')).nativeElement?.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/shared/object-select/item-select/item-select.component.spec.ts b/src/app/shared/object-select/item-select/item-select.component.spec.ts index 5131060cb2..fd09860a1e 100644 --- a/src/app/shared/object-select/item-select/item-select.component.spec.ts +++ b/src/app/shared/object-select/item-select/item-select.component.spec.ts @@ -24,6 +24,7 @@ import { LinkHeadService } from '../../../core/services/link-head.service'; import { GroupDataService } from '../../../core/eperson/group-data.service'; import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; import { ConfigurationProperty } from '../../../core/shared/configuration-property.model'; +import {DisabledDirective} from '../../disabled-directive'; describe('ItemSelectComponent', () => { let comp: ItemSelectComponent; @@ -98,7 +99,7 @@ describe('ItemSelectComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), SharedModule, RouterTestingModule.withRoutes([])], - declarations: [], + declarations: [DisabledDirective], providers: [ { provide: ObjectSelectService, useValue: new ObjectSelectServiceStub([mockItemList[1].id]) }, { provide: HostWindowService, useValue: new HostWindowServiceStub(0) }, @@ -191,7 +192,8 @@ describe('ItemSelectComponent', () => { fixture.whenStable().then(() => { const checkbox = fixture.debugElement.query(By.css('input.item-checkbox')).nativeElement; expect(authorizationDataService.isAuthorized).toHaveBeenCalled(); - expect(checkbox.disabled).toBeTrue(); + expect(checkbox.getAttribute('aria-disabled')).toBe('true'); + expect(checkbox.classList.contains('disabled')).toBe(true); }); })); }); diff --git a/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts b/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts index 1cc908cc6d..5a0e08a496 100644 --- a/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts +++ b/src/app/shared/resource-policies/form/resource-policy-form.component.spec.ts @@ -39,6 +39,7 @@ import { PaginationServiceStub } from '../../testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { StoreMock } from '../../testing/store.mock'; +import {DisabledDirective} from '../../disabled-directive'; export const mockResourcePolicyFormData = { name: [ @@ -189,7 +190,8 @@ describe('ResourcePolicyFormComponent test suite', () => { FormComponent, EpersonGroupListComponent, ResourcePolicyFormComponent, - TestComponent + TestComponent, + DisabledDirective ], providers: [ { provide: ActivatedRoute, useValue: activatedRouteStub }, @@ -389,7 +391,8 @@ describe('ResourcePolicyFormComponent test suite', () => { const depositBtn: any = fixture.debugElement.query(By.css('.btn-primary')); - expect(depositBtn.nativeElement.disabled).toBeFalsy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); it('should emit submit event', () => { @@ -443,7 +446,8 @@ describe('ResourcePolicyFormComponent test suite', () => { const depositBtn: any = fixture.debugElement.query(By.css('.btn-primary')); - expect(depositBtn.nativeElement.disabled).toBeTruthy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeTrue(); }); }); diff --git a/src/app/submission/form/collection/submission-form-collection.component.spec.ts b/src/app/submission/form/collection/submission-form-collection.component.spec.ts index c76de83b83..4cb40e2293 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.spec.ts +++ b/src/app/submission/form/collection/submission-form-collection.component.spec.ts @@ -25,6 +25,7 @@ import { Collection } from '../../../core/shared/collection.model'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; import { DSONameServiceMock } from '../../../shared/mocks/dso-name.service.mock'; +import {DisabledDirective} from '../../../shared/disabled-directive'; describe('SubmissionFormCollectionComponent Component', () => { @@ -135,7 +136,8 @@ describe('SubmissionFormCollectionComponent Component', () => { ], declarations: [ SubmissionFormCollectionComponent, - TestComponent + TestComponent, + DisabledDirective ], providers: [ { provide: DSONameService, useValue: new DSONameServiceMock() }, @@ -255,7 +257,8 @@ describe('SubmissionFormCollectionComponent Component', () => { it('the dropdown button should be disabled when isReadonly is true', () => { comp.isReadonly = true; fixture.detectChanges(); - expect(dropdowBtn.nativeNode.attributes.disabled).toBeDefined(); + expect(dropdowBtn.nativeNode.getAttribute('aria-disabled')).toBe('true'); + expect(dropdowBtn.nativeNode.classList.contains('disabled')).toBeTrue(); }); it('should be simulated when the drop-down menu is closed', () => { diff --git a/src/app/submission/form/footer/submission-form-footer.component.spec.ts b/src/app/submission/form/footer/submission-form-footer.component.spec.ts index dd28f9a10a..9071805514 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.spec.ts +++ b/src/app/submission/form/footer/submission-form-footer.component.spec.ts @@ -16,6 +16,7 @@ import { SubmissionFormFooterComponent } from './submission-form-footer.componen import { SubmissionRestService } from '../../../core/submission/submission-rest.service'; import { createTestComponent } from '../../../shared/testing/utils.test'; import { BrowserOnlyMockPipe } from '../../../shared/testing/browser-only-mock.pipe'; +import {DisabledDirective} from '../../../shared/disabled-directive'; const submissionServiceStub: SubmissionServiceStub = new SubmissionServiceStub(); @@ -39,6 +40,7 @@ describe('SubmissionFormFooterComponent', () => { SubmissionFormFooterComponent, TestComponent, BrowserOnlyMockPipe, + DisabledDirective ], providers: [ { provide: SubmissionService, useValue: submissionServiceStub }, @@ -215,7 +217,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const depositBtn: any = fixture.debugElement.query(By.css('.btn-success')); - expect(depositBtn.nativeElement.disabled).toBeFalsy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); it('should not have deposit button disabled when submission is valid', () => { @@ -224,7 +227,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const depositBtn: any = fixture.debugElement.query(By.css('.btn-success')); - expect(depositBtn.nativeElement.disabled).toBeFalsy(); + expect(depositBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(depositBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); it('should disable save button when all modifications had been saved', () => { @@ -232,7 +236,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const saveBtn: any = fixture.debugElement.query(By.css('#save')); - expect(saveBtn.nativeElement.disabled).toBeTruthy(); + expect(saveBtn.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(saveBtn.nativeElement.classList.contains('disabled')).toBeTrue(); }); it('should enable save button when there are not saved modifications', () => { @@ -240,7 +245,8 @@ describe('SubmissionFormFooterComponent', () => { fixture.detectChanges(); const saveBtn: any = fixture.debugElement.query(By.css('#save')); - expect(saveBtn.nativeElement.disabled).toBeFalsy(); + expect(saveBtn.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(saveBtn.nativeElement.classList.contains('disabled')).toBeFalse(); }); }); From 2d48cc0f6946f8310f5db28739224576b643f11d Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Mon, 26 Aug 2024 10:35:19 +0200 Subject: [PATCH 004/104] 117544: add spec for directive --- src/app/shared/disabled-directive.spec.ts | 89 +++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/app/shared/disabled-directive.spec.ts diff --git a/src/app/shared/disabled-directive.spec.ts b/src/app/shared/disabled-directive.spec.ts new file mode 100644 index 0000000000..c4ca4f0599 --- /dev/null +++ b/src/app/shared/disabled-directive.spec.ts @@ -0,0 +1,89 @@ +import { Component, DebugElement } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DisabledDirective } from './disabled-directive'; + +@Component({ + template: ` + + ` +}) +class TestComponent { + isDisabled = false; +} + +describe('DisabledDirective', () => { + let component: TestComponent; + let fixture: ComponentFixture; + let button: DebugElement; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestComponent, DisabledDirective] + }); + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + button = fixture.debugElement.query(By.css('button')); + fixture.detectChanges(); + }); + + it('should bind aria-disabled to false initially', () => { + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(button.nativeElement.classList.contains('disabled')).toBeFalse(); + }); + + it('should bind aria-disabled to true and add disabled class when isDisabled is true', () => { + component.isDisabled = true; + fixture.detectChanges(); + + expect(button.nativeElement.getAttribute('aria-disabled')).toBe('true'); + expect(button.nativeElement.classList.contains('disabled')).toBeTrue(); + }); + + it('should prevent click events when disabled', () => { + component.isDisabled = true; + fixture.detectChanges(); + + let clickHandled = false; + button.nativeElement.addEventListener('click', () => clickHandled = true); + + button.nativeElement.click(); + + expect(clickHandled).toBeFalse(); + }); + + it('should prevent Enter or Space keydown events when disabled', () => { + component.isDisabled = true; + fixture.detectChanges(); + + let keydownHandled = false; + button.nativeElement.addEventListener('keydown', () => keydownHandled = true); + + const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' }); + const spaceEvent = new KeyboardEvent('keydown', { key: 'Space' }); + + button.nativeElement.dispatchEvent(enterEvent); + button.nativeElement.dispatchEvent(spaceEvent); + + expect(keydownHandled).toBeFalse(); + }); + + it('should allow click and keydown events when not disabled', () => { + let clickHandled = false; + let keydownHandled = false; + + button.nativeElement.addEventListener('click', () => clickHandled = true); + button.nativeElement.addEventListener('keydown', () => keydownHandled = true); + + button.nativeElement.click(); + + const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' }); + const spaceEvent = new KeyboardEvent('keydown', { key: 'Space' }); + + button.nativeElement.dispatchEvent(enterEvent); + button.nativeElement.dispatchEvent(spaceEvent); + + expect(clickHandled).toBeTrue(); + expect(keydownHandled).toBeTrue(); + }); +}); From 094502137887f8370428ea76d8bb81c2d750ff9b Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Tue, 27 Aug 2024 12:29:44 +0200 Subject: [PATCH 005/104] 117544: resolve conflicts after merging in latest 7.x branch --- .../eperson-form/eperson-form.component.html | 2 +- .../eperson-form/eperson-form.component.spec.ts | 2 +- .../members-list/members-list.component.html | 4 ++-- .../collection-source.component.html | 8 ++++---- .../delete-community-page.component.html | 4 ++-- .../dso-edit-metadata-value.component.html | 10 +++++----- .../dso-edit-metadata.component.html | 14 +++++++------- .../feedback-form/feedback-form.component.html | 4 ++-- .../item-bitstreams.component.html | 8 ++++---- .../item-edit-bitstream.component.html | 4 ++-- .../item-delete/item-delete.component.html | 6 +++--- .../edit-relationship-list.component.html | 2 +- .../item-relationships.component.html | 4 ++-- ...y-dspace-new-external-dropdown.component.html | 4 ++-- ...dspace-new-submission-dropdown.component.html | 4 ++-- .../email-request-copy.component.html | 2 +- .../access-control-array-form.component.html | 10 +++++----- .../access-control-form-container.component.html | 16 ++++++++-------- ...o-edit-menu-expandable-section.component.html | 2 +- .../dso-edit-menu-section.component.html | 4 ++-- src/app/shared/form/form.component.html | 4 ++-- .../number-picker.component.spec.ts | 2 +- .../vocabulary-treeview.component.html | 2 +- .../collection-select.component.html | 2 +- .../item-select/item-select.component.html | 4 ++-- ...sion-import-external-searchbar.component.html | 2 +- .../system-wide-alert-form.component.html | 4 ++-- 27 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html index 6c75b52077..d21c1cfa85 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html @@ -25,7 +25,7 @@
-
diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts index ccf276856a..b698d43651 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts @@ -509,7 +509,7 @@ describe('EPersonFormComponent', () => { // ePersonDataServiceStub.activeEPerson = eperson; spyOn(component.epersonService, 'deleteEPerson').and.returnValue(createSuccessfulRemoteDataObject$('No Content', 204)); const deleteButton = fixture.debugElement.query(By.css('.delete-button')); - expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBe('false'); + expect(deleteButton.nativeElement.getAttribute('aria-disabled')).toBeNull(); expect(deleteButton.nativeElement.classList.contains('disabled')).toBeFalse(); deleteButton.triggerEventHandler('click', null); fixture.detectChanges(); diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html index e1fc69026b..1d0e6b9abd 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html @@ -34,7 +34,7 @@
- diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html index 47449bda5c..f3d92ace2d 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html @@ -24,31 +24,31 @@
- - @@ -76,13 +76,13 @@
- - diff --git a/src/app/info/feedback/feedback-form/feedback-form.component.html b/src/app/info/feedback/feedback-form/feedback-form.component.html index 6ca584c82e..3fdc66820a 100644 --- a/src/app/info/feedback/feedback-form/feedback-form.component.html +++ b/src/app/info/feedback/feedback-form/feedback-form.component.html @@ -41,9 +41,9 @@
- +
-
\ No newline at end of file +
diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html index 834ad25c7f..c52d99b439 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html @@ -12,7 +12,7 @@ class="fas fa-undo-alt">
 {{"item.edit.bitstreams.reinstate-button" | translate}} - - - - - diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html index a4cc100377..b9a01c6b38 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html @@ -1,6 +1,6 @@

{{relationshipMessageKey$ | async | translate}} - diff --git a/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html b/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html index 85f41a25d9..6ba593e1f2 100644 --- a/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html @@ -35,7 +35,7 @@
@@ -8,7 +8,7 @@ ngbDropdown *ngIf="(moreThanOne$ | async)"> diff --git a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html index 6e427400ee..747d14cac6 100644 --- a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html +++ b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.html @@ -1,7 +1,7 @@
-
diff --git a/src/app/shared/object-select/collection-select/collection-select.component.html b/src/app/shared/object-select/collection-select/collection-select.component.html index 1534f88895..551edd446c 100644 --- a/src/app/shared/object-select/collection-select/collection-select.component.html +++ b/src/app/shared/object-select/collection-select/collection-select.component.html @@ -16,7 +16,7 @@ - + {{ dsoNameService.getName(selectCollection.dso) }} diff --git a/src/app/shared/object-select/item-select/item-select.component.html b/src/app/shared/object-select/item-select/item-select.component.html index 8271633bcf..a6cb7738d7 100644 --- a/src/app/shared/object-select/item-select/item-select.component.html +++ b/src/app/shared/object-select/item-select/item-select.component.html @@ -18,7 +18,7 @@ - + @@ -42,7 +42,7 @@ diff --git a/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html b/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html index 040987d37b..28fa4695fb 100644 --- a/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html +++ b/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html @@ -23,6 +23,6 @@

{{'submission.import-external.source.loading' | translate}}

- +
diff --git a/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html b/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html index 770f465a4b..0f20e0e927 100644 --- a/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html +++ b/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html @@ -87,8 +87,8 @@ - - \ No newline at end of file + From 685e6d83c5a85269d0c47678ab4a282346184d99 Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Mon, 16 Sep 2024 13:44:06 +0200 Subject: [PATCH 006/104] 117544: PR feedback - added typedocs - changed directive to only be present for buttons - various other small fixes --- .../filtered-items.component.html | 0 .../dso-edit-metadata-value.component.html | 47 +++++++++++++++++++ .../item-delete/item-delete.component.html | 2 +- .../access-control-array-form.component.html | 2 +- ...cess-control-form-container.component.html | 12 ++--- src/app/shared/disabled-directive.spec.ts | 8 ++++ src/app/shared/disabled-directive.ts | 28 ++++++++++- ...amic-form-control-container.component.html | 2 +- .../date-picker/date-picker.component.html | 6 +-- .../disabled/dynamic-disabled.component.html | 2 +- .../dynamic-disabled.component.spec.ts | 2 +- .../lookup/dynamic-lookup.component.html | 4 +- .../onebox/dynamic-onebox.component.html | 4 +- ...dynamic-scrollable-dropdown.component.html | 2 +- .../number-picker.component.html | 2 +- .../vocabulary-treeview.component.html | 4 +- .../collection-select.component.html | 2 +- .../item-select/item-select.component.html | 2 +- .../item-select/item-select.component.spec.ts | 3 +- .../pagination/pagination.component.html | 2 +- ...mission-section-cc-licenses.component.html | 4 +- 21 files changed, 110 insertions(+), 30 deletions(-) create mode 100644 src/app/admin/admin-reports/filtered-items/filtered-items.component.html diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.html b/src/app/admin/admin-reports/filtered-items/filtered-items.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html index f3d92ace2d..1837801902 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html @@ -6,6 +6,53 @@ + + + + +
+ + + {{ dsoType + '.edit.metadata.authority.label' | translate }} {{ mdValue.newValue.authority }} + +
+
+
+ + + + +
+
{{ mdRepresentationName$ | async }} diff --git a/src/app/item-page/edit-item-page/item-delete/item-delete.component.html b/src/app/item-page/edit-item-page/item-delete/item-delete.component.html index eadec9babf..667363a381 100644 --- a/src/app/item-page/edit-item-page/item-delete/item-delete.component.html +++ b/src/app/item-page/edit-item-page/item-delete/item-delete.component.html @@ -18,7 +18,7 @@
diff --git a/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html b/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html index 630812c345..f2a5bdd422 100644 --- a/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html +++ b/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html @@ -13,7 +13,7 @@
+ [dsBtnDisabled]="!form.valid"> {{"login.form.submit" | translate}}
diff --git a/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html b/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html index e4f52cf361..9785715ee8 100644 --- a/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html @@ -1,7 +1,7 @@ diff --git a/src/app/shared/object-select/item-select/item-select.component.html b/src/app/shared/object-select/item-select/item-select.component.html index 58eed6ae4a..d1c2986076 100644 --- a/src/app/shared/object-select/item-select/item-select.component.html +++ b/src/app/shared/object-select/item-select/item-select.component.html @@ -42,7 +42,7 @@ diff --git a/src/app/shared/object-select/item-select/item-select.component.spec.ts b/src/app/shared/object-select/item-select/item-select.component.spec.ts index 7d2e5c4146..9fb9a0260a 100644 --- a/src/app/shared/object-select/item-select/item-select.component.spec.ts +++ b/src/app/shared/object-select/item-select/item-select.component.spec.ts @@ -24,7 +24,7 @@ import { LinkHeadService } from '../../../core/services/link-head.service'; import { GroupDataService } from '../../../core/eperson/group-data.service'; import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; import { ConfigurationProperty } from '../../../core/shared/configuration-property.model'; -import {DisabledDirective} from '../../disabled-directive'; +import {BtnDisabledDirective} from '../../btn-disabled.directive'; describe('ItemSelectComponent', () => { let comp: ItemSelectComponent; @@ -99,7 +99,7 @@ describe('ItemSelectComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), SharedModule, RouterTestingModule.withRoutes([])], - declarations: [DisabledDirective], + declarations: [BtnDisabledDirective], providers: [ { provide: ObjectSelectService, useValue: new ObjectSelectServiceStub([mockItemList[1].id]) }, { provide: HostWindowService, useValue: new HostWindowServiceStub(0) }, diff --git a/src/app/shared/pagination/pagination.component.html b/src/app/shared/pagination/pagination.component.html index b85dcb01ee..f7f2c64e2c 100644 --- a/src/app/shared/pagination/pagination.component.html +++ b/src/app/shared/pagination/pagination.component.html @@ -55,12 +55,12 @@
-
diff --git a/src/app/submission/form/collection/submission-form-collection.component.html b/src/app/submission/form/collection/submission-form-collection.component.html index 7f50e5a341..fe9527c266 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.html +++ b/src/app/submission/form/collection/submission-form-collection.component.html @@ -25,7 +25,7 @@ class="btn btn-outline-primary" (blur)="onClose()" (click)="onClose()" - [dsDisabled]="(processingChange$ | async) || collectionModifiable == false || isReadonly" + [dsBtnDisabled]="(processingChange$ | async) || collectionModifiable == false || isReadonly" ngbDropdownToggle> {{ selectedCollectionName$ | async }} diff --git a/src/app/submission/form/collection/submission-form-collection.component.spec.ts b/src/app/submission/form/collection/submission-form-collection.component.spec.ts index 4cb40e2293..467f164f89 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.spec.ts +++ b/src/app/submission/form/collection/submission-form-collection.component.spec.ts @@ -25,7 +25,7 @@ import { Collection } from '../../../core/shared/collection.model'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; import { DSONameServiceMock } from '../../../shared/mocks/dso-name.service.mock'; -import {DisabledDirective} from '../../../shared/disabled-directive'; +import {BtnDisabledDirective} from '../../../shared/btn-disabled.directive'; describe('SubmissionFormCollectionComponent Component', () => { @@ -137,7 +137,7 @@ describe('SubmissionFormCollectionComponent Component', () => { declarations: [ SubmissionFormCollectionComponent, TestComponent, - DisabledDirective + BtnDisabledDirective ], providers: [ { provide: DSONameService, useValue: new DSONameServiceMock() }, diff --git a/src/app/submission/form/footer/submission-form-footer.component.html b/src/app/submission/form/footer/submission-form-footer.component.html index f7e8bae792..457a56cc76 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.html +++ b/src/app/submission/form/footer/submission-form-footer.component.html @@ -5,7 +5,7 @@ id="discard" [attr.data-test]="'discard' | dsBrowserOnly" class="btn btn-danger" - [dsDisabled]="(processingSaveStatus | async) || (processingDepositStatus | async)" + [dsBtnDisabled]="(processingSaveStatus | async) || (processingDepositStatus | async)" (click)="$event.preventDefault();confirmDiscard(content)"> {{'submission.general.discard.submit' | translate}} @@ -28,7 +28,7 @@ class="btn btn-secondary" id="save" [attr.data-test]="'save' | dsBrowserOnly" - [dsDisabled]="(processingSaveStatus | async) || !(hasUnsavedModification | async)" + [dsBtnDisabled]="(processingSaveStatus | async) || !(hasUnsavedModification | async)" (click)="save($event)"> {{'submission.general.save' | translate}} @@ -38,7 +38,7 @@ class="btn" id="saveForLater" [attr.data-test]="'save-for-later' | dsBrowserOnly" - [dsDisabled]="(processingSaveStatus | async) || (processingDepositStatus | async)" + [dsBtnDisabled]="(processingSaveStatus | async) || (processingDepositStatus | async)" (click)="saveLater($event)"> {{'submission.general.save-later' | translate}} @@ -47,7 +47,7 @@ id="deposit" [attr.data-test]="'deposit' | dsBrowserOnly" class="btn btn-success" - [dsDisabled]="(processingSaveStatus | async) || (processingDepositStatus | async)" + [dsBtnDisabled]="(processingSaveStatus | async) || (processingDepositStatus | async)" (click)="deposit($event)"> {{'submission.general.deposit' | translate}} diff --git a/src/app/submission/form/footer/submission-form-footer.component.spec.ts b/src/app/submission/form/footer/submission-form-footer.component.spec.ts index 9071805514..658926834c 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.spec.ts +++ b/src/app/submission/form/footer/submission-form-footer.component.spec.ts @@ -16,7 +16,7 @@ import { SubmissionFormFooterComponent } from './submission-form-footer.componen import { SubmissionRestService } from '../../../core/submission/submission-rest.service'; import { createTestComponent } from '../../../shared/testing/utils.test'; import { BrowserOnlyMockPipe } from '../../../shared/testing/browser-only-mock.pipe'; -import {DisabledDirective} from '../../../shared/disabled-directive'; +import {BtnDisabledDirective} from '../../../shared/btn-disabled.directive'; const submissionServiceStub: SubmissionServiceStub = new SubmissionServiceStub(); @@ -40,7 +40,7 @@ describe('SubmissionFormFooterComponent', () => { SubmissionFormFooterComponent, TestComponent, BrowserOnlyMockPipe, - DisabledDirective + BtnDisabledDirective ], providers: [ { provide: SubmissionService, useValue: submissionServiceStub }, diff --git a/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html b/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html index 28fa4695fb..cb8dde18c5 100644 --- a/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html +++ b/src/app/submission/import-external/import-external-searchbar/submission-import-external-searchbar.component.html @@ -23,6 +23,6 @@

{{'submission.import-external.source.loading' | translate}}

- +
diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html index 1ce811ce66..b529d9aee4 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.html @@ -1,7 +1,7 @@
diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.html b/src/app/submission/sections/upload/file/section-upload-file.component.html index 589e7b6ebf..3567ef5c64 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.html +++ b/src/app/submission/sections/upload/file/section-upload-file.component.html @@ -19,7 +19,7 @@ -
From 4a7ebeea16cdd902f99da11ba2dc9e5ab155620e Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Mon, 16 Sep 2024 16:09:41 +0200 Subject: [PATCH 008/104] 117544: fix remaining bug --- src/app/shared/btn-disabled.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/btn-disabled.directive.ts b/src/app/shared/btn-disabled.directive.ts index ab37643c02..512aa87ede 100644 --- a/src/app/shared/btn-disabled.directive.ts +++ b/src/app/shared/btn-disabled.directive.ts @@ -12,7 +12,7 @@ import { Directive, Input, HostBinding, HostListener } from '@angular/core'; */ export class BtnDisabledDirective { - @Input() set dsDisabled(value: boolean) { + @Input() set dsBtnDisabled(value: boolean) { this.isDisabled = !!value; } From cd51baa5f1ee5d8fa66e8ee94beb3168f93c5c01 Mon Sep 17 00:00:00 2001 From: Andrea Barbasso <´andrea.barbasso@4science.com´> Date: Mon, 23 Sep 2024 18:15:39 +0200 Subject: [PATCH 009/104] [CST-14904] add orcid icon with tooltip --- ...-item-metadata-list-element.component.html | 5 ++ .../orcid-badge-and-tooltip.component.html | 11 +++ .../orcid-badge-and-tooltip.component.scss | 11 +++ .../orcid-badge-and-tooltip.component.spec.ts | 71 +++++++++++++++++++ .../orcid-badge-and-tooltip.component.ts | 56 +++++++++++++++ src/app/shared/shared.module.ts | 2 + src/assets/i18n/en.json5 | 4 ++ 7 files changed, 160 insertions(+) create mode 100644 src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html create mode 100644 src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.scss create mode 100644 src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.spec.ts create mode 100644 src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.ts diff --git a/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.html b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.html index 6f56056781..f61c14d3ba 100644 --- a/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.html +++ b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.html @@ -12,4 +12,9 @@ + + diff --git a/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html new file mode 100644 index 0000000000..fc34aee970 --- /dev/null +++ b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html @@ -0,0 +1,11 @@ +orcid-logo + + + {{ orcidTooltip }} + diff --git a/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.scss b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.scss new file mode 100644 index 0000000000..6a1c259e18 --- /dev/null +++ b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.scss @@ -0,0 +1,11 @@ +:host { + display: inline-block; +} + +.orcid-icon { + height: 1.2rem; + + &.not-authenticated { + filter: grayscale(100%); + } +} diff --git a/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.spec.ts b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.spec.ts new file mode 100644 index 0000000000..adb3c91f94 --- /dev/null +++ b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.spec.ts @@ -0,0 +1,71 @@ +import { + NgClass, + NgIf, +} from '@angular/common'; +import { + ComponentFixture, + TestBed, +} from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; + +import { MetadataValue } from '../../core/shared/metadata.models'; +import { OrcidBadgeAndTooltipComponent } from './orcid-badge-and-tooltip.component'; + +describe('OrcidBadgeAndTooltipComponent', () => { + let component: OrcidBadgeAndTooltipComponent; + let fixture: ComponentFixture; + let translateService: TranslateService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [OrcidBadgeAndTooltipComponent], + imports: [ + NgbTooltipModule, + NgClass, + NgIf, + ], + providers: [ + { provide: TranslateService, useValue: { instant: (key: string) => key } }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(OrcidBadgeAndTooltipComponent); + component = fixture.componentInstance; + translateService = TestBed.inject(TranslateService); + + component.orcid = { value: '0000-0002-1825-0097' } as MetadataValue; + component.authenticatedTimestamp = { value: '2023-10-01' } as MetadataValue; + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set orcidTooltip when authenticatedTimestamp is provided', () => { + component.ngOnInit(); + expect(component.orcidTooltip).toBe('person.orcid-tooltip.authenticated'); + }); + + it('should set orcidTooltip when authenticatedTimestamp is not provided', () => { + component.authenticatedTimestamp = null; + component.ngOnInit(); + expect(component.orcidTooltip).toBe('person.orcid-tooltip.not-authenticated'); + }); + + it('should display the ORCID icon', () => { + const badgeIcon = fixture.debugElement.query(By.css('img[data-test="orcidIcon"]')); + expect(badgeIcon).toBeTruthy(); + }); + + it('should display the ORCID icon in greyscale if there is no authenticated timestamp', () => { + component.authenticatedTimestamp = null; + fixture.detectChanges(); + const badgeIcon = fixture.debugElement.query(By.css('img[data-test="orcidIcon"]')); + expect(badgeIcon.nativeElement.classList).toContain('not-authenticated'); + }); + +}); diff --git a/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.ts b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.ts new file mode 100644 index 0000000000..1939bad57f --- /dev/null +++ b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.ts @@ -0,0 +1,56 @@ + + +import { + Component, + Input, + OnInit, +} from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +import { MetadataValue } from '../../core/shared/metadata.models'; + +/** + * Component to display an ORCID badge with a tooltip. + * The tooltip text changes based on whether the ORCID is authenticated. + */ +@Component({ + selector: 'ds-orcid-badge-and-tooltip', + templateUrl: './orcid-badge-and-tooltip.component.html', + styleUrls: ['./orcid-badge-and-tooltip.component.scss'], +}) +export class OrcidBadgeAndTooltipComponent implements OnInit { + + /** + * The ORCID value to be displayed. + */ + @Input() orcid: MetadataValue; + + /** + * The timestamp indicating when the ORCID was authenticated. + */ + @Input() authenticatedTimestamp: MetadataValue; + + /** + * The tooltip text to be displayed. + */ + orcidTooltip: string; + + /** + * Constructor to inject the TranslateService. + * @param translateService - Service for translation. + */ + constructor( + private translateService: TranslateService, + ) { } + + /** + * Initializes the component. + * Sets the tooltip text based on the presence of the authenticated timestamp. + */ + ngOnInit() { + this.orcidTooltip = this.authenticatedTimestamp ? + this.translateService.instant('person.orcid-tooltip.authenticated', { orcid: this.orcid.value }) : + this.translateService.instant('person.orcid-tooltip.not-authenticated', { orcid: this.orcid.value }); + } + +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 9f05b1d370..d6b6e861ce 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -284,6 +284,7 @@ import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bi import { NgxPaginationModule } from 'ngx-pagination'; import { ThemedLangSwitchComponent } from './lang-switch/themed-lang-switch.component'; import {ThemedUserMenuComponent} from './auth-nav-menu/user-menu/themed-user-menu.component'; +import { OrcidBadgeAndTooltipComponent } from './orcid-badge-and-tooltip/orcid-badge-and-tooltip.component'; const MODULES = [ CommonModule, @@ -404,6 +405,7 @@ const COMPONENTS = [ EpersonSearchBoxComponent, GroupSearchBoxComponent, ThemedItemPageTitleFieldComponent, + OrcidBadgeAndTooltipComponent, ]; const ENTRY_COMPONENTS = [ diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 0a1804fa5c..3f85e8b687 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -5248,6 +5248,10 @@ "person.orcid.registry.auth": "ORCID Authorizations", + "person.orcid-tooltip.authenticated": "{{orcid}}", + + "person.orcid-tooltip.not-authenticated": "{{orcid}} (unconfirmed)", + "home.recent-submissions.head": "Recent Submissions", "listable-notification-object.default-message": "This object couldn't be retrieved", From 7472be009855376edccb5ac5242673f1bb44e75c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:57:43 +0000 Subject: [PATCH 010/104] Bump @types/lodash from 4.17.13 to 4.17.14 Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.17.13 to 4.17.14. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash) --- updated-dependencies: - dependency-name: "@types/lodash" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ce5449fa33..8ac4635e79 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "@types/grecaptcha": "^3.0.9", "@types/jasmine": "~3.6.0", "@types/js-cookie": "2.2.6", - "@types/lodash": "^4.17.13", + "@types/lodash": "^4.17.14", "@types/node": "^14.18.63", "@types/sanitize-html": "^2.13.0", "@typescript-eslint/eslint-plugin": "^5.62.0", diff --git a/yarn.lock b/yarn.lock index 96b6665499..8b9b52a4e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2539,10 +2539,10 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/lodash@^4.17.13": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb" - integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg== +"@types/lodash@^4.17.14": + version "4.17.14" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.14.tgz#bafc053533f4cdc5fcc9635af46a963c1f3deaff" + integrity sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A== "@types/mime@*": version "3.0.1" From 9741ce3e697a75ec5955c8b2d2b00282fe815790 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:57:54 +0000 Subject: [PATCH 011/104] Bump mirador from 3.4.2 to 3.4.3 Bumps [mirador](https://github.com/ProjectMirador/mirador) from 3.4.2 to 3.4.3. - [Release notes](https://github.com/ProjectMirador/mirador/releases) - [Commits](https://github.com/ProjectMirador/mirador/compare/v3.4.2...v3.4.3) --- updated-dependencies: - dependency-name: mirador dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ce5449fa33..3d7e9c0ec7 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "lru-cache": "^7.14.1", "markdown-it": "^13.0.2", "markdown-it-mathjax3": "^4.3.2", - "mirador": "^3.4.2", + "mirador": "^3.4.3", "mirador-dl-plugin": "^0.13.0", "mirador-share-plugin": "^0.16.0", "morgan": "^1.10.0", diff --git a/yarn.lock b/yarn.lock index 96b6665499..48ca8c3da3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8226,10 +8226,10 @@ mirador-share-plugin@^0.16.0: dependencies: notistack "^3.0.1" -mirador@^3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/mirador/-/mirador-3.4.2.tgz#51ec7ca1b9854792bbe2fa5e13b3692c92e97102" - integrity sha512-Gd7G4NkXq6/qD/De5soYspSo9VykAzrGFunKqUI3x9WShoZP23pYIEPoC/96tvfk3KMv+UbAUxDp99Xeo7vnVQ== +mirador@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/mirador/-/mirador-3.4.3.tgz#1b083bd037b851d1389758f3c86eb94832b00ec6" + integrity sha512-yHoug0MHy4e9apykbbBhK+4CmbZS94zMxmugw2E2VX6iB0b2PKKY0JfYr/QfXh9P29YnWAbymaXJVpgbHVpTVw== dependencies: "@material-ui/core" "^4.12.3" "@material-ui/icons" "^4.9.1" From 9bc65b99a65051bdc4d1d16115ea12c774d8c974 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:58:20 +0000 Subject: [PATCH 012/104] Bump core-js from 3.39.0 to 3.40.0 Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.39.0 to 3.40.0. - [Release notes](https://github.com/zloirock/core-js/releases) - [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/zloirock/core-js/commits/v3.40.0/packages/core-js) --- updated-dependencies: - dependency-name: core-js dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ce5449fa33..7e8f57e977 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "colors": "^1.4.0", "compression": "^1.7.5", "cookie-parser": "1.4.7", - "core-js": "^3.39.0", + "core-js": "^3.40.0", "date-fns": "^2.30.0", "date-fns-tz": "^1.3.7", "deepmerge": "^4.3.1", diff --git a/yarn.lock b/yarn.lock index 96b6665499..88a5116990 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4272,10 +4272,10 @@ core-js-compat@^3.25.1: dependencies: browserslist "^4.21.5" -core-js@^3.39.0: - version "3.39.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.39.0.tgz#57f7647f4d2d030c32a72ea23a0555b2eaa30f83" - integrity sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g== +core-js@^3.40.0: + version "3.40.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.40.0.tgz#2773f6b06877d8eda102fc42f828176437062476" + integrity sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ== core-util-is@1.0.2: version "1.0.2" From 39ddc5cbcd6bae6dd9a1bb2397be6f4a5ef334d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:58:28 +0000 Subject: [PATCH 013/104] Bump jsonschema from 1.4.1 to 1.5.0 Bumps [jsonschema](https://github.com/tdegrunt/jsonschema) from 1.4.1 to 1.5.0. - [Commits](https://github.com/tdegrunt/jsonschema/commits) --- updated-dependencies: - dependency-name: jsonschema dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ce5449fa33..2306326435 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "js-cookie": "2.2.1", "js-yaml": "^4.1.0", "json5": "^2.2.3", - "jsonschema": "1.4.1", + "jsonschema": "1.5.0", "jwt-decode": "^3.1.2", "klaro": "^0.7.21", "lodash": "^4.17.21", diff --git a/yarn.lock b/yarn.lock index 96b6665499..8de93af4f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7398,10 +7398,10 @@ jsonparse@^1.3.1: resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -jsonschema@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab" - integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== +jsonschema@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.5.0.tgz#f6aceb1ab9123563dd901d05f81f9d4883d3b7d8" + integrity sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw== jsprim@^2.0.2: version "2.0.2" From d0b65719544a0938859a10c795dd846a30eeee42 Mon Sep 17 00:00:00 2001 From: Andrea Barbasso <´andrea.barbasso@4science.com´> Date: Mon, 20 Jan 2025 15:31:31 +0100 Subject: [PATCH 014/104] [CST-14904] improve orcid logo image alt --- .../orcid-badge-and-tooltip.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html index fc34aee970..9f4821e780 100644 --- a/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html +++ b/src/app/shared/orcid-badge-and-tooltip/orcid-badge-and-tooltip.component.html @@ -2,7 +2,7 @@ [ngbTooltip]="orcidTooltipTemplate" class="orcid-icon" [ngClass]="{'not-authenticated': !authenticatedTimestamp}" - alt="orcid-logo" + alt="ORCID {{ orcidTooltip }}" src="assets/images/orcid.logo.icon.svg" data-test="orcidIcon"/> From 74d6dbb454cf40d5c418cc0c6cde05ea04de2103 Mon Sep 17 00:00:00 2001 From: Mohana Sarmiento Date: Mon, 20 Jan 2025 18:13:35 -0500 Subject: [PATCH 015/104] Fix double encoding of bitstream filenames in URL --- src/app/core/data/bitstream-data.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/data/bitstream-data.service.ts b/src/app/core/data/bitstream-data.service.ts index bf8e3585df..bb4ec28166 100644 --- a/src/app/core/data/bitstream-data.service.ts +++ b/src/app/core/data/bitstream-data.service.ts @@ -171,7 +171,7 @@ export class BitstreamDataService extends IdentifiableDataService imp searchParams.push(new RequestParam('sequenceId', sequenceId)); } if (hasValue(filename)) { - searchParams.push(new RequestParam('filename', encodeURIComponent(filename))); + searchParams.push(new RequestParam('filename', filename)); } const hrefObs = this.getSearchByHref( From 2bd53d822abe8b811bcde9d613f68001a35ef3bf Mon Sep 17 00:00:00 2001 From: Mohana Sarmiento Date: Tue, 21 Jan 2025 16:26:01 -0500 Subject: [PATCH 016/104] Add unit test --- .../core/data/bitstream-data.service.spec.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/app/core/data/bitstream-data.service.spec.ts b/src/app/core/data/bitstream-data.service.spec.ts index 89178f8dd2..1f4b2efaf6 100644 --- a/src/app/core/data/bitstream-data.service.spec.ts +++ b/src/app/core/data/bitstream-data.service.spec.ts @@ -21,6 +21,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s import objectContaining = jasmine.objectContaining; import { RemoteData } from './remote-data'; import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { RequestParam } from '../cache/models/request-param.model'; describe('BitstreamDataService', () => { let service: BitstreamDataService; @@ -132,4 +133,30 @@ describe('BitstreamDataService', () => { expect(service.invalidateByHref).toHaveBeenCalledWith('fake-bitstream2-self'); }); }); + + describe('findByItemHandle', () => { + it('should encode the filename correctly in the search parameters', () => { + const handle = '123456789/1234'; + const sequenceId = '5'; + const filename = 'file with spaces.pdf'; + const searchParams = [ + new RequestParam('handle', handle), + new RequestParam('sequenceId', sequenceId), + new RequestParam('filename', filename) + ]; + const linksToFollow: FollowLinkConfig[] = []; + + spyOn(service as any, 'getSearchByHref').and.callThrough(); + + service.getSearchByHref('byItemHandle', { searchParams }, ...linksToFollow).subscribe((href) => { + expect(service.getSearchByHref).toHaveBeenCalledWith( + 'byItemHandle', + { searchParams }, + ...linksToFollow + ); + + expect(href).toBe(`${url}/bitstreams/search/byItemHandle?handle=123456789%2F1234&sequenceId=5&filename=file%20with%20spaces.pdf`); + }); + }); + }); }); From e3f13f8c54f6054765848c5f8f95e79fa3c7fd9d Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 21 Jan 2025 14:16:29 -0600 Subject: [PATCH 017/104] Ensure admin menu e2e tests hover over admin menu before clicking on it. Attempt to stabilize tests which open this menu. (cherry picked from commit e9cd0f4c64ad7293afde482b9f59ddc22b5f90cc) --- cypress/e2e/admin-add-new-modals.cy.ts | 3 +++ cypress/e2e/admin-edit-modals.cy.ts | 3 +++ cypress/e2e/admin-export-modals.cy.ts | 2 ++ 3 files changed, 8 insertions(+) diff --git a/cypress/e2e/admin-add-new-modals.cy.ts b/cypress/e2e/admin-add-new-modals.cy.ts index 0179ca7a7c..332d44da13 100644 --- a/cypress/e2e/admin-add-new-modals.cy.ts +++ b/cypress/e2e/admin-add-new-modals.cy.ts @@ -9,6 +9,7 @@ describe('Admin Add New Modals', () => { it('Add new Community modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu @@ -23,6 +24,7 @@ describe('Admin Add New Modals', () => { it('Add new Collection modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu @@ -37,6 +39,7 @@ describe('Admin Add New Modals', () => { it('Add new Item modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu diff --git a/cypress/e2e/admin-edit-modals.cy.ts b/cypress/e2e/admin-edit-modals.cy.ts index 79190bfce9..8ba524d5be 100644 --- a/cypress/e2e/admin-edit-modals.cy.ts +++ b/cypress/e2e/admin-edit-modals.cy.ts @@ -9,6 +9,7 @@ describe('Admin Edit Modals', () => { it('Edit Community modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu @@ -23,6 +24,7 @@ describe('Admin Edit Modals', () => { it('Edit Collection modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu @@ -37,6 +39,7 @@ describe('Admin Edit Modals', () => { it('Edit Item modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu diff --git a/cypress/e2e/admin-export-modals.cy.ts b/cypress/e2e/admin-export-modals.cy.ts index 55d952cad8..24a184fd35 100644 --- a/cypress/e2e/admin-export-modals.cy.ts +++ b/cypress/e2e/admin-export-modals.cy.ts @@ -9,6 +9,7 @@ describe('Admin Export Modals', () => { it('Export metadata modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu @@ -23,6 +24,7 @@ describe('Admin Export Modals', () => { it('Export batch modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').trigger('mouseover'); cy.get('#sidebar-collapse-toggle').click(); // Click on entry of menu From b839252ed7fef45d9e7851012f4dc9c99e7f4c0c Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Wed, 22 Jan 2025 11:02:35 +0300 Subject: [PATCH 018/104] Restrict SSR to paths in the sitemap Because Angular SSR is not very efficient, after discussion with the Google Scholar team we realized a compromise would be to only use SSR for pages in the DSpace sitemap (and the home page). --- config/config.example.yml | 2 ++ server.ts | 2 +- src/config/universal-config.interface.ts | 5 +++++ src/environments/environment.production.ts | 1 + src/environments/environment.test.ts | 1 + src/environments/environment.ts | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/config/config.example.yml b/config/config.example.yml index 42e13038d0..c1d7f967a4 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -23,6 +23,8 @@ ssr: # Determining which styles are critical is a relatively expensive operation; this option is # disabled (false) by default to boost server performance at the expense of loading smoothness. inlineCriticalCss: false + # Path prefixes to enable SSR for. By default these are limited to paths of primary DSpace objects. + paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ] # The REST API server settings # NOTE: these settings define which (publicly available) REST API to use. They are usually diff --git a/server.ts b/server.ts index 23d29723c6..82417f17dc 100644 --- a/server.ts +++ b/server.ts @@ -238,7 +238,7 @@ export function app() { * The callback function to serve server side angular */ function ngApp(req, res) { - if (environment.universal.preboot) { + if (environment.universal.preboot && req.method === 'GET' && (req.path === '/' || environment.universal.paths.some(pathPrefix => req.path.startsWith(pathPrefix)))) { // Render the page to user via SSR (server side rendering) serverSideRender(req, res); } else { diff --git a/src/config/universal-config.interface.ts b/src/config/universal-config.interface.ts index eb89264e37..e54168823f 100644 --- a/src/config/universal-config.interface.ts +++ b/src/config/universal-config.interface.ts @@ -13,4 +13,9 @@ export interface UniversalConfig extends Config { * loading smoothness. */ inlineCriticalCss?: boolean; + + /** + * Paths to enable SSR for. Defaults to the home page and paths in the sitemap. + */ + paths: Array; } diff --git a/src/environments/environment.production.ts b/src/environments/environment.production.ts index 931dd422e3..46a93519df 100644 --- a/src/environments/environment.production.ts +++ b/src/environments/environment.production.ts @@ -9,5 +9,6 @@ export const environment: Partial = { async: true, time: false, inlineCriticalCss: false, + paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], } }; diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index cfd54781e6..e872285f61 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -12,6 +12,7 @@ export const environment: BuildConfig = { async: true, time: false, inlineCriticalCss: false, + paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], }, // Angular Universal server settings. diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 7c09793790..25af371e47 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -14,6 +14,7 @@ export const environment: Partial = { async: true, time: false, inlineCriticalCss: false, + paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], } }; From 6cb3e8bbfb3e7356e5a9f18b15c7e477be8cb23a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 23:47:21 +0000 Subject: [PATCH 019/104] Bump postcss from 8.4.49 to 8.5.1 in the postcss group Bumps the postcss group with 1 update: [postcss](https://github.com/postcss/postcss). Updates `postcss` from 8.4.49 to 8.5.1 - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.4.49...8.5.1) --- updated-dependencies: - dependency-name: postcss dependency-type: direct:development update-type: version-update:semver-minor dependency-group: postcss ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ce5449fa33..980a98c209 100644 --- a/package.json +++ b/package.json @@ -177,7 +177,7 @@ "ng-mocks": "^14.13.2", "ngx-mask": "^13.1.7", "nodemon": "^2.0.22", - "postcss": "^8.4", + "postcss": "^8.5", "postcss-import": "^14.0.0", "postcss-loader": "^4.0.3", "postcss-preset-env": "^7.4.2", diff --git a/yarn.lock b/yarn.lock index 96b6665499..39c6f0378d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8336,10 +8336,10 @@ mute-stream@0.0.8: resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nanoid@^3.3.6, nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +nanoid@^3.3.6, nanoid@^3.3.8: + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== natural-compare-lite@^1.4.0: version "1.4.0" @@ -9438,12 +9438,12 @@ postcss@8.4.31: picocolors "^1.0.0" source-map-js "^1.0.2" -postcss@^8.2.14, postcss@^8.3.11, postcss@^8.3.7, postcss@^8.4, postcss@^8.4.19: - version "8.4.49" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" - integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== +postcss@^8.2.14, postcss@^8.3.11, postcss@^8.3.7, postcss@^8.4.19, postcss@^8.5: + version "8.5.1" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.1.tgz#e2272a1f8a807fafa413218245630b5db10a3214" + integrity sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ== dependencies: - nanoid "^3.3.7" + nanoid "^3.3.8" picocolors "^1.1.1" source-map-js "^1.2.1" From fc2d3f0a233b70b5bbf0857fa22c7fb7a3c4951e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 23:47:29 +0000 Subject: [PATCH 020/104] Bump sass from 1.83.1 to 1.83.4 in the sass group Bumps the sass group with 1 update: [sass](https://github.com/sass/dart-sass). Updates `sass` from 1.83.1 to 1.83.4 - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.83.1...1.83.4) --- updated-dependencies: - dependency-name: sass dependency-type: direct:development update-type: version-update:semver-patch dependency-group: sass ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ce5449fa33..758d467bf6 100644 --- a/package.json +++ b/package.json @@ -186,7 +186,7 @@ "react-copy-to-clipboard": "^5.1.0", "react-dom": "^16.14.0", "rimraf": "^3.0.2", - "sass": "~1.83.1", + "sass": "~1.83.4", "sass-loader": "^12.6.0", "sass-resources-loader": "^2.2.5", "ts-node": "^8.10.2", diff --git a/yarn.lock b/yarn.lock index 96b6665499..7e9df932cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10255,10 +10255,10 @@ sass@1.58.1: immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" -sass@^1.25.0, sass@~1.83.1: - version "1.83.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.83.1.tgz#dee1ab94b47a6f9993d3195d36f556bcbda64846" - integrity sha512-EVJbDaEs4Rr3F0glJzFSOvtg2/oy2V/YrGFPqPY24UqcLDWcI9ZY5sN+qyO3c/QCZwzgfirvhXvINiJCE/OLcA== +sass@^1.25.0, sass@~1.83.4: + version "1.83.4" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.83.4.tgz#5ccf60f43eb61eeec300b780b8dcb85f16eec6d1" + integrity sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA== dependencies: chokidar "^4.0.0" immutable "^5.0.2" From c5fd4426cd5e688ff65b38d2e4c177831e8ecc5c Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 21 Nov 2024 16:28:41 +0100 Subject: [PATCH 021/104] [DURACOM-303] prevent possibly long-lasting search and browse calls in SSR --- .../browse-by-date-page.component.spec.ts | 39 +++++++++++++++++-- .../browse-by-date-page.component.ts | 11 +++++- .../browse-by-metadata-page.component.spec.ts | 36 +++++++++++++++-- .../browse-by-metadata-page.component.ts | 13 +++++-- .../browse-by-title-page.component.spec.ts | 32 ++++++++++++++- .../configuration-search-page.component.ts | 5 ++- .../shared/search/search.component.spec.ts | 32 ++++++++++++++- src/app/shared/search/search.component.ts | 24 +++++++++++- 8 files changed, 176 insertions(+), 16 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index b19250edae..ac572c7b86 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -1,5 +1,5 @@ import { BrowseByDatePageComponent } from './browse-by-date-page.component'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { CommonModule } from '@angular/common'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; @@ -9,7 +9,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { BrowseService } from '../../core/browse/browse.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { RouterMock } from '../../shared/mocks/router.mock'; -import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ChangeDetectorRef, NO_ERRORS_SCHEMA, PLATFORM_ID } from '@angular/core'; import { of as observableOf } from 'rxjs'; import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; import { Community } from '../../core/shared/community.model'; @@ -24,6 +24,7 @@ import { APP_CONFIG } from '../../../config/app-config.interface'; import { environment } from '../../../environments/environment'; import { SortDirection } from '../../core/cache/models/sort-options.model'; import { cold } from 'jasmine-marbles'; +import { Store } from "@ngrx/store"; describe('BrowseByDatePageComponent', () => { let comp: BrowseByDatePageComponent; @@ -95,7 +96,10 @@ describe('BrowseByDatePageComponent', () => { { provide: Router, useValue: new RouterMock() }, { provide: PaginationService, useValue: paginationService }, { provide: ChangeDetectorRef, useValue: mockCdRef }, - { provide: APP_CONFIG, useValue: environment } + { provide: APP_CONFIG, useValue: environment }, + { provide: Store, useValue: {} }, + { provide: APP_CONFIG, useValue: environment }, + { provide: PLATFORM_ID, useValue: 'browser' }, ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -131,4 +135,33 @@ describe('BrowseByDatePageComponent', () => { //expect(comp.startsWithOptions[0]).toEqual(new Date().getUTCFullYear()); expect(comp.startsWithOptions[0]).toEqual(1960); }); + + describe('when rendered in SSR', () => { + beforeEach(() => { + comp.platformId = 'server'; + spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + }); + + it('should not call getBrowseEntriesFor on init', (done) => { + comp.ngOnInit(); + expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled(); + comp.loading$.subscribe((res) => { + expect(res).toBeFalsy(); + done(); + }); + }); + }); + + describe('when rendered in CSR', () => { + beforeEach(() => { + comp.platformId = 'browser'; + spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + }); + + it('should call getBrowseEntriesFor on init', fakeAsync(() => { + comp.ngOnInit(); + tick(100); + expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled(); + })); + }); }); diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 7e0b6f0f88..62bba4d86c 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, Inject } from '@angular/core'; +import { ChangeDetectorRef, Component, Inject, PLATFORM_ID } from '@angular/core'; import { BrowseByMetadataPageComponent, browseParamsToOptions @@ -11,6 +11,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv import { StartsWithType } from '../../shared/starts-with/starts-with-decorator'; import { PaginationService } from '../../core/pagination/pagination.service'; import { map, take } from 'rxjs/operators'; +import { of as observableOf } from 'rxjs'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { isValidDate } from '../../shared/date.util'; @@ -18,6 +19,7 @@ import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { RemoteData } from '../../core/data/remote-data'; import { Item } from '../../core/shared/item.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { isPlatformServer } from "@angular/common"; @Component({ selector: 'ds-browse-by-date-page', @@ -44,11 +46,16 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { protected cdRef: ChangeDetectorRef, @Inject(APP_CONFIG) public appConfig: AppConfig, public dsoNameService: DSONameService, + @Inject(PLATFORM_ID) public platformId: any, ) { - super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService); + super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService, platformId); } ngOnInit(): void { + if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + this.loading$ = observableOf(false); + return; + } const sortConfig = new SortOptions('default', SortDirection.ASC); this.startsWithType = StartsWithType.date; this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts index 2bdecc2670..8eda34cd62 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts @@ -3,7 +3,7 @@ import { browseParamsToOptions, getBrowseSearchOptions } from './browse-by-metadata-page.component'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { BrowseService } from '../../core/browse/browse.service'; import { CommonModule } from '@angular/common'; import { RouterTestingModule } from '@angular/router/testing'; @@ -13,7 +13,7 @@ import { EnumKeysPipe } from '../../shared/utils/enum-keys-pipe'; import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; import { Observable, of as observableOf } from 'rxjs'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { NO_ERRORS_SCHEMA, PLATFORM_ID } from '@angular/core'; import { RemoteData } from '../../core/data/remote-data'; import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model'; import { PageInfo } from '../../core/shared/page-info.model'; @@ -111,7 +111,8 @@ describe('BrowseByMetadataPageComponent', () => { { provide: DSpaceObjectDataService, useValue: mockDsoService }, { provide: PaginationService, useValue: paginationService }, { provide: Router, useValue: new RouterMock() }, - { provide: APP_CONFIG, useValue: environmentMock } + { provide: APP_CONFIG, useValue: environmentMock }, + { provide: PLATFORM_ID, useValue: 'browser' }, ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -224,6 +225,35 @@ describe('BrowseByMetadataPageComponent', () => { expect(result.fetchThumbnail).toBeTrue(); }); }); + + describe('when rendered in SSR', () => { + beforeEach(() => { + comp.platformId = 'server'; + spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + }); + + it('should not call getBrowseEntriesFor on init', (done) => { + comp.ngOnInit(); + expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled(); + comp.loading$.subscribe((res) => { + expect(res).toBeFalsy(); + done(); + }); + }); + }); + + describe('when rendered in CSR', () => { + beforeEach(() => { + comp.platformId = 'browser'; + spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + }); + + it('should call getBrowseEntriesFor on init', fakeAsync(() => { + comp.ngOnInit(); + tick(100); + expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled(); + })); + }); }); export function toRemoteData(objects: any[]): Observable>> { diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index fe407a2fb0..4629982e65 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -1,5 +1,5 @@ import { combineLatest as observableCombineLatest, Observable, Subscription, of as observableOf } from 'rxjs'; -import { Component, Inject, OnInit, OnDestroy } from '@angular/core'; +import { Component, Inject, OnInit, OnDestroy, Input, PLATFORM_ID } from '@angular/core'; import { RemoteData } from '../../core/data/remote-data'; import { PaginatedList } from '../../core/data/paginated-list.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; @@ -37,7 +37,10 @@ export const BBM_PAGINATION_ID = 'bbm'; * 'dc.contributor.*' */ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { - + /** + * Defines whether to fetch search results during SSR execution + */ + @Input() renderOnServerSide = false; /** * The list of browse-entries to display */ @@ -134,6 +137,7 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { protected router: Router, @Inject(APP_CONFIG) public appConfig: AppConfig, public dsoNameService: DSONameService, + @Inject(PLATFORM_ID) public platformId: any, ) { this.fetchThumbnails = this.appConfig.browseBy.showThumbnails; @@ -146,7 +150,10 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { ngOnInit(): void { - + if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + this.loading$ = observableOf(false); + return; + } const sortConfig = new SortOptions('default', SortDirection.ASC); this.updatePage(getBrowseSearchOptions(this.defaultBrowseId, this.paginationConfig, sortConfig)); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts index e32c0ac430..9c9586032d 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { Item } from '../../core/shared/item.model'; import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; @@ -22,6 +22,7 @@ import { PaginationService } from '../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub'; import { APP_CONFIG } from '../../../config/app-config.interface'; import { environment } from '../../../environments/environment'; +import { BrowseEntry } from "../../core/shared/browse-entry.model"; describe('BrowseByTitlePageComponent', () => { @@ -97,4 +98,33 @@ describe('BrowseByTitlePageComponent', () => { expect(result.payload.page).toEqual(mockItems); }); }); + + describe('when rendered in SSR', () => { + beforeEach(() => { + comp.platformId = 'server'; + spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + }); + + it('should not call getBrowseEntriesFor on init', (done) => { + comp.ngOnInit(); + expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled(); + comp.loading$.subscribe((res) => { + expect(res).toBeFalsy(); + done(); + }); + }); + }); + + describe('when rendered in CSR', () => { + beforeEach(() => { + comp.platformId = 'browser'; + spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + }); + + it('should call getBrowseEntriesFor on init', fakeAsync(() => { + comp.ngOnInit(); + tick(100); + expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled(); + })); + }); }); diff --git a/src/app/search-page/configuration-search-page.component.ts b/src/app/search-page/configuration-search-page.component.ts index 9196dda025..13e4709ca0 100644 --- a/src/app/search-page/configuration-search-page.component.ts +++ b/src/app/search-page/configuration-search-page.component.ts @@ -1,7 +1,7 @@ import { HostWindowService } from '../shared/host-window.service'; import { SidebarService } from '../shared/sidebar/sidebar.service'; import { SearchComponent } from '../shared/search/search.component'; -import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject, PLATFORM_ID } from '@angular/core'; import { pushInOut } from '../shared/animations/push'; import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; @@ -35,7 +35,8 @@ export class ConfigurationSearchPageComponent extends SearchComponent { protected routeService: RouteService, protected router: Router, @Inject(APP_CONFIG) protected appConfig: AppConfig, + @Inject(PLATFORM_ID) public platformId: any, ) { - super(service, sidebarService, windowService, searchConfigService, routeService, router, appConfig); + super(service, sidebarService, windowService, searchConfigService, routeService, router, appConfig, platformId); } } diff --git a/src/app/shared/search/search.component.spec.ts b/src/app/shared/search/search.component.spec.ts index 8ffd832009..05d4fc6b85 100644 --- a/src/app/shared/search/search.component.spec.ts +++ b/src/app/shared/search/search.component.spec.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA, PLATFORM_ID } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; @@ -216,6 +216,7 @@ export function configureSearchComponentTestingModule(compType, additionalDeclar useValue: searchConfigurationServiceStub }, { provide: APP_CONFIG, useValue: environment }, + { provide: PLATFORM_ID, useValue: 'browser' }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(compType, { @@ -374,5 +375,34 @@ describe('SearchComponent', () => { expect(result).toBeNull(); }); }); + + describe('when rendered in SSR', () => { + beforeEach(() => { + comp.platformId = 'server'; + }); + + it('should not call search method on init', (done) => { + comp.ngOnInit(); + //Check that the first method from which the search depend upon is not being called + expect(searchConfigurationServiceStub.getCurrentConfiguration).not.toHaveBeenCalled(); + comp.initialized$.subscribe((res) => { + expect(res).toBeTruthy(); + done(); + }); + }); + }); + + describe('when rendered in CSR', () => { + beforeEach(() => { + comp.platformId = 'browser'; + }); + + it('should call search method on init', fakeAsync(() => { + comp.ngOnInit(); + tick(100); + //Check that the last method from which the search depend upon is being called + expect(searchServiceStub.search).toHaveBeenCalled(); + })); + }); }); }); diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 5a848c9786..6040a47d6e 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -1,4 +1,14 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, OnInit, Output, OnDestroy } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Inject, + Input, + OnInit, + Output, + OnDestroy, + PLATFORM_ID +} from '@angular/core'; import { NavigationStart, Router } from '@angular/router'; import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; @@ -38,6 +48,7 @@ import { ITEM_MODULE_PATH } from '../../item-page/item-page-routing-paths'; import { COLLECTION_MODULE_PATH } from '../../collection-page/collection-page-routing-paths'; import { COMMUNITY_MODULE_PATH } from '../../community-page/community-page-routing-paths'; import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; +import { isPlatformServer } from "@angular/common"; @Component({ selector: 'ds-search', @@ -176,6 +187,11 @@ export class SearchComponent implements OnDestroy, OnInit { */ @Input() scope: string; + /** + * Defines whether to fetch search results during SSR execution + */ + @Input() renderOnServerSide = false; + /** * The current configuration used during the search */ @@ -285,6 +301,7 @@ export class SearchComponent implements OnDestroy, OnInit { protected routeService: RouteService, protected router: Router, @Inject(APP_CONFIG) protected appConfig: AppConfig, + @Inject(PLATFORM_ID) public platformId: any, ) { this.isXsOrSm$ = this.windowService.isXsOrSm(); } @@ -297,6 +314,11 @@ export class SearchComponent implements OnDestroy, OnInit { * If something changes, update the list of scopes for the dropdown */ ngOnInit(): void { + if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + this.initialized$.next(true); + return; + } + if (this.useUniquePageId) { // Create an unique pagination id related to the instance of the SearchComponent this.paginationId = uniqueId(this.paginationId); From 5868a3198f9d12d817ac845ea1d04c59aa756359 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 16:49:25 +0100 Subject: [PATCH 022/104] [DURACOM-303] fix missing imports --- .../browse-by-date-page.component.spec.ts | 1 + .../browse-by-metadata-page.component.ts | 1 + .../browse-by-title-page.component.ts | 11 +++++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index ac572c7b86..d94e7df04f 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -25,6 +25,7 @@ import { environment } from '../../../environments/environment'; import { SortDirection } from '../../core/cache/models/sort-options.model'; import { cold } from 'jasmine-marbles'; import { Store } from "@ngrx/store"; +import { BrowseEntry } from "../../core/shared/browse-entry.model"; describe('BrowseByDatePageComponent', () => { let comp: BrowseByDatePageComponent; diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 4629982e65..e18841f9ca 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -22,6 +22,7 @@ import { Collection } from '../../core/shared/collection.model'; import { Community } from '../../core/shared/community.model'; import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { isPlatformServer } from "@angular/common"; export const BBM_PAGINATION_ID = 'bbm'; diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index 11dc2a2a6a..0d8a2e32ed 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -1,5 +1,5 @@ import { combineLatest as observableCombineLatest } from 'rxjs'; -import { Component, Inject } from '@angular/core'; +import { Component, Inject, PLATFORM_ID } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { hasValue } from '../../shared/empty.util'; import { @@ -11,9 +11,11 @@ import { BrowseService } from '../../core/browse/browse.service'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { PaginationService } from '../../core/pagination/pagination.service'; import { map, take } from 'rxjs/operators'; +import { of as observableOf } from 'rxjs'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { isPlatformServer } from "@angular/common"; @Component({ selector: 'ds-browse-by-title-page', @@ -32,11 +34,16 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent { protected router: Router, @Inject(APP_CONFIG) public appConfig: AppConfig, public dsoNameService: DSONameService, + @Inject(PLATFORM_ID) public platformId: any, ) { - super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService); + super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService, platformId); } ngOnInit(): void { + if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + this.loading$ = observableOf(false); + return; + } const sortConfig = new SortOptions('dc.title', SortDirection.ASC); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); From 39c5de6e18ff7e4baa78861b760990c775433562 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Tue, 26 Nov 2024 13:11:26 +0100 Subject: [PATCH 023/104] [DURACOM-303] implement skeleton component for search results --- package.json | 1 + .../search-results-skeleton.component.html | 12 +++++++ .../search-results-skeleton.component.scss | 0 .../search-results-skeleton.component.spec.ts | 27 ++++++++++++++ .../search-results-skeleton.component.ts | 36 +++++++++++++++++++ .../search-results.component.html | 7 +++- .../search-results.component.spec.ts | 2 ++ src/themes/custom/lazy-theme.module.ts | 4 +++ 8 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts create mode 100644 src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts diff --git a/package.json b/package.json index c2aa6d74dd..86a506c57a 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "ngx-infinite-scroll": "^15.0.0", "ngx-pagination": "6.0.3", "ngx-sortablejs": "^11.1.0", + "ngx-skeleton-loader": "^9.0.0", "ngx-ui-switch": "^14.1.0", "nouislider": "^15.8.1", "pem": "1.14.8", diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html new file mode 100644 index 0000000000..33f05985e1 --- /dev/null +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -0,0 +1,12 @@ +@for (result of loadingResults; track result) { +
+ @if(showThumbnails) { + + } + +
+ + +
+
+} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts new file mode 100644 index 0000000000..0ec74eb946 --- /dev/null +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts @@ -0,0 +1,27 @@ +import { + ComponentFixture, + TestBed, +} from '@angular/core/testing'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + +import { SearchResultsSkeletonComponent } from './search-results-skeleton.component'; + +describe('SearchResultsSkeletonComponent', () => { + let component: SearchResultsSkeletonComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SearchResultsSkeletonComponent, NgxSkeletonLoaderModule], + }) + .compileComponents(); + + fixture = TestBed.createComponent(SearchResultsSkeletonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts new file mode 100644 index 0000000000..d35c5d1733 --- /dev/null +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -0,0 +1,36 @@ +import { + Component, + Input, + OnInit, +} from '@angular/core'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + +import { hasValue } from '../../../empty.util'; + +@Component({ + selector: 'ds-search-results-skeleton', + standalone: true, + imports: [ + NgxSkeletonLoaderModule, + ], + templateUrl: './search-results-skeleton.component.html', + styleUrl: './search-results-skeleton.component.scss', +}) +export class SearchResultsSkeletonComponent implements OnInit { + @Input() + showThumbnails: boolean; + + @Input() + numberOfResults = 0; + + public loadingResults: number[]; + + ngOnInit() { + this.loadingResults = Array.from({ length: this.numberOfResults }, (_, i) => i + 1); + + if (!hasValue(this.showThumbnails)) { + // this is needed as the default value of show thumbnails is true but set in lower levels of the DOM. + this.showThumbnails = true; + } + } +} diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 1f1e58ea10..1ad0129d2d 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -19,7 +19,12 @@ (selectObject)="selectObject.emit($event)"> - + +
diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index 4cc4f84f65..cf4bcf61a5 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -7,6 +7,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { SearchResultsComponent } from './search-results.component'; import { QueryParamsDirectiveStub } from '../../testing/query-params-directive.stub'; import { createFailedRemoteDataObject } from '../../remote-data.utils'; +import { SearchResultsSkeletonComponent } from "./search-results-skeleton/search-results-skeleton.component"; describe('SearchResultsComponent', () => { let comp: SearchResultsComponent; @@ -19,6 +20,7 @@ describe('SearchResultsComponent', () => { imports: [TranslateModule.forRoot(), NoopAnimationsModule], declarations: [ SearchResultsComponent, + SearchResultsSkeletonComponent, QueryParamsDirectiveStub], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); diff --git a/src/themes/custom/lazy-theme.module.ts b/src/themes/custom/lazy-theme.module.ts index 73400e7880..1fe476c1e1 100644 --- a/src/themes/custom/lazy-theme.module.ts +++ b/src/themes/custom/lazy-theme.module.ts @@ -159,6 +159,9 @@ import { RequestCopyModule } from 'src/app/request-copy/request-copy.module'; import {UserMenuComponent} from './app/shared/auth-nav-menu/user-menu/user-menu.component'; import { BrowseByComponent } from './app/shared/browse-by/browse-by.component'; import { RegisterEmailFormComponent } from './app/register-email-form/register-email-form.component'; +import { + SearchResultsSkeletonComponent +} from "../../app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component"; const DECLARATIONS = [ FileSectionComponent, @@ -245,6 +248,7 @@ const DECLARATIONS = [ UserMenuComponent, BrowseByComponent, RegisterEmailFormComponent, + SearchResultsSkeletonComponent, ]; @NgModule({ From 6cd092671f1dfd382410517fccd55650db0edf6a Mon Sep 17 00:00:00 2001 From: DSpace Bot <68393067+dspace-bot@users.noreply.github.com> Date: Fri, 24 Jan 2025 09:58:41 -0600 Subject: [PATCH 024/104] [Port dspace-7_x] Improving the color contrast of home news content (#3890) * Improving the color contrast of home news content (cherry picked from commit 2290b871f72acc85dd05955a7e2877f8cea16238) * Improved color contrast (cherry picked from commit 62b6677e04b6ba6578603d1ceb6ae40e967340de) * Adjusting font color changes (cherry picked from commit be335415fd8e62ed108c6652544588c3be46ac88) --------- Co-authored-by: root --- .../dspace/app/home-page/home-news/home-news.component.scss | 6 ++++++ src/themes/dspace/styles/_theme_css_variable_overrides.scss | 2 +- .../dspace/styles/_theme_sass_variable_overrides.scss | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/themes/dspace/app/home-page/home-news/home-news.component.scss b/src/themes/dspace/app/home-page/home-news/home-news.component.scss index 3c3aa8b445..d00b0ec959 100644 --- a/src/themes/dspace/app/home-page/home-news/home-news.component.scss +++ b/src/themes/dspace/app/home-page/home-news/home-news.component.scss @@ -4,6 +4,7 @@ div.background-image-container { color: white; position: relative; + font-weight: 600; .background-image > img { background-color: var(--bs-info); @@ -68,6 +69,11 @@ color: var(--ds-home-news-link-hover-color); } } + + .lead { + font-size: 1.25rem; + font-weight: 400; + } } diff --git a/src/themes/dspace/styles/_theme_css_variable_overrides.scss b/src/themes/dspace/styles/_theme_css_variable_overrides.scss index d016ff4032..8b95cd0033 100644 --- a/src/themes/dspace/styles/_theme_css_variable_overrides.scss +++ b/src/themes/dspace/styles/_theme_css_variable_overrides.scss @@ -11,7 +11,7 @@ --ds-header-height: 90px; } - --ds-banner-text-background: rgba(0, 0, 0, 0.45); + --ds-banner-text-background: rgba(0, 0, 0, 0.58); --ds-banner-background-gradient-width: 300px; --ds-header-navbar-border-bottom-height: 5px; diff --git a/src/themes/dspace/styles/_theme_sass_variable_overrides.scss b/src/themes/dspace/styles/_theme_sass_variable_overrides.scss index 17155b15a1..3750b1f826 100644 --- a/src/themes/dspace/styles/_theme_sass_variable_overrides.scss +++ b/src/themes/dspace/styles/_theme_sass_variable_overrides.scss @@ -83,7 +83,7 @@ $navbar-dark-color: #fff; /*** CUSTOM DSPACE VARIABLES ***/ -$ds-home-news-link-color: #92c642; +$ds-home-news-link-color: #D2FC93; $ds-header-navbar-border-bottom-color: #92c642; $ds-breadcrumb-link-color: #154E66 !default; From 126f3c71f4a2ad5a9f6b52b098ed1317e3c0d935 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Wed, 27 Nov 2024 16:01:41 +0100 Subject: [PATCH 025/104] [DURACOM-303] add skeleton loader for search results and filters --- .../search-filters.component.html | 6 ++++- .../search-filters.component.scss | 10 ++++++- .../search-filters.component.ts | 8 +++++- .../search-results-skeleton.component.html | 18 ++++++++++--- .../search-results-skeleton.component.scss | 27 +++++++++++++++++++ .../search-results-skeleton.component.ts | 3 +++ .../search-results.component.html | 2 +- src/app/shared/search/search.component.ts | 3 +++ src/config/search-page-config.interface.ts | 16 +++++++++++ src/styles/_custom_variables.scss | 11 ++++++++ .../styles/_theme_css_variable_overrides.scss | 1 + 11 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/config/search-page-config.interface.ts diff --git a/src/app/shared/search/search-filters/search-filters.component.html b/src/app/shared/search/search-filters/search-filters.component.html index c006d80c44..97f8c75234 100644 --- a/src/app/shared/search/search-filters/search-filters.component.html +++ b/src/app/shared/search/search-filters/search-filters.component.html @@ -1,7 +1,11 @@

{{"search.filters.head" | translate}}

-
+
+ + + + {{"search.filters.reset" | translate}} diff --git a/src/app/shared/search/search-filters/search-filters.component.scss b/src/app/shared/search/search-filters/search-filters.component.scss index b5b2816e89..a103119daf 100644 --- a/src/app/shared/search/search-filters/search-filters.component.scss +++ b/src/app/shared/search/search-filters/search-filters.component.scss @@ -1,2 +1,10 @@ @import '../../../../styles/variables'; -@import '../../../../styles/mixins'; \ No newline at end of file +@import '../../../../styles/mixins'; + +:host ::ng-deep { + ngx-skeleton-loader .skeleton-loader { + height: var(--ds-filters-skeleton-height); + margin-bottom: var(--ds-filters-skeleton-spacing); + padding: var(--ds-filters-skeleton-spacing); + } +} diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 766939226d..c960dfda56 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -12,6 +12,7 @@ import { SearchFilterService } from '../../../core/shared/search/search-filter.s import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../utils/route.utils'; import { hasValue } from '../../empty.util'; +import { APP_CONFIG, AppConfig } from "../../../../config/app-config.interface"; @Component({ selector: 'ds-search-filters', @@ -61,6 +62,7 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { searchLink: string; subs = []; + defaultFilterCount: number; /** * Initialize instance variables @@ -68,12 +70,16 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { * @param {SearchFilterService} filterService * @param {Router} router * @param {SearchConfigurationService} searchConfigService + * @param appConfig */ constructor( private searchService: SearchService, private filterService: SearchFilterService, private router: Router, - @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) { + @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, + @Inject(APP_CONFIG) protected appConfig: AppConfig, + ) { + this.defaultFilterCount = this.appConfig.search.defaultFilterCount ?? 5; } ngOnInit(): void { diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 33f05985e1..5972a54dc4 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -1,12 +1,24 @@ +
+
+ +
+
+ @for (result of loadingResults; track result) {
@if(showThumbnails) { - +
+ +
}
- - +
+ +
+
+ +
} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index e69de29bb2..c982d14fb0 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -0,0 +1,27 @@ +:host ::ng-deep { + .info-skeleton, .badge-skeleton, .text-skeleton{ + ngx-skeleton-loader .skeleton-loader { + height: var(--ds-search-skeleton-text-height); + } + } + + .badge-skeleton, .info-skeleton { + ngx-skeleton-loader .skeleton-loader { + width: var(--ds-search-skeleton-badge-width); + } + } + + .info-skeleton { + ngx-skeleton-loader .skeleton-loader { + width: var(--ds-search-skeleton-info-width); + } + } + + .thumbnail-skeleton { + ngx-skeleton-loader .skeleton-loader { + width: var(--ds-search-skeleton-thumbnail-width); + height: var(--ds-search-skeleton-thumbnail-height); + padding: var(--ds-search-skeleton-thumbnail-padding); + } + } +} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index d35c5d1733..fef1529460 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -23,6 +23,9 @@ export class SearchResultsSkeletonComponent implements OnInit { @Input() numberOfResults = 0; + @Input() + textLineCount = 2; + public loadingResults: number[]; ngOnInit() { diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 1ad0129d2d..a190b64752 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -20,7 +20,7 @@
diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 6040a47d6e..362257be0e 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -315,6 +315,9 @@ export class SearchComponent implements OnDestroy, OnInit { */ ngOnInit(): void { if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + this.subs.push(this.getSearchOptions().pipe(distinctUntilChanged()).subscribe((options) => { + this.searchOptions$.next(options); + })); this.initialized$.next(true); return; } diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts new file mode 100644 index 0000000000..7d582866e7 --- /dev/null +++ b/src/config/search-page-config.interface.ts @@ -0,0 +1,16 @@ +import { AdvancedSearchConfig } from './advance-search-config.interface'; +import { Config } from './config.interface'; + +export interface SearchConfig extends Config { + + /** + * List of standard filter to select in adding advanced Search + * Used by {@link UploadBitstreamComponent}. + */ + advancedFilters: AdvancedSearchConfig; + /** + * Number used to render n skeletons while the filters are loading + */ + defaultFilterCount?: number; + +} diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index aa67acac1c..96db246079 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -138,4 +138,15 @@ --green1: #1FB300; // This variable represents the success color for the Klaro cookie banner --button-text-color-cookie: #333; // This variable represents the text color for buttons in the Klaro cookie banner --very-dark-cyan: #215E50; // This variable represents the background color of the save cookies button + + --ds-search-skeleton-text-height: 20px; + --ds-search-skeleton-thumbnail-height: 100px; + --ds-search-skeleton-thumbnail-width: 120px; + --ds-search-skeleton-thumbnail-padding: 1em; + --ds-search-skeleton-text-line-count: 2; + --ds-search-skeleton-badge-width: 75px; + --ds-search-skeleton-info-width: 200px; + + --ds-filters-skeleton-height: 40px; + --ds-filters-skeleton-spacing: 12px; } diff --git a/src/themes/dspace/styles/_theme_css_variable_overrides.scss b/src/themes/dspace/styles/_theme_css_variable_overrides.scss index d016ff4032..5978eadb28 100644 --- a/src/themes/dspace/styles/_theme_css_variable_overrides.scss +++ b/src/themes/dspace/styles/_theme_css_variable_overrides.scss @@ -18,6 +18,7 @@ /* set the next two properties as `--ds-header-navbar-border-bottom-*` in order to keep the bottom border of the header when navbar is expanded */ + --ds-expandable-navbar-border-top-color: #{$white}; --ds-expandable-navbar-border-top-height: 0; --ds-expandable-navbar-padding-top: 0; From 61eb14783e3995fe2beede1801b1027a62032f0b Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:03:47 +0100 Subject: [PATCH 026/104] [DURACOM-303] resolve conflicts --- src/config/app-config.interface.ts | 2 ++ src/config/default-app-config.ts | 5 +++++ src/config/search-page-config.interface.ts | 7 ------- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/config/app-config.interface.ts b/src/config/app-config.interface.ts index a2bf0cb876..8b8dcf74a7 100644 --- a/src/config/app-config.interface.ts +++ b/src/config/app-config.interface.ts @@ -23,6 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; +import { SearchConfig } from "./search-page-config.interface"; interface AppConfig extends Config { ui: UIServerConfig; @@ -50,6 +51,7 @@ interface AppConfig extends Config { vocabularies: FilterVocabularyConfig[]; comcolSelectionSort: DiscoverySortConfig; liveRegion: LiveRegionConfig; + search: SearchConfig } /** diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index a3a490538c..0915f90069 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -23,6 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; +import { SearchConfig } from "./search-page-config.interface"; export class DefaultAppConfig implements AppConfig { production = false; @@ -442,4 +443,8 @@ export class DefaultAppConfig implements AppConfig { messageTimeOutDurationMs: 30000, isVisible: false, }; + + search: SearchConfig = { + defaultFilterCount: 2 + } } diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts index 7d582866e7..cc63607f7f 100644 --- a/src/config/search-page-config.interface.ts +++ b/src/config/search-page-config.interface.ts @@ -1,13 +1,6 @@ -import { AdvancedSearchConfig } from './advance-search-config.interface'; import { Config } from './config.interface'; export interface SearchConfig extends Config { - - /** - * List of standard filter to select in adding advanced Search - * Used by {@link UploadBitstreamComponent}. - */ - advancedFilters: AdvancedSearchConfig; /** * Number used to render n skeletons while the filters are loading */ From d6f0f02c1aaf437126289ac6ed0180ea266ac8ab Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 28 Nov 2024 13:54:48 +0100 Subject: [PATCH 027/104] [DURACOM-303] minor restyle of skeleton for mobile --- .../search-results-skeleton.component.html | 6 +++--- .../search-results-skeleton.component.scss | 5 +++++ .../search/search-results/search-results.component.html | 2 +- src/config/default-app-config.ts | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 5972a54dc4..4bc70d1263 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -1,11 +1,11 @@ -
-
+
+
@for (result of loadingResults; track result) { -
+
@if(showThumbnails) {
diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index c982d14fb0..02711a33b6 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -25,3 +25,8 @@ } } } + +.result-row { + margin-right: 0; + margin-left: 0; +} diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index a190b64752..1ad0129d2d 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -20,7 +20,7 @@
diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 0915f90069..7ed4168217 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -445,6 +445,6 @@ export class DefaultAppConfig implements AppConfig { }; search: SearchConfig = { - defaultFilterCount: 2 + defaultFilterCount: 5 } } From 312a2a7f58decb141822c81fc5e4c86b10331f2f Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 28 Nov 2024 15:01:00 +0100 Subject: [PATCH 028/104] [DURACOM-303] fix lint and tests --- .../search/search-filters/search-filters.component.spec.ts | 4 +++- .../search/search-results/search-results.component.spec.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/shared/search/search-filters/search-filters.component.spec.ts b/src/app/shared/search/search-filters/search-filters.component.spec.ts index 522459b603..c8ad89910c 100644 --- a/src/app/shared/search/search-filters/search-filters.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filters.component.spec.ts @@ -9,6 +9,8 @@ import { SearchFiltersComponent } from './search-filters.component'; import { SearchService } from '../../../core/shared/search/search.service'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; +import { APP_CONFIG } from "../../../../config/app-config.interface"; +import { environment } from "../../../../environments/environment"; describe('SearchFiltersComponent', () => { let comp: SearchFiltersComponent; @@ -37,7 +39,7 @@ describe('SearchFiltersComponent', () => { { provide: SearchService, useValue: searchServiceStub }, { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: SearchFilterService, useValue: searchFiltersStub }, - + { provide: APP_CONFIG, useValue: environment }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(SearchFiltersComponent, { diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index cf4bcf61a5..dc961c97cb 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -65,7 +65,7 @@ describe('SearchResultsComponent', () => { it('should display link with new search where query is quoted if search return a error 400', () => { (comp as any).searchResults = createFailedRemoteDataObject('Error', 400); - (comp as any).searchConfig = { query: 'foobar' }; + (comp as any).searchConfig = { query: 'foobar', pagination: { pageSize: 10 } }; fixture.detectChanges(); const linkDes = fixture.debugElement.queryAll(By.directive(QueryParamsDirectiveStub)); From b482b58d530b946b4e3376acb406e1ee04c68059 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 20 Dec 2024 15:36:06 +0100 Subject: [PATCH 029/104] [DURACOM-303] adapt tests --- .../browse-by-date-page.component.spec.ts | 12 ++++++------ .../browse-by-title-page.component.spec.ts | 17 ++++++++++------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index d94e7df04f..2fe673f821 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -140,12 +140,12 @@ describe('BrowseByDatePageComponent', () => { describe('when rendered in SSR', () => { beforeEach(() => { comp.platformId = 'server'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + spyOn((comp as any).browseService, 'getBrowseItemsFor'); }); - it('should not call getBrowseEntriesFor on init', (done) => { + it('should not call getBrowseItemsFor on init', (done) => { comp.ngOnInit(); - expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).not.toHaveBeenCalled(); comp.loading$.subscribe((res) => { expect(res).toBeFalsy(); done(); @@ -156,13 +156,13 @@ describe('BrowseByDatePageComponent', () => { describe('when rendered in CSR', () => { beforeEach(() => { comp.platformId = 'browser'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + spyOn((comp as any).browseService, 'getBrowseItemsFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); }); - it('should call getBrowseEntriesFor on init', fakeAsync(() => { + it('should call getBrowseItemsFor on init', fakeAsync(() => { comp.ngOnInit(); tick(100); - expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).toHaveBeenCalled(); })); }); }); diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts index 9c9586032d..653ad596c5 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts @@ -64,7 +64,8 @@ describe('BrowseByTitlePageComponent', () => { const activatedRouteStub = Object.assign(new ActivatedRouteStub(), { params: observableOf({}), - data: observableOf({ metadata: 'title' }) + queryParams: observableOf({}), + data: observableOf({ metadata: 'title' }), }); const paginationService = new PaginationServiceStub(); @@ -102,12 +103,13 @@ describe('BrowseByTitlePageComponent', () => { describe('when rendered in SSR', () => { beforeEach(() => { comp.platformId = 'server'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + spyOn((comp as any).browseService, 'getBrowseItemsFor'); + fixture.detectChanges(); }); - it('should not call getBrowseEntriesFor on init', (done) => { + it('should not call getBrowseItemsFor on init', (done) => { comp.ngOnInit(); - expect((comp as any).browseService.getBrowseEntriesFor).not.toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).not.toHaveBeenCalled(); comp.loading$.subscribe((res) => { expect(res).toBeFalsy(); done(); @@ -118,13 +120,14 @@ describe('BrowseByTitlePageComponent', () => { describe('when rendered in CSR', () => { beforeEach(() => { comp.platformId = 'browser'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + fixture.detectChanges(); + spyOn((comp as any).browseService, 'getBrowseItemsFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); }); - it('should call getBrowseEntriesFor on init', fakeAsync(() => { + it('should call getBrowseItemsFor on init', fakeAsync(() => { comp.ngOnInit(); tick(100); - expect((comp as any).browseService.getBrowseEntriesFor).toHaveBeenCalled(); + expect((comp as any).browseService.getBrowseItemsFor).toHaveBeenCalled(); })); }); }); From 6756a78ba03944a8ee28a582a89480fd2a3fc3e4 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 12:01:50 +0100 Subject: [PATCH 030/104] [DURACOM-303] restyle skeleton, add filter badge skeleton --- .../search-filters/search-filters.component.scss | 2 ++ .../search-results-skeleton.component.scss | 7 +++++++ .../search-results/search-results.component.html | 11 +++++++++++ .../search-results/search-results.component.scss | 10 ++++++++++ .../search/search-results/search-results.component.ts | 9 +++++++++ src/styles/_custom_variables.scss | 6 ++++-- 6 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/app/shared/search/search-results/search-results.component.scss diff --git a/src/app/shared/search/search-filters/search-filters.component.scss b/src/app/shared/search/search-filters/search-filters.component.scss index a103119daf..6170b9281c 100644 --- a/src/app/shared/search/search-filters/search-filters.component.scss +++ b/src/app/shared/search/search-filters/search-filters.component.scss @@ -6,5 +6,7 @@ height: var(--ds-filters-skeleton-height); margin-bottom: var(--ds-filters-skeleton-spacing); padding: var(--ds-filters-skeleton-spacing); + background-color: var(--bs-light); + box-shadow: none; } } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index 02711a33b6..1a111f9dd9 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -22,8 +22,15 @@ width: var(--ds-search-skeleton-thumbnail-width); height: var(--ds-search-skeleton-thumbnail-height); padding: var(--ds-search-skeleton-thumbnail-padding); + margin-right: var(--ds-search-skeleton-thumbnail-margin); + border-radius: 0; } } + + ngx-skeleton-loader .skeleton-loader { + background-color: var(--bs-light); + box-shadow: none; + } } .result-row { diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 1ad0129d2d..d812561ea7 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,3 +1,13 @@ +@if ((filters$ | async).length > 0 && isLoading()) { +
+
+
+ +
+
+
+} +

{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}

@@ -19,6 +29,7 @@ (selectObject)="selectObject.emit($event)">
+ ; + /** * The link type of the listed search results */ @@ -104,6 +109,10 @@ export class SearchResultsComponent { @Output() selectObject: EventEmitter = new EventEmitter(); + constructor(private searchConfigService: SearchConfigurationService) { + this.filters$ = this.searchConfigService.getCurrentFilters(); + } + /** * Check if search results are loading */ diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 96db246079..d64f1c6acd 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -140,11 +140,13 @@ --very-dark-cyan: #215E50; // This variable represents the background color of the save cookies button --ds-search-skeleton-text-height: 20px; - --ds-search-skeleton-thumbnail-height: 100px; - --ds-search-skeleton-thumbnail-width: 120px; + --ds-search-skeleton-thumbnail-height: 125px; + --ds-search-skeleton-thumbnail-width: 90px; --ds-search-skeleton-thumbnail-padding: 1em; + --ds-search-skeleton-thumbnail-margin: 1em; --ds-search-skeleton-text-line-count: 2; --ds-search-skeleton-badge-width: 75px; + --ds-search-skeleton-filter-badge-width: 200px; --ds-search-skeleton-info-width: 200px; --ds-filters-skeleton-height: 40px; From 8ee05f43521462b85f041c1c903f5eb7f52d94bd Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:11:13 +0100 Subject: [PATCH 031/104] [DURACOM-303] fix missing url link --- src/app/shared/search/search-results/search-results.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index e4ebf2819b..296d73f9d8 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -22,6 +22,7 @@ export interface SelectionConfig { @Component({ selector: 'ds-search-results', + styleUrls: ['./search-results.component.scss'], templateUrl: './search-results.component.html', animations: [ fadeIn, From 99656f1357438695385820f2c95d4ca5a58993b9 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 12:54:40 +0100 Subject: [PATCH 032/104] [DURACOM-303] add loop for filters count --- .../search/search-results/search-results.component.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index d812561ea7..643cf5eb4b 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,8 +1,12 @@ @if ((filters$ | async).length > 0 && isLoading()) {
-
- +
+ @for (filter of (filters$| async); track filter.key) { +
+ +
+ }
From 9467838066cb48906dcda334919f468fea59efbe Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 18:08:20 +0100 Subject: [PATCH 033/104] [DURACOM-303] add grid layout, make SSR enabling configurable, minor restyle of skeletons --- config/config.example.yml | 12 +++++- .../browse-by-metadata-page.component.ts | 4 +- .../search-filter/search-filter.component.ts | 7 +++- .../search-filters.component.html | 9 +++-- .../search-filters.component.ts | 11 +++++ .../search-results-skeleton.component.html | 40 ++++++++++++------- .../search-results-skeleton.component.scss | 20 ++++++++++ .../search-results-skeleton.component.ts | 17 ++++++++ .../search-results.component.html | 10 ++--- .../search-results.component.scss | 9 ++++- .../search-results.component.ts | 6 ++- src/app/shared/search/search.component.ts | 2 + src/environments/environment.production.ts | 4 +- src/environments/environment.test.ts | 2 + src/environments/environment.ts | 4 +- src/styles/_custom_variables.scss | 2 + 16 files changed, 127 insertions(+), 32 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index c1d7f967a4..0a039a40ad 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -25,6 +25,14 @@ ssr: inlineCriticalCss: false # Path prefixes to enable SSR for. By default these are limited to paths of primary DSpace objects. paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ] + # Whether to enable rendering of Search component on SSR. + # If set to true the component will be included in the HTML returned from the server side rendering. + # If set to false the component will not be included in the HTML returned from the server side rendering. + enableSearchComponent: false, + # Whether to enable rendering of Browse component on SSR. + # If set to true the component will be included in the HTML returned from the server side rendering. + # If set to false the component will not be included in the HTML returned from the server side rendering. + enableBrowseComponent: false, # The REST API server settings # NOTE: these settings define which (publicly available) REST API to use. They are usually @@ -84,7 +92,7 @@ cache: anonymousCache: # Maximum number of pages to cache. Default is zero (0) which means anonymous user cache is disabled. # As all pages are cached in server memory, increasing this value will increase memory needs. - # Individual cached pages are usually small (<100KB), so a value of max=1000 would only require ~100MB of memory. + # Individual cached pages are usually small (<100KB), so a value of max=1000 would only require ~100MB of memory. max: 0 # Amount of time after which cached pages are considered stale (in ms). After becoming stale, the cached # copy is automatically refreshed on the next request. @@ -394,7 +402,7 @@ vocabularies: vocabulary: 'srsc' enabled: true -# Default collection/community sorting order at Advanced search, Create/update community and collection when there are not a query. +# Default collection/community sorting order at Advanced search, Create/update community and collection when there are not a query. comcolSelectionSort: sortField: 'dc.title' sortDirection: 'ASC' diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index e18841f9ca..7f14f45b2c 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -23,6 +23,7 @@ import { Community } from '../../core/shared/community.model'; import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { isPlatformServer } from "@angular/common"; +import { environment } from "../../../environments/environment"; export const BBM_PAGINATION_ID = 'bbm'; @@ -147,7 +148,8 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); - } + this.renderOnServerSide = environment.ssr.enableBrowseComponent; + } ngOnInit(): void { diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts index 67e8906bb5..6f88d3924a 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core'; import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; @@ -43,6 +43,8 @@ export class SearchFilterComponent implements OnInit { */ @Input() scope: string; + @Output() isVisibilityComputed = new EventEmitter(); + /** * True when the filter is 100% collapsed in the UI */ @@ -99,6 +101,9 @@ export class SearchFilterComponent implements OnInit { this.filterService.expand(this.filter.name); } }); + this.active$.pipe(take(1)).subscribe(() => { + this.isVisibilityComputed.emit(true); + }) } /** diff --git a/src/app/shared/search/search-filters/search-filters.component.html b/src/app/shared/search/search-filters/search-filters.component.html index 97f8c75234..45875ad7ae 100644 --- a/src/app/shared/search/search-filters/search-filters.component.html +++ b/src/app/shared/search/search-filters/search-filters.component.html @@ -1,11 +1,12 @@

{{"search.filters.head" | translate}}

-
+
- +
- + + - + {{"search.filters.reset" | translate}} diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index c960dfda56..28f351cb6c 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -61,6 +61,11 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { */ searchLink: string; + /** + * Filters for which visibility has been computed + */ + filtersWithComputedVisibility = 0; + subs = []; defaultFilterCount: number; @@ -114,4 +119,10 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { } }); } + + countFiltersWithComputedVisibility(computed: boolean) { + if (computed) { + this.filtersWithComputedVisibility += 1; + } + } } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 4bc70d1263..84a67f4358 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -1,24 +1,36 @@
-
+
-@for (result of loadingResults; track result) { -
- @if(showThumbnails) { -
- +@if((viewMode$ | async) === ViewMode.ListElement) { + @for (result of loadingResults; track result) { +
+ @if(showThumbnails) { +
+ +
+ } +
+
+ +
+
+ +
+
+
+ } +} @else if ((viewMode$ | async) === ViewMode.GridElement) { +
+ @for (result of loadingResults; track result) { +
+
+ +
} -
-
- -
-
- -
-
} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index 1a111f9dd9..e05e4be6d8 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -1,4 +1,6 @@ :host ::ng-deep { + --ds-wrapper-grid-spacing: calc(var(--bs-spacer) / 2); + .info-skeleton, .badge-skeleton, .text-skeleton{ ngx-skeleton-loader .skeleton-loader { height: var(--ds-search-skeleton-text-height); @@ -27,13 +29,31 @@ } } + .card-skeleton { + ngx-skeleton-loader .skeleton-loader { + height: var(--ds-search-skeleton-card-height); + } + } + ngx-skeleton-loader .skeleton-loader { background-color: var(--bs-light); box-shadow: none; } + + .card-columns { + margin-left: calc(-1 * var(--ds-wrapper-grid-spacing)); + margin-right: calc(-1 * var(--ds-wrapper-grid-spacing)); + column-gap: 0; + + .card-column { + padding-left: var(--ds-wrapper-grid-spacing); + padding-right: var(--ds-wrapper-grid-spacing); + } + } } .result-row { margin-right: 0; margin-left: 0; } + diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index fef1529460..d2896460e1 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -1,10 +1,17 @@ +import { + AsyncPipe, + NgForOf, +} from '@angular/common'; import { Component, Input, OnInit, } from '@angular/core'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { Observable } from 'rxjs'; +import { SearchService } from '../../../../core/shared/search/search.service'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; import { hasValue } from '../../../empty.util'; @Component({ @@ -12,6 +19,8 @@ import { hasValue } from '../../../empty.util'; standalone: true, imports: [ NgxSkeletonLoaderModule, + AsyncPipe, + NgForOf, ], templateUrl: './search-results-skeleton.component.html', styleUrl: './search-results-skeleton.component.scss', @@ -26,8 +35,16 @@ export class SearchResultsSkeletonComponent implements OnInit { @Input() textLineCount = 2; + public viewMode$: Observable; + public loadingResults: number[]; + protected readonly ViewMode = ViewMode; + + constructor(private searchService: SearchService) { + this.viewMode$ = searchService.getViewMode(); + } + ngOnInit() { this.loadingResults = Array.from({ length: this.numberOfResults }, (_, i) => i + 1); diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 643cf5eb4b..71839d009b 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,12 +1,10 @@ -@if ((filters$ | async).length > 0 && isLoading()) { +@if ((activeFilters$ | async).length > 0 && (appliedFilters$ | async).length === 0) {
-
- @for (filter of (filters$| async); track filter.key) { -
- +
+
+
- }
diff --git a/src/app/shared/search/search-results/search-results.component.scss b/src/app/shared/search/search-results/search-results.component.scss index 4bf3f8325e..6e369c729b 100644 --- a/src/app/shared/search/search-results/search-results.component.scss +++ b/src/app/shared/search/search-results/search-results.component.scss @@ -4,7 +4,14 @@ background-color: var(--bs-light); box-shadow: none; width: var(--ds-search-skeleton-filter-badge-width); - height: var(--ds-search-skeleton-text-height); + height: var(--ds-search-skeleton-badge-height); + margin-bottom: 0; + margin-right: calc(var(--bs-spacer) / 4); } } + + .filters-badge-skeleton-container { + display: flex; + max-height: var(--ds-search-skeleton-badge-height); + } } diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index 296d73f9d8..1faf8dd778 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -14,6 +14,7 @@ import { PaginatedSearchOptions } from '../models/paginated-search-options.model import { SearchFilter } from "../models/search-filter.model"; import { Observable } from "rxjs"; import { SearchConfigurationService } from "../../../core/shared/search/search-configuration.service"; +import { SearchService } from "../../../core/shared/search/search.service"; export interface SelectionConfig { repeatable: boolean; @@ -110,7 +111,10 @@ export class SearchResultsComponent { @Output() selectObject: EventEmitter = new EventEmitter(); - constructor(private searchConfigService: SearchConfigurationService) { + constructor( + protected searchConfigService: SearchConfigurationService, + protected searchService: SearchService, + ) { this.filters$ = this.searchConfigService.getCurrentFilters(); } diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 362257be0e..1e8811aa86 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -49,6 +49,7 @@ import { COLLECTION_MODULE_PATH } from '../../collection-page/collection-page-ro import { COMMUNITY_MODULE_PATH } from '../../community-page/community-page-routing-paths'; import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; import { isPlatformServer } from "@angular/common"; +import { environment } from 'src/environments/environment'; @Component({ selector: 'ds-search', @@ -304,6 +305,7 @@ export class SearchComponent implements OnDestroy, OnInit { @Inject(PLATFORM_ID) public platformId: any, ) { this.isXsOrSm$ = this.windowService.isXsOrSm(); + this.renderOnServerSide = environment.universal.enableSearchComponent; } /** diff --git a/src/environments/environment.production.ts b/src/environments/environment.production.ts index 46a93519df..c3cb74651b 100644 --- a/src/environments/environment.production.ts +++ b/src/environments/environment.production.ts @@ -10,5 +10,7 @@ export const environment: Partial = { time: false, inlineCriticalCss: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], - } + enableSearchComponent: false, + enableBrowseComponent: false, + }, }; diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index e872285f61..ea49f5eb10 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -13,6 +13,8 @@ export const environment: BuildConfig = { time: false, inlineCriticalCss: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], + enableSearchComponent: false, + enableBrowseComponent: false, }, // Angular Universal server settings. diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 25af371e47..419238f264 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -15,7 +15,9 @@ export const environment: Partial = { time: false, inlineCriticalCss: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], - } + enableSearchComponent: false, + enableBrowseComponent: false, + }, }; /* diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index d64f1c6acd..d47f5d2dfa 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -140,6 +140,7 @@ --very-dark-cyan: #215E50; // This variable represents the background color of the save cookies button --ds-search-skeleton-text-height: 20px; + --ds-search-skeleton-badge-height: 18px; --ds-search-skeleton-thumbnail-height: 125px; --ds-search-skeleton-thumbnail-width: 90px; --ds-search-skeleton-thumbnail-padding: 1em; @@ -148,6 +149,7 @@ --ds-search-skeleton-badge-width: 75px; --ds-search-skeleton-filter-badge-width: 200px; --ds-search-skeleton-info-width: 200px; + --ds-search-skeleton-card-height: 435px; --ds-filters-skeleton-height: 40px; --ds-filters-skeleton-spacing: 12px; From 53335658e0874b84841473307d9cd546bd369962 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:29:37 +0100 Subject: [PATCH 034/104] [DURACOM-303] adapt interface for ssr --- .../browse-by-metadata-page.component.ts | 2 +- src/config/universal-config.interface.ts | 9 +++++++++ src/environments/environment.test.ts | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 7f14f45b2c..06a29aad1a 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -148,7 +148,7 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); - this.renderOnServerSide = environment.ssr.enableBrowseComponent; + this.renderOnServerSide = environment.universal.enableBrowseComponent; } diff --git a/src/config/universal-config.interface.ts b/src/config/universal-config.interface.ts index e54168823f..e3f7f399a9 100644 --- a/src/config/universal-config.interface.ts +++ b/src/config/universal-config.interface.ts @@ -18,4 +18,13 @@ export interface UniversalConfig extends Config { * Paths to enable SSR for. Defaults to the home page and paths in the sitemap. */ paths: Array; + /** + * Whether to enable rendering of search component on SSR + */ + enableSearchComponent: boolean; + + /** + * Whether to enable rendering of browse component on SSR + */ + enableBrowseComponent: boolean; } diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index ea49f5eb10..4f832e1ac4 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -323,4 +323,8 @@ export const environment: BuildConfig = { messageTimeOutDurationMs: 30000, isVisible: false, }, + + search: { + defaultFilterCount: 5 + } }; From 2c28f7526366450022d7533e1952463fdc31ce52 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 10 Jan 2025 18:20:58 +0100 Subject: [PATCH 035/104] [DURACOM-303] refactor param, add example of configuration --- config/config.example.yml | 9 +++++++++ .../search/search-filters/search-filters.component.ts | 2 +- src/config/search-page-config.interface.ts | 5 ++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index 0a039a40ad..6674bc5334 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -420,3 +420,12 @@ liveRegion: messageTimeOutDurationMs: 30000 # The visibility of the live region. Setting this to true is only useful for debugging purposes. isVisible: false + + +# Search settings +search: + # Number used to render n UI elements called loading skeletons that act as placeholders. + # These elements indicate that some content will be loaded in their stead. + # Since we don't know how many filters will be loaded before we receive a response from the server we use this parameter for the skeletons count. + # e.g. If we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. + defaultFiltersCount: 5 diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 28f351cb6c..4667694edd 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -84,7 +84,7 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, @Inject(APP_CONFIG) protected appConfig: AppConfig, ) { - this.defaultFilterCount = this.appConfig.search.defaultFilterCount ?? 5; + this.defaultFilterCount = this.appConfig.search.defaultFiltersCount ?? 5; } ngOnInit(): void { diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts index cc63607f7f..0f4a145868 100644 --- a/src/config/search-page-config.interface.ts +++ b/src/config/search-page-config.interface.ts @@ -2,7 +2,10 @@ import { Config } from './config.interface'; export interface SearchConfig extends Config { /** - * Number used to render n skeletons while the filters are loading + * Number used to render n UI elements called loading skeletons that act as placeholders. + * These elements indicate that some content will be loaded in their stead. + * Since we don't know how many filters will be loaded before we receive a response from the server we use this parameter for the skeletons count. + * For instance f we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. */ defaultFilterCount?: number; From 311f648c3f8707fdaa8124a9ddb355e7ff227876 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 13 Jan 2025 10:51:53 +0100 Subject: [PATCH 036/104] [DURACOM-303] rename variable, minor code refactor --- .../shared/search/search-filters/search-filters.component.ts | 2 +- .../search-results-skeleton.component.spec.ts | 5 +++++ .../search-results-skeleton.component.ts | 2 +- src/app/shared/testing/search-configuration-service.stub.ts | 4 ++++ src/config/default-app-config.ts | 2 +- src/config/search-page-config.interface.ts | 4 ++-- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 4667694edd..1f08a5ac5d 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -84,7 +84,7 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, @Inject(APP_CONFIG) protected appConfig: AppConfig, ) { - this.defaultFilterCount = this.appConfig.search.defaultFiltersCount ?? 5; + this.defaultFilterCount = this.appConfig.search.filterPlaceholdersCount ?? 5; } ngOnInit(): void { diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts index 0ec74eb946..68c8db5a8e 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts @@ -4,6 +4,8 @@ import { } from '@angular/core/testing'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { SearchService } from '../../../../core/shared/search/search.service'; +import { SearchServiceStub } from '../../../testing/search-service.stub'; import { SearchResultsSkeletonComponent } from './search-results-skeleton.component'; describe('SearchResultsSkeletonComponent', () => { @@ -13,6 +15,9 @@ describe('SearchResultsSkeletonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [SearchResultsSkeletonComponent, NgxSkeletonLoaderModule], + providers: [ + { provide: SearchService, useValue: new SearchServiceStub() }, + ], }) .compileComponents(); diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index d2896460e1..28a603cfa3 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -42,7 +42,7 @@ export class SearchResultsSkeletonComponent implements OnInit { protected readonly ViewMode = ViewMode; constructor(private searchService: SearchService) { - this.viewMode$ = searchService.getViewMode(); + this.viewMode$ = this.searchService.getViewMode(); } ngOnInit() { diff --git a/src/app/shared/testing/search-configuration-service.stub.ts b/src/app/shared/testing/search-configuration-service.stub.ts index 78b358f0d4..ef72e40041 100644 --- a/src/app/shared/testing/search-configuration-service.stub.ts +++ b/src/app/shared/testing/search-configuration-service.stub.ts @@ -13,6 +13,10 @@ export class SearchConfigurationServiceStub { return observableOf([]); } + getCurrentFilters() { + return observableOf([]); + } + getCurrentScope(a) { return observableOf('test-id'); } diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 7ed4168217..2384942e3b 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -445,6 +445,6 @@ export class DefaultAppConfig implements AppConfig { }; search: SearchConfig = { - defaultFilterCount: 5 + filterPlaceholdersCount: 5 } } diff --git a/src/config/search-page-config.interface.ts b/src/config/search-page-config.interface.ts index 0f4a145868..410876cde2 100644 --- a/src/config/search-page-config.interface.ts +++ b/src/config/search-page-config.interface.ts @@ -5,8 +5,8 @@ export interface SearchConfig extends Config { * Number used to render n UI elements called loading skeletons that act as placeholders. * These elements indicate that some content will be loaded in their stead. * Since we don't know how many filters will be loaded before we receive a response from the server we use this parameter for the skeletons count. - * For instance f we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. + * For instance if we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. */ - defaultFilterCount?: number; + filterPlaceholdersCount?: number; } From 32364e4f68e8153ecb1143bc9d2827a9789d6f16 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 13 Jan 2025 17:31:12 +0100 Subject: [PATCH 037/104] [DURACOM-303] add override possibility with input --- .../browse-by-metadata-page.component.ts | 3 +-- src/app/shared/search/search.component.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 06a29aad1a..5575b153db 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -148,12 +148,11 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); - this.renderOnServerSide = environment.universal.enableBrowseComponent; } ngOnInit(): void { - if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { this.loading$ = observableOf(false); return; } diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index 1e8811aa86..e69a183408 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -305,7 +305,6 @@ export class SearchComponent implements OnDestroy, OnInit { @Inject(PLATFORM_ID) public platformId: any, ) { this.isXsOrSm$ = this.windowService.isXsOrSm(); - this.renderOnServerSide = environment.universal.enableSearchComponent; } /** @@ -316,7 +315,7 @@ export class SearchComponent implements OnDestroy, OnInit { * If something changes, update the list of scopes for the dropdown */ ngOnInit(): void { - if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + if (!this.renderOnServerSide && !environment.universal.enableSearchComponent && isPlatformServer(this.platformId)) { this.subs.push(this.getSearchOptions().pipe(distinctUntilChanged()).subscribe((options) => { this.searchOptions$.next(options); })); From 8a4e8f60451ef83c8f5f9ee95f1c874424408a73 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 20 Jan 2025 13:16:36 +0100 Subject: [PATCH 038/104] [DURACOM-303] fix SSR check on template and on components missing the environment config. Add descriptive comment for skeleton component. Fix JS error on SSR. --- .../browse-by-date-page/browse-by-date-page.component.ts | 3 ++- .../browse-by-metadata-page.component.spec.ts | 6 +++--- .../browse-by-metadata-page.component.ts | 7 ++++++- .../search-results-skeleton.component.ts | 3 +++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 62bba4d86c..86a2f3dfa3 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -20,6 +20,7 @@ import { RemoteData } from '../../core/data/remote-data'; import { Item } from '../../core/shared/item.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { isPlatformServer } from "@angular/common"; +import { environment } from "../../../environments/environment"; @Component({ selector: 'ds-browse-by-date-page', @@ -52,7 +53,7 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { } ngOnInit(): void { - if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { this.loading$ = observableOf(false); return; } diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts index 8eda34cd62..4ea68eaa0c 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec.ts @@ -228,8 +228,8 @@ describe('BrowseByMetadataPageComponent', () => { describe('when rendered in SSR', () => { beforeEach(() => { - comp.platformId = 'server'; - spyOn((comp as any).browseService, 'getBrowseEntriesFor'); + comp.ssrRenderingDisabled = true; + spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(null)); }); it('should not call getBrowseEntriesFor on init', (done) => { @@ -244,7 +244,7 @@ describe('BrowseByMetadataPageComponent', () => { describe('when rendered in CSR', () => { beforeEach(() => { - comp.platformId = 'browser'; + comp.ssrRenderingDisabled = false; spyOn((comp as any).browseService, 'getBrowseEntriesFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); }); diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 5575b153db..a7357aaaf3 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -131,6 +131,10 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { * Observable determining if the loading animation needs to be shown */ loading$ = observableOf(true); + /** + * Whether this component should be rendered or not in SSR + */ + ssrRenderingDisabled = false; public constructor(protected route: ActivatedRoute, protected browseService: BrowseService, @@ -148,11 +152,12 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { currentPage: 1, pageSize: this.appConfig.browseBy.pageSize, }); + this.ssrRenderingDisabled = !this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId); } ngOnInit(): void { - if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { + if (this.ssrRenderingDisabled) { this.loading$ = observableOf(false); return; } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index 28a603cfa3..16df026cfd 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -25,6 +25,9 @@ import { hasValue } from '../../../empty.util'; templateUrl: './search-results-skeleton.component.html', styleUrl: './search-results-skeleton.component.scss', }) +/** + * Component to show placeholders for search results while loading, to give a loading feedback to the user without layout shifting. + */ export class SearchResultsSkeletonComponent implements OnInit { @Input() showThumbnails: boolean; From 171a971572cc9c634677376c6063bd0f54487dfe Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 17:41:38 +0100 Subject: [PATCH 039/104] [DURACOM-303] resolve conflicts --- .../browse-by-metadata-page.component.html | 2 +- .../browse-by-title-page/browse-by-title-page.component.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html index a6abd5a7a4..9628de44b2 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index 0d8a2e32ed..74a109574c 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -16,6 +16,7 @@ import { PaginationComponentOptions } from '../../shared/pagination/pagination-c import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { isPlatformServer } from "@angular/common"; +import { environment } from "../../../environments/environment"; @Component({ selector: 'ds-browse-by-title-page', @@ -40,7 +41,7 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent { } ngOnInit(): void { - if (!this.renderOnServerSide && isPlatformServer(this.platformId)) { + if (!this.renderOnServerSide && !environment.universal.enableBrowseComponent && isPlatformServer(this.platformId)) { this.loading$ = observableOf(false); return; } From 483b97d9c187f415f5d3ad7579c4e4b773dbd782 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Tue, 21 Jan 2025 11:01:54 +0100 Subject: [PATCH 040/104] [DURACOM-303] refactor thumbnail's skeleton style --- .../search-results-skeleton.component.html | 12 +++++++----- .../search-results-skeleton.component.scss | 11 ++++------- .../search-results-skeleton.component.ts | 19 +++++++++++++++---- src/styles/_custom_variables.scss | 3 --- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index 84a67f4358..a42bda0674 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -5,14 +5,16 @@
@if((viewMode$ | async) === ViewMode.ListElement) { - @for (result of loadingResults; track result) { -
+ @for (result of loadingResults; track result; let first = $first) { +
@if(showThumbnails) { -
- +
+
+ +
} -
+
diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss index e05e4be6d8..9345f1ab43 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.scss @@ -20,12 +20,13 @@ } .thumbnail-skeleton { + max-width: var(--ds-thumbnail-max-width); + height: 100%; + ngx-skeleton-loader .skeleton-loader { - width: var(--ds-search-skeleton-thumbnail-width); - height: var(--ds-search-skeleton-thumbnail-height); - padding: var(--ds-search-skeleton-thumbnail-padding); margin-right: var(--ds-search-skeleton-thumbnail-margin); border-radius: 0; + height: 100%; } } @@ -52,8 +53,4 @@ } } -.result-row { - margin-right: 0; - margin-left: 0; -} diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index 16df026cfd..3fba70b119 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -29,17 +29,28 @@ import { hasValue } from '../../../empty.util'; * Component to show placeholders for search results while loading, to give a loading feedback to the user without layout shifting. */ export class SearchResultsSkeletonComponent implements OnInit { + /** + * Whether the search result contains thumbnail + */ @Input() showThumbnails: boolean; - + /** + * The number of search result loaded in the current page + */ @Input() numberOfResults = 0; - + /** + * How many placeholder are displayed for the search result text + */ @Input() textLineCount = 2; - + /** + * The view mode of the search page + */ public viewMode$: Observable; - + /** + * Array built from numberOfResults to count and iterate based on index + */ public loadingResults: number[]; protected readonly ViewMode = ViewMode; diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index d47f5d2dfa..3c3244549e 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -141,9 +141,6 @@ --ds-search-skeleton-text-height: 20px; --ds-search-skeleton-badge-height: 18px; - --ds-search-skeleton-thumbnail-height: 125px; - --ds-search-skeleton-thumbnail-width: 90px; - --ds-search-skeleton-thumbnail-padding: 1em; --ds-search-skeleton-thumbnail-margin: 1em; --ds-search-skeleton-text-line-count: 2; --ds-search-skeleton-badge-width: 75px; From 990f00b129c2b7f23e8ac41904d4778b4e07e702 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Fri, 24 Jan 2025 18:26:28 +0100 Subject: [PATCH 041/104] [DURACOM-303] adapt solution to older version of angular --- package.json | 2 +- .../browse-by-date-page.component.spec.ts | 4 +-- .../browse-by-date-page.component.ts | 4 +-- .../browse-by-metadata-page.component.ts | 4 +-- .../browse-by-title-page.component.spec.ts | 2 +- .../browse-by-title-page.component.ts | 4 +-- .../search-filter/search-filter.component.ts | 12 ++++---- .../search-filters.component.html | 3 +- .../search-filters.component.spec.ts | 4 +-- .../search-filters.component.ts | 15 ++++++---- .../search-results-skeleton.component.html | 30 +++++++++---------- .../search-results-skeleton.component.ts | 13 +------- .../search-results.component.html | 12 -------- .../search-results.component.spec.ts | 2 +- .../search-results.component.ts | 8 ++--- src/app/shared/search/search.component.ts | 2 +- src/app/shared/search/search.module.ts | 9 +++++- src/config/app-config.interface.ts | 2 +- src/config/default-app-config.ts | 4 +-- src/environments/environment.test.ts | 2 +- src/themes/custom/lazy-theme.module.ts | 7 ++--- yarn.lock | 15 ++++++++++ 22 files changed, 82 insertions(+), 78 deletions(-) diff --git a/package.json b/package.json index 86a506c57a..76ae2d5827 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "ngx-infinite-scroll": "^15.0.0", "ngx-pagination": "6.0.3", "ngx-sortablejs": "^11.1.0", - "ngx-skeleton-loader": "^9.0.0", + "ngx-skeleton-loader": "^7.0.0", "ngx-ui-switch": "^14.1.0", "nouislider": "^15.8.1", "pem": "1.14.8", diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts index 2fe673f821..f64091e41f 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.spec.ts @@ -24,8 +24,8 @@ import { APP_CONFIG } from '../../../config/app-config.interface'; import { environment } from '../../../environments/environment'; import { SortDirection } from '../../core/cache/models/sort-options.model'; import { cold } from 'jasmine-marbles'; -import { Store } from "@ngrx/store"; -import { BrowseEntry } from "../../core/shared/browse-entry.model"; +import { Store } from '@ngrx/store'; +import { BrowseEntry } from '../../core/shared/browse-entry.model'; describe('BrowseByDatePageComponent', () => { let comp: BrowseByDatePageComponent; diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 86a2f3dfa3..afb58e6ad2 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -19,8 +19,8 @@ import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { RemoteData } from '../../core/data/remote-data'; import { Item } from '../../core/shared/item.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; -import { isPlatformServer } from "@angular/common"; -import { environment } from "../../../environments/environment"; +import { isPlatformServer } from '@angular/common'; +import { environment } from '../../../environments/environment'; @Component({ selector: 'ds-browse-by-date-page', diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index a7357aaaf3..52cf3b9d7b 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -22,8 +22,8 @@ import { Collection } from '../../core/shared/collection.model'; import { Community } from '../../core/shared/community.model'; import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; -import { isPlatformServer } from "@angular/common"; -import { environment } from "../../../environments/environment"; +import { isPlatformServer } from '@angular/common'; +import { environment } from '../../../environments/environment'; export const BBM_PAGINATION_ID = 'bbm'; diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts index 653ad596c5..1b8eb352a3 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.spec.ts @@ -22,7 +22,7 @@ import { PaginationService } from '../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub'; import { APP_CONFIG } from '../../../config/app-config.interface'; import { environment } from '../../../environments/environment'; -import { BrowseEntry } from "../../core/shared/browse-entry.model"; +import { BrowseEntry } from '../../core/shared/browse-entry.model'; describe('BrowseByTitlePageComponent', () => { diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index 74a109574c..518fdf8c15 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -15,8 +15,8 @@ import { of as observableOf } from 'rxjs'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; -import { isPlatformServer } from "@angular/common"; -import { environment } from "../../../environments/environment"; +import { isPlatformServer } from '@angular/common'; +import { environment } from '../../../environments/environment'; @Component({ selector: 'ds-browse-by-title-page', diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts index 6f88d3924a..a440652fe5 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.ts @@ -93,7 +93,9 @@ export class SearchFilterComponent implements OnInit { */ ngOnInit() { this.selectedValues$ = this.getSelectedValues(); - this.active$ = this.isActive(); + this.active$ = this.isActive().pipe( + startWith(true) + ); this.collapsed$ = this.isCollapsed(); this.initializeFilter(); this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => { @@ -101,9 +103,9 @@ export class SearchFilterComponent implements OnInit { this.filterService.expand(this.filter.name); } }); - this.active$.pipe(take(1)).subscribe(() => { + this.isActive().pipe(take(1)).subscribe(() => { this.isVisibilityComputed.emit(true); - }) + }); } /** @@ -192,7 +194,7 @@ export class SearchFilterComponent implements OnInit { } )); } - }), - startWith(true)); + }) + ); } } diff --git a/src/app/shared/search/search-filters/search-filters.component.html b/src/app/shared/search/search-filters/search-filters.component.html index 45875ad7ae..e1e54c683d 100644 --- a/src/app/shared/search/search-filters/search-filters.component.html +++ b/src/app/shared/search/search-filters/search-filters.component.html @@ -1,6 +1,7 @@

{{"search.filters.head" | translate}}

-
+
diff --git a/src/app/shared/search/search-filters/search-filters.component.spec.ts b/src/app/shared/search/search-filters/search-filters.component.spec.ts index c8ad89910c..864d7b583e 100644 --- a/src/app/shared/search/search-filters/search-filters.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filters.component.spec.ts @@ -9,8 +9,8 @@ import { SearchFiltersComponent } from './search-filters.component'; import { SearchService } from '../../../core/shared/search/search.service'; import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; -import { APP_CONFIG } from "../../../../config/app-config.interface"; -import { environment } from "../../../../environments/environment"; +import { APP_CONFIG } from '../../../../config/app-config.interface'; +import { environment } from '../../../../environments/environment'; describe('SearchFiltersComponent', () => { let comp: SearchFiltersComponent; diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index 1f08a5ac5d..b491f21177 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, Input, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { BehaviorSubject, Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { map, tap } from 'rxjs/operators'; import { SearchService } from '../../../core/shared/search/search.service'; import { RemoteData } from '../../../core/data/remote-data'; @@ -12,7 +12,7 @@ import { SearchFilterService } from '../../../core/shared/search/search-filter.s import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../utils/route.utils'; import { hasValue } from '../../empty.util'; -import { APP_CONFIG, AppConfig } from "../../../../config/app-config.interface"; +import { APP_CONFIG, AppConfig } from '../../../../config/app-config.interface'; @Component({ selector: 'ds-search-filters', @@ -88,10 +88,13 @@ export class SearchFiltersComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => { - Object.keys(filters).forEach((f) => filters[f] = null); - return filters; - })); + this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe( + tap(() => this.filtersWithComputedVisibility = 0), + map((filters) => { + Object.keys(filters).forEach((f) => filters[f] = null); + return filters; + }) + ); this.searchLink = this.getSearchLink(); } diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index a42bda0674..bd98040257 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -4,16 +4,14 @@
-@if((viewMode$ | async) === ViewMode.ListElement) { - @for (result of loadingResults; track result; let first = $first) { -
- @if(showThumbnails) { -
-
- -
+ + +
+
+
+
- } +
@@ -23,16 +21,18 @@
- } -} @else if ((viewMode$ | async) === ViewMode.GridElement) { +
+
+ +
- @for (result of loadingResults; track result) { +
- } - +
-} +
+ diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts index 3fba70b119..179b26f1fd 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.ts @@ -1,13 +1,8 @@ -import { - AsyncPipe, - NgForOf, -} from '@angular/common'; import { Component, Input, OnInit, } from '@angular/core'; -import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Observable } from 'rxjs'; import { SearchService } from '../../../../core/shared/search/search.service'; @@ -16,14 +11,8 @@ import { hasValue } from '../../../empty.util'; @Component({ selector: 'ds-search-results-skeleton', - standalone: true, - imports: [ - NgxSkeletonLoaderModule, - AsyncPipe, - NgForOf, - ], templateUrl: './search-results-skeleton.component.html', - styleUrl: './search-results-skeleton.component.scss', + styleUrls: ['./search-results-skeleton.component.scss'], }) /** * Component to show placeholders for search results while loading, to give a loading feedback to the user without layout shifting. diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 71839d009b..a2bc91195c 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,15 +1,3 @@ -@if ((activeFilters$ | async).length > 0 && (appliedFilters$ | async).length === 0) { -
-
-
-
- -
-
-
-
-} -

{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}

diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index dc961c97cb..c2b181038a 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -7,7 +7,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { SearchResultsComponent } from './search-results.component'; import { QueryParamsDirectiveStub } from '../../testing/query-params-directive.stub'; import { createFailedRemoteDataObject } from '../../remote-data.utils'; -import { SearchResultsSkeletonComponent } from "./search-results-skeleton/search-results-skeleton.component"; +import { SearchResultsSkeletonComponent } from './search-results-skeleton/search-results-skeleton.component'; describe('SearchResultsComponent', () => { let comp: SearchResultsComponent; diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index 1faf8dd778..9050ce9cd0 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -11,10 +11,10 @@ import { CollectionElementLinkType } from '../../object-collection/collection-el import { ViewMode } from '../../../core/shared/view-mode.model'; import { Context } from '../../../core/shared/context.model'; import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; -import { SearchFilter } from "../models/search-filter.model"; -import { Observable } from "rxjs"; -import { SearchConfigurationService } from "../../../core/shared/search/search-configuration.service"; -import { SearchService } from "../../../core/shared/search/search.service"; +import { SearchFilter } from '../models/search-filter.model'; +import { Observable } from 'rxjs'; +import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; +import { SearchService } from '../../../core/shared/search/search.service'; export interface SelectionConfig { repeatable: boolean; diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index e69a183408..527d2d2719 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -48,7 +48,7 @@ import { ITEM_MODULE_PATH } from '../../item-page/item-page-routing-paths'; import { COLLECTION_MODULE_PATH } from '../../collection-page/collection-page-routing-paths'; import { COMMUNITY_MODULE_PATH } from '../../community-page/community-page-routing-paths'; import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; -import { isPlatformServer } from "@angular/common"; +import { isPlatformServer } from '@angular/common'; import { environment } from 'src/environments/environment'; @Component({ diff --git a/src/app/shared/search/search.module.ts b/src/app/shared/search/search.module.ts index 69500999a8..e2075a5f56 100644 --- a/src/app/shared/search/search.module.ts +++ b/src/app/shared/search/search.module.ts @@ -34,6 +34,10 @@ import { ThemedSearchSettingsComponent } from './search-settings/themed-search-s import { NouisliderModule } from 'ng2-nouislider'; import { ThemedSearchFiltersComponent } from './search-filters/themed-search-filters.component'; import { ThemedSearchSidebarComponent } from './search-sidebar/themed-search-sidebar.component'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { + SearchResultsSkeletonComponent +} from './search-results/search-results-skeleton/search-results-skeleton.component'; const COMPONENTS = [ SearchComponent, @@ -62,6 +66,7 @@ const COMPONENTS = [ ThemedSearchSettingsComponent, ThemedSearchFiltersComponent, ThemedSearchSidebarComponent, + SearchResultsSkeletonComponent ]; const ENTRY_COMPONENTS = [ @@ -74,6 +79,7 @@ const ENTRY_COMPONENTS = [ SearchFacetSelectedOptionComponent, SearchFacetRangeOptionComponent, SearchAuthorityFilterComponent, + SearchResultsSkeletonComponent ]; /** @@ -93,11 +99,12 @@ export const MODELS = [ imports: [ CommonModule, TranslateModule.forChild({ - missingTranslationHandler: { provide: MissingTranslationHandler, useClass: MissingTranslationHelper }, + missingTranslationHandler: {provide: MissingTranslationHandler, useClass: MissingTranslationHelper}, useDefaultLang: true }), SharedModule.withEntryComponents(), NouisliderModule, + NgxSkeletonLoaderModule, ], exports: [ ...COMPONENTS diff --git a/src/config/app-config.interface.ts b/src/config/app-config.interface.ts index 8b8dcf74a7..af78d4ab88 100644 --- a/src/config/app-config.interface.ts +++ b/src/config/app-config.interface.ts @@ -23,7 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; -import { SearchConfig } from "./search-page-config.interface"; +import { SearchConfig } from './search-page-config.interface'; interface AppConfig extends Config { ui: UIServerConfig; diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 2384942e3b..de4f3bd56e 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -23,7 +23,7 @@ import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; import { LiveRegionConfig } from '../app/shared/live-region/live-region.config'; -import { SearchConfig } from "./search-page-config.interface"; +import { SearchConfig } from './search-page-config.interface'; export class DefaultAppConfig implements AppConfig { production = false; @@ -446,5 +446,5 @@ export class DefaultAppConfig implements AppConfig { search: SearchConfig = { filterPlaceholdersCount: 5 - } + }; } diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index 4f832e1ac4..e6ffe85df6 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -325,6 +325,6 @@ export const environment: BuildConfig = { }, search: { - defaultFilterCount: 5 + filterPlaceholdersCount: 5 } }; diff --git a/src/themes/custom/lazy-theme.module.ts b/src/themes/custom/lazy-theme.module.ts index 1fe476c1e1..546d2dccbf 100644 --- a/src/themes/custom/lazy-theme.module.ts +++ b/src/themes/custom/lazy-theme.module.ts @@ -159,9 +159,8 @@ import { RequestCopyModule } from 'src/app/request-copy/request-copy.module'; import {UserMenuComponent} from './app/shared/auth-nav-menu/user-menu/user-menu.component'; import { BrowseByComponent } from './app/shared/browse-by/browse-by.component'; import { RegisterEmailFormComponent } from './app/register-email-form/register-email-form.component'; -import { - SearchResultsSkeletonComponent -} from "../../app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component"; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + const DECLARATIONS = [ FileSectionComponent, @@ -248,7 +247,6 @@ const DECLARATIONS = [ UserMenuComponent, BrowseByComponent, RegisterEmailFormComponent, - SearchResultsSkeletonComponent, ]; @NgModule({ @@ -309,6 +307,7 @@ const DECLARATIONS = [ NgxGalleryModule, FormModule, RequestCopyModule, + NgxSkeletonLoaderModule ], declarations: DECLARATIONS, exports: [ diff --git a/yarn.lock b/yarn.lock index 7760902b72..39661b8d43 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8415,6 +8415,14 @@ ngx-pagination@6.0.3: dependencies: tslib "^2.3.0" +ngx-skeleton-loader@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ngx-skeleton-loader/-/ngx-skeleton-loader-7.0.0.tgz#3b1325025a7208a20f3a0fdba6e578532a09cfcd" + integrity sha512-myc6GNcNhyksZrimIFkCxeihi0kQ8JhQVZiGbtiIv4gYrnnRk5nXbs3kYitK8E8OstHG+jlsmRofqGBxuIsYTA== + dependencies: + perf-marks "^1.13.4" + tslib "^2.0.0" + ngx-sortablejs@^11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/ngx-sortablejs/-/ngx-sortablejs-11.1.0.tgz" @@ -9060,6 +9068,13 @@ pend@~1.2.0: resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== +perf-marks@^1.13.4: + version "1.14.2" + resolved "https://registry.yarnpkg.com/perf-marks/-/perf-marks-1.14.2.tgz#7511c24239b9c2071717993a33ec3057f387b8c7" + integrity sha512-N0/bQcuTlETpgox/DsXS1voGjqaoamMoiyhncgeW3rSHy/qw8URVgmPRYfFDQns/+C6yFUHDbeSBGL7ixT6Y4A== + dependencies: + tslib "^2.1.0" + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" From ecd2faea4aa3c4322e98da295b3f826b6c1b3d10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:43:00 +0000 Subject: [PATCH 042/104] Bump cross-spawn from 7.0.3 to 7.0.6 Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6. - [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md) - [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6) --- updated-dependencies: - dependency-name: cross-spawn dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7760902b72..3a723f2ab9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4331,9 +4331,9 @@ cross-env@^7.0.3: cross-spawn "^7.0.1" cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" From 147564b114afd7c88246da0dbafe4073707f0f06 Mon Sep 17 00:00:00 2001 From: Alisa Ismailati Date: Thu, 10 Oct 2024 18:13:34 +0200 Subject: [PATCH 043/104] [CST-17153] improve descriptive labels for show/hide more buttons on related items lists (cherry picked from commit 7cd82e542bec81bf768124c20ea18162881cb56d) --- .../simple/related-items/related-items.component.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/item-page/simple/related-items/related-items.component.html b/src/app/item-page/simple/related-items/related-items.component.html index bee1f345fd..b15c93178c 100644 --- a/src/app/item-page/simple/related-items/related-items.component.html +++ b/src/app/item-page/simple/related-items/related-items.component.html @@ -7,12 +7,12 @@
- +
- +
From 5d6bf0bb334ddda17741837058a27de60f1a9e26 Mon Sep 17 00:00:00 2001 From: autavares-dev Date: Mon, 22 Jul 2024 21:20:05 -0300 Subject: [PATCH 044/104] Fix truncatable-part keyboard accessibility (cherry picked from commit 6cb4faa8d34cbb18eb0516506c2c6da6b5e15df9) --- .../truncatable-part.component.html | 18 +++++++++++------- .../truncatable-part.component.spec.ts | 13 +++++++++++++ .../truncatable-part.component.ts | 7 +++++++ 3 files changed, 31 insertions(+), 7 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 32a2a21349..55ebe2d957 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html @@ -2,12 +2,16 @@
- -
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 08d3e18117..a40703bbf3 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 @@ -73,6 +73,11 @@ describe('TruncatablePartComponent', () => { const a = fixture.debugElement.query(By.css('.collapseButton')); expect(a).toBeNull(); }); + + it('expandButton aria-expanded should be false', () => { + const btn = fixture.debugElement.query(By.css('.expandButton')); + expect(btn.nativeElement.getAttribute('aria-expanded')).toEqual('false'); + }); }); describe('When the item is expanded', () => { @@ -101,6 +106,14 @@ describe('TruncatablePartComponent', () => { const a = fixture.debugElement.query(By.css('.collapseButton')); expect(a).not.toBeNull(); }); + + it('collapseButton aria-expanded should be true', () => { + (comp as any).setLines(); + (comp as any).expandable = true; + fixture.detectChanges(); + const btn = fixture.debugElement.query(By.css('.collapseButton')); + expect(btn.nativeElement.getAttribute('aria-expanded')).toEqual('true'); + }); }); }); 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 790bd5985d..c25e44c968 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -136,6 +136,13 @@ export class TruncatablePartComponent implements AfterViewChecked, OnInit, OnDes } } + /** + * Indicates if the content is expanded, button state is 'Collapse' + */ + public get isExpanded() { + return this.expand && this.expandable; + } + /** * Unsubscribe from the subscription */ From 868b0211186e9c1d4507d5afafc4ff42d7b5d92b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 02:35:56 +0000 Subject: [PATCH 045/104] Bump @babel/runtime from 7.26.0 to 7.26.7 Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.26.0 to 7.26.7. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.7/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e94785d93e..cd5c2e6461 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@angular/platform-browser-dynamic": "^15.2.10", "@angular/platform-server": "^15.2.10", "@angular/router": "^15.2.10", - "@babel/runtime": "7.26.0", + "@babel/runtime": "7.26.7", "@kolkov/ngx-gallery": "^2.0.1", "@ng-bootstrap/ng-bootstrap": "^11.0.0", "@ng-dynamic-forms/core": "^15.0.0", diff --git a/yarn.lock b/yarn.lock index 58d8f59fbc..23db53d7cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1352,10 +1352,10 @@ dependencies: regenerator-runtime "^0.13.11" -"@babel/runtime@7.26.0", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" - integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== +"@babel/runtime@7.26.7", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.7.tgz#f4e7fe527cd710f8dc0618610b61b4b060c3c341" + integrity sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ== dependencies: regenerator-runtime "^0.14.0" From 8a4f24fc31bd1fad18f63cb71a0f377a51f63d87 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Mon, 27 Jan 2025 09:34:42 +0100 Subject: [PATCH 046/104] [DURACOM-303] adapt tests dependencies and template variable --- .../search-results-skeleton.component.html | 2 +- .../search-results-skeleton.component.spec.ts | 3 ++- .../search-results/search-results.component.spec.ts | 11 ++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html index bd98040257..c318eea2e1 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.html @@ -5,7 +5,7 @@
- +
diff --git a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts index 68c8db5a8e..86277181fe 100644 --- a/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts +++ b/src/app/shared/search/search-results/search-results-skeleton/search-results-skeleton.component.spec.ts @@ -14,7 +14,8 @@ describe('SearchResultsSkeletonComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [SearchResultsSkeletonComponent, NgxSkeletonLoaderModule], + imports: [NgxSkeletonLoaderModule], + declarations: [SearchResultsSkeletonComponent], providers: [ { provide: SearchService, useValue: new SearchServiceStub() }, ], diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index c2b181038a..1ef596a4ed 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -8,6 +8,10 @@ import { SearchResultsComponent } from './search-results.component'; import { QueryParamsDirectiveStub } from '../../testing/query-params-directive.stub'; import { createFailedRemoteDataObject } from '../../remote-data.utils'; import { SearchResultsSkeletonComponent } from './search-results-skeleton/search-results-skeleton.component'; +import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; +import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub'; +import { SearchService } from '../../../core/shared/search/search.service'; +import { SearchServiceStub } from '../../testing/search-service.stub'; describe('SearchResultsComponent', () => { let comp: SearchResultsComponent; @@ -21,7 +25,12 @@ describe('SearchResultsComponent', () => { declarations: [ SearchResultsComponent, SearchResultsSkeletonComponent, - QueryParamsDirectiveStub], + QueryParamsDirectiveStub + ], + providers: [ + { provide: SearchConfigurationService, useValue: new SearchConfigurationServiceStub() }, + { provide: SearchService, useValue: new SearchServiceStub() }, + ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); })); From cd2f8abd2d14a75433a5c0ce3c6362206c4b7eb2 Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Fri, 24 Jan 2025 11:23:48 +0100 Subject: [PATCH 047/104] 117544: fix issues latest 7.x merge --- .../filtered-items.component.html | 0 ...llection-source-controls.component.spec.ts | 1 - .../dso-edit-metadata-value.component.html | 47 ------------------- 3 files changed, 48 deletions(-) delete mode 100644 src/app/admin/admin-reports/filtered-items/filtered-items.component.html diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.html b/src/app/admin/admin-reports/filtered-items/filtered-items.component.html deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts index 12de34d3a9..ed53f8ab2f 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.spec.ts @@ -191,7 +191,6 @@ describe('CollectionSourceControlsComponent', () => { const buttons = fixture.debugElement.queryAll(By.css('button')); buttons.forEach(button => { - console.log(button.nativeElement); expect(button.nativeElement.getAttribute('aria-disabled')).toBe('true'); expect(button.nativeElement.classList.contains('disabled')).toBeTrue(); }); diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html index e07585b39b..f96759a75e 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html @@ -6,53 +6,6 @@ - - - - -
- - - {{ dsoType + '.edit.metadata.authority.label' | translate }} {{ mdValue.newValue.authority }} - -
-
-
- - - - -
-
{{ mdRepresentationName$ | async }} From 8c92364d43e464a00585304550b7dc9e8a2d5e11 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Thu, 9 Jan 2025 18:46:10 +0100 Subject: [PATCH 048/104] 122357: Ensure the request href$ observable aren't triggered multiple times (cherry picked from commit 3ecdfe422df3b31b20d257f9197d0b2e7d250920) --- src/app/core/data/base/base-data.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/core/data/base/base-data.service.ts b/src/app/core/data/base/base-data.service.ts index 18131dea63..234e7272a6 100644 --- a/src/app/core/data/base/base-data.service.ts +++ b/src/app/core/data/base/base-data.service.ts @@ -6,7 +6,7 @@ * http://www.dspace.org/license/ */ -import { AsyncSubject, from as observableFrom, Observable, of as observableOf } from 'rxjs'; +import { AsyncSubject, from as observableFrom, Observable, of as observableOf, shareReplay } from 'rxjs'; import { map, mergeMap, skipWhile, switchMap, take, tap, toArray } from 'rxjs/operators'; import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../../shared/empty.util'; import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model'; @@ -264,6 +264,7 @@ export class BaseDataService implements HALDataServic isNotEmptyOperator(), take(1), map((href: string) => this.buildHrefFromFindOptions(href, {}, [], ...linksToFollow)), + shareReplay(1), ); const startTime: number = new Date().getTime(); @@ -299,6 +300,7 @@ export class BaseDataService implements HALDataServic isNotEmptyOperator(), take(1), map((href: string) => this.buildHrefFromFindOptions(href, options, [], ...linksToFollow)), + shareReplay(1), ); const startTime: number = new Date().getTime(); From bb3d2bb4837a29664defa8830ac138edc63118d6 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Thu, 9 Jan 2025 15:18:24 +0100 Subject: [PATCH 049/104] 122357: Reduced the amount of times the browse observables are fired again (cherry picked from commit 0570542b1eb2874617deac27f38c4ecec7bbc1c3) --- .../browse-by-date-page.component.ts | 23 +++++++++------- .../browse-by-metadata-page.component.ts | 26 ++++++++++--------- .../browse-by-title-page.component.ts | 21 ++++++++++----- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index afb58e6ad2..cca56647d8 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -10,7 +10,7 @@ import { BrowseService } from '../../core/browse/browse.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { StartsWithType } from '../../shared/starts-with/starts-with-decorator'; import { PaginationService } from '../../core/pagination/pagination.service'; -import { map, take } from 'rxjs/operators'; +import { map, distinctUntilChanged } from 'rxjs/operators'; import { of as observableOf } from 'rxjs'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; @@ -61,16 +61,19 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { this.startsWithType = StartsWithType.date; this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); + const routeParams$: Observable = observableCombineLatest([ + this.route.params, + this.route.queryParams, + ]).pipe( + map(([params, queryParams]: [Params, Params]) => Object.assign({}, params, queryParams)), + distinctUntilChanged((prev: Params, curr: Params) => prev.id === curr.id && prev.startsWith === curr.startsWith), + ); this.subs.push( - observableCombineLatest( - [ this.route.params.pipe(take(1)), - this.route.queryParams, - this.currentPagination$, - this.currentSort$]).pipe( - map(([routeParams, queryParams, currentPage, currentSort]) => { - return [Object.assign({}, routeParams, queryParams), currentPage, currentSort]; - }) - ).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { + observableCombineLatest([ + routeParams$, + this.currentPagination$, + this.currentSort$, + ]).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { const metadataKeys = params.browseDefinition ? params.browseDefinition.metadataKeys : this.defaultMetadataKeys; this.browseId = params.id || this.defaultBrowseId; this.startsWith = +params.startsWith || params.startsWith; diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 52cf3b9d7b..5f921667bf 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -15,7 +15,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { StartsWithType } from '../../shared/starts-with/starts-with-decorator'; import { PaginationService } from '../../core/pagination/pagination.service'; -import { filter, map, mergeMap, take } from 'rxjs/operators'; +import { filter, map, mergeMap, distinctUntilChanged } from 'rxjs/operators'; import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; import { Bitstream } from '../../core/shared/bitstream.model'; import { Collection } from '../../core/shared/collection.model'; @@ -162,20 +162,22 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { return; } const sortConfig = new SortOptions('default', SortDirection.ASC); - this.updatePage(getBrowseSearchOptions(this.defaultBrowseId, this.paginationConfig, sortConfig)); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); + const routeParams$: Observable = observableCombineLatest([ + this.route.params, + this.route.queryParams, + ]).pipe( + map(([params, queryParams]: [Params, Params]) => Object.assign({}, params, queryParams)), + distinctUntilChanged((prev: Params, curr: Params) => prev.id === curr.id && prev.authority === curr.authority && prev.value === curr.value && prev.startsWith === curr.startsWith), + ); this.subs.push( - observableCombineLatest( - [ this.route.params.pipe(take(1)), - this.route.queryParams, - this.currentPagination$, - this.currentSort$]).pipe( - map(([routeParams, queryParams, currentPage, currentSort]) => { - return [Object.assign({}, routeParams, queryParams),currentPage,currentSort]; - }) - ).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { - this.browseId = params.id || this.defaultBrowseId; + observableCombineLatest([ + routeParams$, + this.currentPagination$, + this.currentSort$, + ]).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { + this.browseId = params.id || this.defaultBrowseId; this.authority = params.authority; if (typeof params.value === 'string'){ diff --git a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts index 518fdf8c15..10968d265f 100644 --- a/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts +++ b/src/app/browse-by/browse-by-title-page/browse-by-title-page.component.ts @@ -1,4 +1,4 @@ -import { combineLatest as observableCombineLatest } from 'rxjs'; +import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { Component, Inject, PLATFORM_ID } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { hasValue } from '../../shared/empty.util'; @@ -10,7 +10,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv import { BrowseService } from '../../core/browse/browse.service'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { PaginationService } from '../../core/pagination/pagination.service'; -import { map, take } from 'rxjs/operators'; +import { map, distinctUntilChanged } from 'rxjs/operators'; import { of as observableOf } from 'rxjs'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface'; @@ -48,12 +48,19 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent { const sortConfig = new SortOptions('dc.title', SortDirection.ASC); this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); this.currentSort$ = this.paginationService.getCurrentSort(this.paginationConfig.id, sortConfig); + const routeParams$: Observable = observableCombineLatest([ + this.route.params, + this.route.queryParams, + ]).pipe( + map(([params, queryParams]: [Params, Params]) => Object.assign({}, params, queryParams)), + distinctUntilChanged((prev: Params, curr: Params) => prev.id === curr.id && prev.startsWith === curr.startsWith), + ); this.subs.push( - observableCombineLatest([this.route.params.pipe(take(1)), this.route.queryParams, this.currentPagination$, this.currentSort$]).pipe( - map(([routeParams, queryParams, currentPage, currentSort]) => { - return [Object.assign({}, routeParams, queryParams),currentPage,currentSort]; - }) - ).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { + observableCombineLatest([ + routeParams$, + this.currentPagination$, + this.currentSort$, + ]).subscribe(([params, currentPage, currentSort]: [Params, PaginationComponentOptions, SortOptions]) => { this.startsWith = +params.startsWith || params.startsWith; this.browseId = params.id || this.defaultBrowseId; this.updatePageWithItems(browseParamsToOptions(params, currentPage, currentSort, this.browseId, this.fetchThumbnails), undefined, undefined); From 5a5c1f18e3a1e20b892899106139ef97d5a55f30 Mon Sep 17 00:00:00 2001 From: VictorDuranEscire Date: Tue, 28 Jan 2025 17:07:00 -0600 Subject: [PATCH 050/104] Changing metadata in a user profile without specifying a password brings up a success and an error panel (#3818) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Agregar validador para mostrar mensaje de error solo si se escribe la contraseña actual * Agregar validador para mostrar mensaje de error solo si se escribe la contraseña actual * Set constant variable for valid current password in profile page --- src/app/profile-page/profile-page.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/profile-page/profile-page.component.ts b/src/app/profile-page/profile-page.component.ts index f8cb30a447..7fb1a14124 100644 --- a/src/app/profile-page/profile-page.component.ts +++ b/src/app/profile-page/profile-page.component.ts @@ -173,7 +173,8 @@ export class ProfilePageComponent implements OnInit { */ updateSecurity() { const passEntered = isNotEmpty(this.password); - if (this.invalidSecurity) { + const validCurrentPassword = isNotEmpty(this.currentPassword); + if (validCurrentPassword && !passEntered) { this.notificationsService.error(this.translate.instant(this.PASSWORD_NOTIFICATIONS_PREFIX + 'error.general')); } if (!this.invalidSecurity && passEntered) { From e296295df59099c3778f735334c98038821774d7 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 29 Jan 2025 15:57:55 -0600 Subject: [PATCH 051/104] Fix YAML syntax and revert section name to "universal" as that's the name in 7.x --- config/config.example.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index 6674bc5334..c79c87f4d7 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -17,8 +17,8 @@ ui: # Trust X-FORWARDED-* headers from proxies (default = true) useProxies: true -# Angular Server Side Rendering (SSR) settings -ssr: +# Angular Universal / Server Side Rendering (SSR) settings +universal: # Whether to tell Angular to inline "critical" styles into the server-side rendered HTML. # Determining which styles are critical is a relatively expensive operation; this option is # disabled (false) by default to boost server performance at the expense of loading smoothness. @@ -28,11 +28,11 @@ ssr: # Whether to enable rendering of Search component on SSR. # If set to true the component will be included in the HTML returned from the server side rendering. # If set to false the component will not be included in the HTML returned from the server side rendering. - enableSearchComponent: false, + enableSearchComponent: false # Whether to enable rendering of Browse component on SSR. # If set to true the component will be included in the HTML returned from the server side rendering. # If set to false the component will not be included in the HTML returned from the server side rendering. - enableBrowseComponent: false, + enableBrowseComponent: false # The REST API server settings # NOTE: these settings define which (publicly available) REST API to use. They are usually From 470ad807410fbc733dc84c57346e9955757ab8ed Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 5 Jul 2024 10:34:49 +0200 Subject: [PATCH 052/104] 116404: Fixed expandable navbar section loosing focus on expand through keyboard (cherry picked from commit 2547b1218f36f00e1a62522a47d9c9f59dbc91e9) --- .../expandable-admin-sidebar-section.component.ts | 4 ++-- .../expandable-navbar-section.component.html | 12 +++++------- .../expandable-navbar-section.component.ts | 10 ++++------ .../menu/menu-section/menu-section.component.ts | 8 +++++--- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts index e2995598f8..d25d7c6b40 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts @@ -67,8 +67,8 @@ export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionC this.sidebarActiveBg$ = this.variableService.getVariable('--ds-admin-sidebar-active-bg'); this.isSidebarCollapsed$ = this.menuService.isMenuCollapsed(this.menuID); this.isSidebarPreviewCollapsed$ = this.menuService.isMenuPreviewCollapsed(this.menuID); - this.isExpanded$ = combineLatestObservable([this.active, this.isSidebarCollapsed$, this.isSidebarPreviewCollapsed$]).pipe( - map(([active, sidebarCollapsed, sidebarPreviewCollapsed]) => (active && (!sidebarCollapsed || !sidebarPreviewCollapsed))) + this.isExpanded$ = combineLatestObservable([this.active$, this.isSidebarCollapsed$, this.isSidebarPreviewCollapsed$]).pipe( + map(([active, sidebarCollapsed, sidebarPreviewCollapsed]) => (active && (!sidebarCollapsed || !sidebarPreviewCollapsed))), ); } diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html index 7f9b4a546f..5119cec689 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html @@ -1,9 +1,8 @@
+ (mouseenter)="onMouseEnter($event)" + (mouseleave)="onMouseLeave($event)" + data-test="navbar-section-wrapper"> - -
diff --git a/src/app/shared/menu/menu-section/menu-section.component.ts b/src/app/shared/menu/menu-section/menu-section.component.ts index 2611935dfa..e0464a769f 100644 --- a/src/app/shared/menu/menu-section/menu-section.component.ts +++ b/src/app/shared/menu/menu-section/menu-section.component.ts @@ -85,10 +85,14 @@ export class MenuSectionComponent implements OnInit, OnDestroy { /** * Deactivate this section + * * @param {Event} event The user event that triggered this method + * @param skipEvent Weather the event should still be triggered after deactivating the section or not */ - deactivateSection(event: Event) { - event.preventDefault(); + deactivateSection(event: Event, skipEvent = true): void { + if (skipEvent) { + event.preventDefault(); + } this.menuService.deactivateSection(this.menuID, this.section.id); } From 53186988f58073054c9b269144aab50d98da9755 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 5 Jul 2024 13:30:01 +0200 Subject: [PATCH 054/104] 116404: Added navigation with arrow keys in navbar & collapsed the expandable menu when hovering outside of it (cherry picked from commit 05232cdf2b068223c8147ed61afe364fc92986d1) --- .../expandable-navbar-section.component.html | 59 ++++++------ .../expandable-navbar-section.component.ts | 92 +++++++++++++++++-- src/app/navbar/navbar.module.ts | 7 ++ .../shared/utils/hover-outside.directive.ts | 50 ++++++++++ 4 files changed, 169 insertions(+), 39 deletions(-) create mode 100644 src/app/shared/utils/hover-outside.directive.ts diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html index f37fc222d5..f8facaa82a 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html @@ -1,36 +1,37 @@ -
- +
+ - - -