Merge tag 'dspace-7.4' into fix-ngonchanges-not-working-for-themed-components_contribute-7.4

# Conflicts:
#	src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/collection-search-result/collection-admin-search-result-grid-element.component.spec.ts
#	src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/community-search-result/community-admin-search-result-grid-element.component.spec.ts
#	src/app/shared/mydspace-actions/claimed-task/switcher/claimed-task-actions-loader.component.ts
#	src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts
#	src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html
#	src/app/shared/object-grid/community-grid-element/community-grid-element.component.html
#	src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html
#	src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html
#	src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html
#	src/app/shared/theme-support/themed.component.ts
#	src/app/thumbnail/thumbnail.component.spec.ts
#	src/app/thumbnail/thumbnail.component.ts
#	src/themes/custom/lazy-theme.module.ts
This commit is contained in:
Alexandre Vryghem
2023-05-19 12:30:19 +02:00
1608 changed files with 95995 additions and 40601 deletions

View File

@@ -1,5 +1,5 @@
<div class="card">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', object.id]" class="card-img-top">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', object.id]" class="card-img-top" [attr.title]="'search.results.view-result' | translate">
<ds-themed-thumbnail [thumbnail]="(object.logo | async)?.payload" [limitWidth]="false">
</ds-themed-thumbnail>
</a>
@@ -11,7 +11,7 @@
<h4 class="card-title">{{object.name}}</h4>
<p *ngIf="object.shortDescription" class="card-text">{{object.shortDescription}}</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', object.id]" class="lead btn btn-primary viewButton">View</a>
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', object.id]" class="lead btn btn-primary viewButton">{{ 'search.results.view-result' | translate}}</a>
</div>
</div>
</div>

View File

@@ -4,6 +4,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { Collection } from '../../../core/shared/collection.model';
import { LinkService } from '../../../core/cache/builders/link.service';
import { TranslateModule } from '@ngx-translate/core';
let collectionGridElementComponent: CollectionGridElementComponent;
let fixture: ComponentFixture<CollectionGridElementComponent>;
@@ -37,6 +38,9 @@ const linkService = jasmine.createSpyObj('linkService', {
describe('CollectionGridElementComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [CollectionGridElementComponent],
providers: [
{ provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) },

View File

@@ -1,5 +1,5 @@
<div class="card">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', object.id]" class="card-img-top">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', object.id]" class="card-img-top" [attr.title]="'search.results.view-result' | translate">
<ds-themed-thumbnail [thumbnail]="(object.logo | async)?.payload" [limitWidth]="false">
</ds-themed-thumbnail>
</a>
@@ -11,7 +11,7 @@
<h4 class="card-title">{{object.name}}</h4>
<p *ngIf="object.shortDescription" class="card-text">{{object.shortDescription}}</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', object.id]" class="lead btn btn-primary viewButton">View</a>
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', object.id]" class="lead btn btn-primary viewButton">{{ 'search.results.view-result' | translate}}</a>
</div>
</div>
</div>

View File

@@ -4,6 +4,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { Community } from '../../../core/shared/community.model';
import { LinkService } from '../../../core/cache/builders/link.service';
import { TranslateModule } from '@ngx-translate/core';
let communityGridElementComponent: CommunityGridElementComponent;
let fixture: ComponentFixture<CommunityGridElementComponent>;
@@ -37,6 +38,9 @@ const linkService = jasmine.createSpyObj('linkService', {
describe('CommunityGridElementComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [CommunityGridElementComponent],
providers: [
{ provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) },

View File

@@ -4,21 +4,27 @@
[collectionSize]="objects?.payload?.totalElements"
[sortOptions]="sortConfig"
[hideGear]="hideGear"
[objects]="objects"
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
[hidePaginationDetail]="hidePaginationDetail"
[showPaginator]="showPaginator"
(pageChange)="onPageChange($event)"
(pageSizeChange)="onPageSizeChange($event)"
(sortDirectionChange)="onSortDirectionChange($event)"
(sortFieldChange)="onSortFieldChange($event)"
(paginationChange)="onPaginationChange($event)">
(paginationChange)="onPaginationChange($event)"
(prev)="goPrev()"
(next)="goNext()"
>
<div class="card-columns row" *ngIf="objects?.hasSucceeded">
<div class="card-column col col-sm-6 col-lg-4" *ngFor="let column of (columns$ | async)" @fadeIn>
<div class="card-element" *ngFor="let object of column">
<div class="card-element" *ngFor="let object of column" [attr.data-test]="'grid-object' | dsBrowserOnly">
<ds-listable-object-component-loader [object]="object" [viewMode]="viewMode" [context]="context" [linkType]="linkType"></ds-listable-object-component-loader>
</div>
</div>
</div>
<ds-error *ngIf="objects.hasFailed" message="{{'error.objects' | translate}}"></ds-error>
<ds-loading *ngIf="objects.isLoading" message="{{'loading.objects' | translate}}"></ds-loading>
<ds-themed-loading *ngIf="objects.isLoading" message="{{'loading.objects' | translate}}"></ds-themed-loading>
</ds-pagination>

View File

@@ -1,18 +1,19 @@
:host ::ng-deep {
--ds-wrapper-grid-spacing: calc(var(--bs-spacer) / 2);
div.thumbnail > .thumbnail-content {
height: var(--ds-card-thumbnail-height);
width: 100%;
display: block;
min-width: 100%;
min-height: 100%;
object-fit: cover;
object-position: 50% 15%;
}
div.card {
margin-top: var(--ds-wrapper-grid-spacing);
margin-bottom: var(--ds-wrapper-grid-spacing);
div.thumbnail > .thumbnail-content {
height: var(--ds-card-thumbnail-height);
width: 100%;
display: block;
min-width: 100%;
min-height: 100%;
object-fit: cover;
object-position: 50% 15%;
}
}
}
@@ -26,4 +27,3 @@
padding-right: var(--ds-wrapper-grid-spacing);
}
}

View File

@@ -49,6 +49,11 @@ export class ObjectGridComponent implements OnInit {
*/
@Input() sortConfig: SortOptions;
/**
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
*/
@Input() showPaginator = true;
/**
* The whether or not the gear is hidden
*/
@@ -134,6 +139,17 @@ export class ObjectGridComponent implements OnInit {
* Event's payload equals to the newly selected sort field.
*/
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
/**
* If showPaginator is set to true, emit when the previous button is clicked
*/
@Output() prev = new EventEmitter<boolean>();
/**
* If showPaginator is set to true, emit when the next button is clicked
*/
@Output() next = new EventEmitter<boolean>();
data: any = {};
columns$: Observable<ListableObject[]>;
@@ -225,4 +241,18 @@ export class ObjectGridComponent implements OnInit {
this.paginationChange.emit(event);
}
/**
* Go to the previous page
*/
goPrev() {
this.prev.emit(true);
}
/**
* Go to the next page
*/
goNext() {
this.next.emit(true);
}
}

View File

@@ -1,5 +1,5 @@
<div class="card">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', dso.id]" class="card-img-top">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', dso.id]" class="card-img-top" [attr.title]="'search.results.view-result' | translate">
<ds-themed-thumbnail [thumbnail]="(dso.logo | async)?.payload" [limitWidth]="false">
</ds-themed-thumbnail>
</a>
@@ -12,7 +12,7 @@
<h4 class="card-title">{{dso.name}}</h4>
<p *ngIf="dso.shortDescription" class="card-text">{{dso.shortDescription}}</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', dso.id]" class="lead btn btn-primary viewButton">View</a>
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/collections/', dso.id]" class="lead btn btn-primary viewButton">{{ 'search.results.view-result' | translate}}</a>
</div>
</div>
<ng-content></ng-content>

View File

@@ -20,6 +20,7 @@ import { TruncatePipe } from '../../../utils/truncate.pipe';
import { CollectionSearchResultGridElementComponent } from './collection-search-result-grid-element.component';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { LinkService } from '../../../../core/cache/builders/link.service';
import { TranslateModule } from '@ngx-translate/core';
let collectionSearchResultGridElementComponent: CollectionSearchResultGridElementComponent;
let fixture: ComponentFixture<CollectionSearchResultGridElementComponent>;
@@ -60,6 +61,9 @@ const linkService = jasmine.createSpyObj('linkService', {
describe('CollectionSearchResultGridElementComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [CollectionSearchResultGridElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: truncatableServiceStub },

View File

@@ -1,5 +1,5 @@
<div class="card">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', dso.id]" class="card-img-top">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', dso.id]" class="card-img-top" [attr.title]="'search.results.view-result' | translate">
<ds-themed-thumbnail [thumbnail]="(dso.logo | async)?.payload" [limitWidth]="false">
</ds-themed-thumbnail>
</a>
@@ -12,7 +12,7 @@
<h4 class="card-title">{{dso.name}}</h4>
<p *ngIf="dso.shortDescription" class="card-text">{{dso.shortDescription}}</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', dso.id]" class="lead btn btn-primary viewButton">View</a>
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/communities/', dso.id]" class="lead btn btn-primary viewButton">{{ 'search.results.view-result' | translate}}</a>
</div>
</div>
<ng-content></ng-content>

View File

@@ -20,6 +20,7 @@ import { TruncatePipe } from '../../../utils/truncate.pipe';
import { CommunitySearchResultGridElementComponent } from './community-search-result-grid-element.component';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { LinkService } from '../../../../core/cache/builders/link.service';
import { TranslateModule } from '@ngx-translate/core';
let communitySearchResultGridElementComponent: CommunitySearchResultGridElementComponent;
let fixture: ComponentFixture<CommunitySearchResultGridElementComponent>;
@@ -60,6 +61,9 @@ const linkService = jasmine.createSpyObj('linkService', {
describe('CommunitySearchResultGridElementComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [CommunitySearchResultGridElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: truncatableServiceStub },

View File

@@ -1,45 +1,45 @@
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<ds-truncatable [id]="dso.id">
<div class="position-absolute ml-1">
<div class="position-absolute ml-1">
<ng-content></ng-content>
</div>
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width">
<div>
</div>
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
<div>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-themed-thumbnail [thumbnail]="dso?.thumbnail | async" [limitWidth]="false">
</ds-themed-thumbnail>
</div>
</span>
<div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="firstMetadataValue('dc.title')"></h4>
</ds-truncatable-part>
<p *ngIf="dso.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])"
class="item-authors card-text text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span *ngIf="dso.hasMetadata('dc.date.issued')" class="item-date">{{firstMetadataValue('dc.date.issued')}}</span>
<span *ngFor="let author of allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']);">,
<span [innerHTML]="author"></span>
</span>
</ds-truncatable-part>
</p>
<p *ngIf="dso.hasMetadata('dc.description.abstract')" class="item-abstract card-text">
<ds-truncatable-part [id]="dso.id" [minLines]="3">
<span [innerHTML]="firstMetadataValue('dc.description.abstract')"></span>
</ds-truncatable-part>
</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">View</a>
</div>
</div>
</ds-truncatable>
</div>
</span>
<div class="card-body">
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
<ds-access-status-badge [item]="dso"></ds-access-status-badge>
<ds-truncatable [id]="dso.id">
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
</ds-truncatable-part>
<ds-truncatable-part [id]="dso.id" [minLines]="1" *ngIf="dso.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])">
<p class="item-authors card-text text-muted">
<span *ngIf="dso.hasMetadata('dc.date.issued')" class="item-date">{{firstMetadataValue('dc.date.issued')}}</span>
<span *ngFor="let author of allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']);">,
<span [innerHTML]="author"></span>
</span>
</p>
</ds-truncatable-part>
<ds-truncatable-part *ngIf="dso.hasMetadata('dc.description.abstract')" [id]="dso.id" [minLines]="3">
<p class="item-abstract card-text">
<span [innerHTML]="firstMetadataValue('dc.description.abstract')"></span>
</p>
</ds-truncatable-part>
</ds-truncatable>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="[itemPageRoute]"
class="lead btn btn-primary viewButton">{{ 'search.results.view-result' | translate}}</a>
</div>
</div>
<ng-content></ng-content>
</div>

View File

@@ -4,6 +4,7 @@ import { TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { Store } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../../../core/cache/object-cache.service';
@@ -99,7 +100,10 @@ export function getEntityGridElementTestComponent(component, searchResultWithMet
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule],
imports: [
NoopAnimationsModule,
TranslateModule.forRoot()
],
declarations: [component, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: truncatableServiceStub },

View File

@@ -1,11 +1,16 @@
import { Component } from '@angular/core';
import { focusShadow } from '../../../../animations/focus';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../object-collection/shared/listable-object/listable-object.decorator';
import {
listableObjectComponent
} from '../../../../object-collection/shared/listable-object/listable-object.decorator';
import { SearchResultGridElementComponent } from '../../search-result-grid-element.component';
import { Item } from '../../../../../core/shared/item.model';
import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
import { getItemPageRoute } from '../../../../../item-page/item-page-routing-paths';
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
import { TruncatableService } from '../../../../truncatable/truncatable.service';
import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
@listableObjectComponent('PublicationSearchResult', ViewMode.GridElement)
@listableObjectComponent(ItemSearchResult, ViewMode.GridElement)
@@ -24,8 +29,19 @@ export class ItemSearchResultGridElementComponent extends SearchResultGridElemen
*/
itemPageRoute: string;
dsoTitle: string;
constructor(
protected truncatableService: TruncatableService,
protected bitstreamDataService: BitstreamDataService,
private dsoNameService: DSONameService,
) {
super(truncatableService, bitstreamDataService);
}
ngOnInit(): void {
super.ngOnInit();
this.itemPageRoute = getItemPageRoute(this.dso);
this.dsoTitle = this.dsoNameService.getName(this.dso);
}
}