Merge pull request #497 from atmire/w2p-65195_dynamic-component-refactoring

Dynamic component loading refactoring
This commit is contained in:
Tim Donohue
2019-11-14 09:58:49 -06:00
committed by GitHub
350 changed files with 4619 additions and 3402 deletions

View File

@@ -1,6 +1,6 @@
<div class="row" *ngIf="item"> <div class="row" *ngIf="item">
<div class="col-10 relationship"> <div class="col-10 relationship">
<ds-item-type-switcher [object]="item" [viewMode]="viewMode"></ds-item-type-switcher> <ds-listable-object-component-loader [object]="item" [viewMode]="viewMode"></ds-listable-object-component-loader>
</div> </div>
<div class="col-2"> <div class="col-2">
<div class="btn-group relationship-action-buttons"> <div class="btn-group relationship-action-buttons">

View File

@@ -5,7 +5,6 @@ import { ObjectUpdatesService } from '../../../../core/data/object-updates/objec
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { EditRelationshipComponent } from './edit-relationship.component'; import { EditRelationshipComponent } from './edit-relationship.component';
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model'; import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
import { ResourceType } from '../../../../core/shared/resource-type';
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
import { RemoteData } from '../../../../core/data/remote-data'; import { RemoteData } from '../../../../core/data/remote-data';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';

View File

@@ -4,7 +4,7 @@ import { cloneDeep } from 'lodash';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service'; import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions'; import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
import { ItemViewMode } from '../../../../shared/items/item-type-decorator'; import { ViewMode } from '../../../../core/shared/view-mode.model';
@Component({ @Component({
// tslint:disable-next-line:component-selector // tslint:disable-next-line:component-selector
@@ -31,7 +31,7 @@ export class EditRelationshipComponent implements OnChanges {
/** /**
* The view-mode we're currently on * The view-mode we're currently on
*/ */
viewMode = ItemViewMode.Element; viewMode = ViewMode.ListElement;
constructor(private objectUpdatesService: ObjectUpdatesService) { constructor(private objectUpdatesService: ObjectUpdatesService) {
} }

View File

@@ -10,7 +10,7 @@ import { ItemPageFieldComponent } from '../item-page-field.component';
/** /**
* This component can be used to represent metadata on a simple item page. * This component can be used to represent metadata on a simple item page.
* It is the most generic way of displaying metadata values * It is the most generic way of displaying metadata values
* It expects 4 parameters: The item, a seperator, the metadata keys and an i18n key * It expects 4 parameters: The item, a separator, the metadata keys and an i18n key
*/ */
export class GenericItemPageFieldComponent extends ItemPageFieldComponent { export class GenericItemPageFieldComponent extends ItemPageFieldComponent {

View File

@@ -4,12 +4,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
import { Observable } from 'rxjs';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { ItemPageFieldComponent } from './item-page-field.component'; import { ItemPageFieldComponent } from './item-page-field.component';
import { MetadataValuesComponent } from '../../../field-components/metadata-values/metadata-values.component'; import { MetadataValuesComponent } from '../../../field-components/metadata-values/metadata-values.component';
import { of as observableOf } from 'rxjs';
import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models'; import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';

View File

@@ -1,7 +1,7 @@
<div class="container" *ngVar="(itemRD$ | async) as itemRD"> <div class="container" *ngVar="(itemRD$ | async) as itemRD">
<div class="item-page" *ngIf="itemRD?.hasSucceeded" @fadeInOut> <div class="item-page" *ngIf="itemRD?.hasSucceeded" @fadeInOut>
<div *ngIf="itemRD?.payload as item"> <div *ngIf="itemRD?.payload as item">
<ds-item-type-switcher [object]="item" [viewMode]="viewMode"></ds-item-type-switcher> <ds-listable-object-component-loader [object]="item" [viewMode]="viewMode"></ds-listable-object-component-loader>
</div> </div>
</div> </div>
<ds-error *ngIf="itemRD?.hasFailed" message="{{'error.item' | translate}}"></ds-error> <ds-error *ngIf="itemRD?.hasFailed" message="{{'error.item' | translate}}"></ds-error>

View File

@@ -1,21 +1,18 @@
import { map } from 'rxjs/operators';
import { mergeMap, filter, map, take, tap } from 'rxjs/operators';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { ItemDataService } from '../../core/data/item-data.service'; import { ItemDataService } from '../../core/data/item-data.service';
import { RemoteData } from '../../core/data/remote-data'; import { RemoteData } from '../../core/data/remote-data';
import { Bitstream } from '../../core/shared/bitstream.model';
import { Item } from '../../core/shared/item.model'; import { Item } from '../../core/shared/item.model';
import { MetadataService } from '../../core/metadata/metadata.service'; import { MetadataService } from '../../core/metadata/metadata.service';
import { fadeInOut } from '../../shared/animations/fade'; import { fadeInOut } from '../../shared/animations/fade';
import { hasValue } from '../../shared/empty.util';
import { redirectToPageNotFoundOn404 } from '../../core/shared/operators'; import { redirectToPageNotFoundOn404 } from '../../core/shared/operators';
import { ItemViewMode } from '../../shared/items/item-type-decorator'; import { ViewMode } from '../../core/shared/view-mode.model';
/** /**
* This component renders a simple item page. * This component renders a simple item page.
@@ -44,7 +41,7 @@ export class ItemPageComponent implements OnInit {
/** /**
* The view-mode we're currently on * The view-mode we're currently on
*/ */
viewMode = ItemViewMode.Full; viewMode = ViewMode.StandalonePage;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -53,6 +50,9 @@ export class ItemPageComponent implements OnInit {
private metadataService: MetadataService, private metadataService: MetadataService,
) { } ) { }
/**
* Initialize instance variables
*/
ngOnInit(): void { ngOnInit(): void {
this.itemRD$ = this.route.data.pipe( this.itemRD$ = this.route.data.pipe(
map((data) => data.item as RemoteData<Item>), map((data) => data.item as RemoteData<Item>),

View File

@@ -1,72 +1,72 @@
<h2 class="item-page-title-field"> <h2 class="item-page-title-field">
{{'publication.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="item?.allMetadata(['dc.title'])"></ds-metadata-values> {{'publication.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper> <ds-metadata-field-wrapper>
<ds-thumbnail [thumbnail]="this.item.getThumbnail() | async"></ds-thumbnail> <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-item-page-file-section [item]="item"></ds-item-page-file-section> <ds-item-page-file-section [item]="object"></ds-item-page-file-section>
<ds-item-page-date-field [item]="item"></ds-item-page-date-field> <ds-item-page-date-field [item]="object"></ds-item-page-date-field>
<ds-item-page-author-field [item]="item"></ds-item-page-author-field> <ds-item-page-author-field [item]="object"></ds-item-page-author-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['journal.title']" [fields]="['journal.title']"
[label]="'publication.page.journal-title'"> [label]="'publication.page.journal-title'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['journal.identifier.issn']" [fields]="['journal.identifier.issn']"
[label]="'publication.page.journal-issn'"> [label]="'publication.page.journal-issn'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['journalvolume.identifier.name']" [fields]="['journalvolume.identifier.name']"
[label]="'publication.page.volume-title'"> [label]="'publication.page.volume-title'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['dc.publisher']" [fields]="['dc.publisher']"
[label]="'publication.page.publisher'"> [label]="'publication.page.publisher'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<ds-metadata-representation-list <ds-metadata-representation-list
[parentItem]="item" [parentItem]="object"
[itemType]="'Person'" [itemType]="'Person'"
[metadataField]="'dc.contributor.author'" [metadataField]="'dc.contributor.author'"
[label]="'relationships.isAuthorOf' | translate"> [label]="'relationships.isAuthorOf' | translate">
</ds-metadata-representation-list> </ds-metadata-representation-list>
<ds-related-items <ds-related-items
[parentItem]="item" [parentItem]="object"
[relationType]="'isProjectOfPublication'" [relationType]="'isProjectOfPublication'"
[label]="'relationships.isProjectOf' | translate"> [label]="'relationships.isProjectOf' | translate">
</ds-related-items> </ds-related-items>
<ds-related-items <ds-related-items
[parentItem]="item" [parentItem]="object"
[relationType]="'isOrgUnitOfPublication'" [relationType]="'isOrgUnitOfPublication'"
[label]="'relationships.isOrgUnitOf' | translate"> [label]="'relationships.isOrgUnitOf' | translate">
</ds-related-items> </ds-related-items>
<ds-related-items <ds-related-items
[parentItem]="item" [parentItem]="object"
[relationType]="'isJournalIssueOfPublication'" [relationType]="'isJournalIssueOfPublication'"
[label]="'relationships.isJournalIssueOf' | translate"> [label]="'relationships.isJournalIssueOf' | translate">
</ds-related-items> </ds-related-items>
<ds-item-page-abstract-field [item]="item"></ds-item-page-abstract-field> <ds-item-page-abstract-field [item]="object"></ds-item-page-abstract-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['dc.description']" [fields]="['dc.description']"
[label]="'publication.page.description'"> [label]="'publication.page.description'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['dc.subject']" [fields]="['dc.subject']"
[separator]="','" [separator]="','"
[label]="'item.page.subject'"> [label]="'item.page.subject'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['dc.identifier.citation']" [fields]="['dc.identifier.citation']"
[label]="'item.page.citation'"> [label]="'item.page.citation'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-item-page-uri-field [item]="item"></ds-item-page-uri-field> <ds-item-page-uri-field [item]="object"></ds-item-page-uri-field>
<ds-item-page-collections [item]="item"></ds-item-page-collections> <ds-item-page-collections [item]="object"></ds-item-page-collections>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + item.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -3,19 +3,16 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component'; import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
import { ItemDataService } from '../../../../core/data/item-data.service'; import { ItemDataService } from '../../../../core/data/item-data.service';
import { SearchFixedFilterService } from '../../../../+search-page/search-filters/search-filter/search-fixed-filter.service'; import { SearchFixedFilterService } from '../../../../+search-page/search-filters/search-filter/search-fixed-filter.service';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { createRelationshipsObservable } from '../shared/item.component.spec'; import { createRelationshipsObservable } from '../shared/item.component.spec';
import { PublicationComponent } from './publication.component'; import { PublicationComponent } from './publication.component';
import { of as observableOf } from 'rxjs';
import { MetadataMap } from '../../../../core/shared/metadata.models'; import { MetadataMap } from '../../../../core/shared/metadata.models';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
@@ -45,7 +42,6 @@ describe('PublicationComponent', () => {
})], })],
declarations: [PublicationComponent, GenericItemPageFieldComponent, TruncatePipe], declarations: [PublicationComponent, GenericItemPageFieldComponent, TruncatePipe],
providers: [ providers: [
{provide: ITEM, useValue: mockItem},
{provide: ItemDataService, useValue: {}}, {provide: ItemDataService, useValue: {}},
{provide: SearchFixedFilterService, useValue: searchFixedFilterServiceStub}, {provide: SearchFixedFilterService, useValue: searchFixedFilterServiceStub},
{provide: TruncatableService, useValue: {}} {provide: TruncatableService, useValue: {}}
@@ -60,6 +56,7 @@ describe('PublicationComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
fixture = TestBed.createComponent(PublicationComponent); fixture = TestBed.createComponent(PublicationComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.object = mockItem;
fixture.detectChanges(); fixture.detectChanges();
})); }));

View File

@@ -1,12 +1,15 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import {
DEFAULT_ITEM_TYPE, ItemViewMode,
rendersItemType
} from '../../../../shared/items/item-type-decorator';
import { ItemComponent } from '../shared/item.component'; import { ItemComponent } from '../shared/item.component';
import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { Item } from '../../../../core/shared/item.model';
import { ViewMode } from '../../../../core/shared/view-mode.model';
@rendersItemType('Publication', ItemViewMode.Full) /**
@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Full) * Component that represents a publication Item page
*/
@listableObjectComponent('Publication', ViewMode.StandalonePage)
@listableObjectComponent(Item, ViewMode.StandalonePage)
@Component({ @Component({
selector: 'ds-publication', selector: 'ds-publication',
styleUrls: ['./publication.component.scss'], styleUrls: ['./publication.component.scss'],

View File

@@ -7,17 +7,14 @@ import { ItemDataService } from '../../../../core/data/item-data.service';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { isNotEmpty } from '../../../../shared/empty.util'; import { isNotEmpty } from '../../../../shared/empty.util';
import { SearchFixedFilterService } from '../../../../+search-page/search-filters/search-filter/search-fixed-filter.service'; import { SearchFixedFilterService } from '../../../../+search-page/search-filters/search-filter/search-fixed-filter.service';
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model'; import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { RemoteData } from '../../../../core/data/remote-data';
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { ItemComponent } from './item.component'; import { ItemComponent } from './item.component';
import { of as observableOf } from 'rxjs';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { VarDirective } from '../../../../shared/utils/var.directive'; import { VarDirective } from '../../../../shared/utils/var.directive';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
@@ -56,7 +53,6 @@ export function getItemPageFieldsTest(mockItem: Item, component) {
})], })],
declarations: [component, GenericItemPageFieldComponent, TruncatePipe], declarations: [component, GenericItemPageFieldComponent, TruncatePipe],
providers: [ providers: [
{provide: ITEM, useValue: mockItem},
{provide: ItemDataService, useValue: {}}, {provide: ItemDataService, useValue: {}},
{provide: SearchFixedFilterService, useValue: searchFixedFilterServiceStub}, {provide: SearchFixedFilterService, useValue: searchFixedFilterServiceStub},
{provide: TruncatableService, useValue: {}} {provide: TruncatableService, useValue: {}}
@@ -71,6 +67,7 @@ export function getItemPageFieldsTest(mockItem: Item, component) {
beforeEach(async(() => { beforeEach(async(() => {
fixture = TestBed.createComponent(component); fixture = TestBed.createComponent(component);
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.object = mockItem;
fixture.detectChanges(); fixture.detectChanges();
})); }));

View File

@@ -1,6 +1,5 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject, Input } from '@angular/core';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
@Component({ @Component({
selector: 'ds-item', selector: 'ds-item',
@@ -10,9 +9,5 @@ import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.compo
* A generic component for displaying metadata and relations of an item * A generic component for displaying metadata and relations of an item
*/ */
export class ItemComponent { export class ItemComponent {
@Input() object: Item;
constructor(
@Inject(ITEM) public item: Item
) {}
} }

View File

@@ -1,7 +1,7 @@
<ds-metadata-field-wrapper *ngIf="representations$ && (representations$ | async)?.length > 0" [label]="label"> <ds-metadata-field-wrapper *ngIf="representations$ && (representations$ | async)?.length > 0" [label]="label">
<ds-item-type-switcher *ngFor="let rep of (representations$ | async)" <ds-metadata-representation-loader *ngFor="let rep of (representations$ | async)"
[object]="rep" [viewMode]="viewMode"> [mdRepresentation]="rep">
</ds-item-type-switcher> </ds-metadata-representation-loader>
<div *ngIf="(representations$ | async)?.length < total" class="mt-2"> <div *ngIf="(representations$ | async)?.length < total" class="mt-2">
<a [routerLink]="" (click)="viewMore()">{{'item.page.related-items.view-more' | translate}}</a> <a [routerLink]="" (click)="viewMore()">{{'item.page.related-items.view-more' | translate}}</a>
</div> </div>

View File

@@ -83,8 +83,8 @@ describe('MetadataRepresentationListComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
})); }));
it('should load 2 item-type-switcher components', () => { it('should load 2 ds-metadata-representation-loader components', () => {
const fields = fixture.debugElement.queryAll(By.css('ds-item-type-switcher')); const fields = fixture.debugElement.queryAll(By.css('ds-metadata-representation-loader'));
expect(fields.length).toBe(2); expect(fields.length).toBe(2);
}); });

View File

@@ -1,11 +1,10 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { MetadataRepresentation } from '../../../core/shared/metadata-representation/metadata-representation.model'; import { MetadataRepresentation } from '../../../core/shared/metadata-representation/metadata-representation.model';
import { ItemViewMode } from '../../../shared/items/item-type-decorator';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { RelationshipService } from '../../../core/data/relationship.service'; import { RelationshipService } from '../../../core/data/relationship.service';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { zip as observableZip, combineLatest as observableCombineLatest, of as observableOf } from 'rxjs'; import { combineLatest as observableCombineLatest, of as observableOf, zip as observableZip } from 'rxjs';
import { MetadataValue } from '../../../core/shared/metadata.models'; import { MetadataValue } from '../../../core/shared/metadata.models';
import { MetadatumRepresentation } from '../../../core/shared/metadata-representation/metadatum/metadatum-representation.model'; import { MetadatumRepresentation } from '../../../core/shared/metadata-representation/metadatum/metadatum-representation.model';
import { filter, map, switchMap } from 'rxjs/operators'; import { filter, map, switchMap } from 'rxjs/operators';
@@ -56,12 +55,6 @@ export class MetadataRepresentationListComponent implements OnInit {
*/ */
representations$: Observable<MetadataRepresentation[]>; representations$: Observable<MetadataRepresentation[]>;
/**
* The view-mode we're currently on
* @type {ElementViewMode}
*/
viewMode = ItemViewMode.Metadata;
/** /**
* The originally provided limit * The originally provided limit
* Used for resetting the limit to the original value when collapsing the list * Used for resetting the limit to the original value when collapsing the list

View File

@@ -1,14 +1,12 @@
import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core'; import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { ItemViewMode } from '../../../shared/items/item-type-decorator';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list'; import { PaginatedList } from '../../../core/data/paginated-list';
import { RelationshipService } from '../../../core/data/relationship.service'; import { RelationshipService } from '../../../core/data/relationship.service';
import { FindAllOptions } from '../../../core/data/request.models'; import { FindAllOptions } from '../../../core/data/request.models';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators';
import { hasNoValue, hasValueOperator } from '../../../shared/empty.util';
import { Subscription } from 'rxjs/internal/Subscription'; import { Subscription } from 'rxjs/internal/Subscription';
import { ViewMode } from '../../../core/shared/view-mode.model';
@Component({ @Component({
selector: 'ds-related-items', selector: 'ds-related-items',
@@ -61,7 +59,7 @@ export class RelatedItemsComponent implements OnInit, OnDestroy {
* The view-mode we're currently on * The view-mode we're currently on
* @type {ElementViewMode} * @type {ElementViewMode}
*/ */
viewMode = ItemViewMode.Element; viewMode = ViewMode.ListElement;
/** /**
* Whether or not the list is currently expanded to show all related items * Whether or not the list is currently expanded to show all related items

View File

@@ -1,7 +1,7 @@
<ds-metadata-field-wrapper *ngIf="(items$ | async)?.payload?.page?.length > 0" [label]="label"> <ds-metadata-field-wrapper *ngIf="(items$ | async)?.payload?.page?.length > 0" [label]="label">
<ds-item-type-switcher *ngFor="let item of (items$ | async)?.payload?.page" <ds-listable-object-component-loader *ngFor="let item of (items$ | async)?.payload?.page"
[object]="item" [viewMode]="viewMode"> [object]="item" [viewMode]="viewMode">
</ds-item-type-switcher> </ds-listable-object-component-loader>
<div *ngIf="(items$ | async)?.payload?.page?.length < (items$ | async)?.payload?.totalElements" class="mt-2" id="view-more"> <div *ngIf="(items$ | async)?.payload?.page?.length < (items$ | async)?.payload?.totalElements" class="mt-2" id="view-more">
<a [routerLink]="" (click)="viewMore()">{{'item.page.related-items.view-more' | translate}}</a> <a [routerLink]="" (click)="viewMore()">{{'item.page.related-items.view-more' | translate}}</a>
</div> </div>

View File

@@ -61,7 +61,7 @@ describe('RelatedItemsComponent', () => {
})); }));
it(`should load ${mockItems.length} item-type-switcher components`, () => { it(`should load ${mockItems.length} item-type-switcher components`, () => {
const fields = fixture.debugElement.queryAll(By.css('ds-item-type-switcher')); const fields = fixture.debugElement.queryAll(By.css('ds-listable-object-component-loader'));
expect(fields.length).toBe(mockItems.length); expect(fields.length).toBe(mockItems.length);
}); });

View File

@@ -7,7 +7,6 @@ import { TranslateService } from '@ngx-translate/core';
import { SubmissionState } from '../../submission/submission.reducers'; import { SubmissionState } from '../../submission/submission.reducers';
import { AuthService } from '../../core/auth/auth.service'; import { AuthService } from '../../core/auth/auth.service';
import { MyDSpaceResult } from '../my-dspace-result.model';
import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
@@ -15,6 +14,7 @@ import { UploaderOptions } from '../../shared/uploader/uploader-options.model';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { NotificationType } from '../../shared/notifications/models/notification-type'; import { NotificationType } from '../../shared/notifications/models/notification-type';
import { hasValue } from '../../shared/empty.util'; import { hasValue } from '../../shared/empty.util';
import { SearchResult } from '../../+search-page/search-result.model';
/** /**
* This component represents the whole mydspace page header * This component represents the whole mydspace page header
@@ -25,7 +25,10 @@ import { hasValue } from '../../shared/empty.util';
templateUrl: './my-dspace-new-submission.component.html' templateUrl: './my-dspace-new-submission.component.html'
}) })
export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit { export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit {
@Output() uploadEnd = new EventEmitter<Array<MyDSpaceResult<DSpaceObject>>>(); /**
* Output that emits the workspace item when the upload has completed
*/
@Output() uploadEnd = new EventEmitter<Array<SearchResult<DSpaceObject>>>();
/** /**
* The UploaderOptions object * The UploaderOptions object

View File

@@ -39,7 +39,8 @@
</button> </button>
</div> </div>
<ds-my-dspace-results [searchResults]="resultsRD$ | async" <ds-my-dspace-results [searchResults]="resultsRD$ | async"
[searchConfig]="searchOptions$ | async"></ds-my-dspace-results> [searchConfig]="searchOptions$ | async"
[context]="context$ | async"></ds-my-dspace-results>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -8,7 +8,7 @@ import {
} from '@angular/core'; } from '@angular/core';
import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { switchMap, tap, } from 'rxjs/operators'; import { map, switchMap, tap, } from 'rxjs/operators';
import { PaginatedList } from '../core/data/paginated-list'; import { PaginatedList } from '../core/data/paginated-list';
import { RemoteData } from '../core/data/remote-data'; import { RemoteData } from '../core/data/remote-data';
@@ -20,7 +20,6 @@ import { SearchService } from '../+search-page/search-service/search.service';
import { SearchSidebarService } from '../+search-page/search-sidebar/search-sidebar.service'; import { SearchSidebarService } from '../+search-page/search-sidebar/search-sidebar.service';
import { hasValue } from '../shared/empty.util'; import { hasValue } from '../shared/empty.util';
import { getSucceededRemoteData } from '../core/shared/operators'; import { getSucceededRemoteData } from '../core/shared/operators';
import { MyDSpaceResult } from './my-dspace-result.model';
import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service'; import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service';
import { SearchConfigurationOption } from '../+search-page/search-switch-configuration/search-configuration-option.model'; import { SearchConfigurationOption } from '../+search-page/search-switch-configuration/search-configuration-option.model';
import { RoleType } from '../core/roles/role-types'; import { RoleType } from '../core/roles/role-types';
@@ -28,6 +27,8 @@ import { SearchConfigurationService } from '../+search-page/search-service/searc
import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; import { MyDSpaceConfigurationService } from './my-dspace-configuration.service';
import { ViewMode } from '../core/shared/view-mode.model'; import { ViewMode } from '../core/shared/view-mode.model';
import { MyDSpaceRequest } from '../core/data/request.models'; import { MyDSpaceRequest } from '../core/data/request.models';
import { SearchResult } from '../+search-page/search-result.model';
import { Context } from '../core/shared/context.model';
export const MYDSPACE_ROUTE = '/mydspace'; export const MYDSPACE_ROUTE = '/mydspace';
export const SEARCH_CONFIG_SERVICE: InjectionToken<SearchConfigurationService> = new InjectionToken<SearchConfigurationService>('searchConfigurationService'); export const SEARCH_CONFIG_SERVICE: InjectionToken<SearchConfigurationService> = new InjectionToken<SearchConfigurationService>('searchConfigurationService');
@@ -63,7 +64,7 @@ export class MyDSpacePageComponent implements OnInit {
/** /**
* The current search results * The current search results
*/ */
resultsRD$: BehaviorSubject<RemoteData<PaginatedList<MyDSpaceResult<DSpaceObject>>>> = new BehaviorSubject(null); resultsRD$: BehaviorSubject<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> = new BehaviorSubject(null);
/** /**
* The current paginated search options * The current paginated search options
@@ -93,7 +94,12 @@ export class MyDSpacePageComponent implements OnInit {
/** /**
* List of available view mode * List of available view mode
*/ */
viewModeList = [ViewMode.List, ViewMode.Detail]; viewModeList = [ViewMode.ListElement, ViewMode.DetailedListElement];
/**
* The current context of this page: workspace or workflow
*/
context$: Observable<Context>;
constructor(private service: SearchService, constructor(private service: SearchService,
private sidebarService: SearchSidebarService, private sidebarService: SearchSidebarService,
@@ -111,6 +117,9 @@ export class MyDSpacePageComponent implements OnInit {
* *
* Listen to changes in the scope * Listen to changes in the scope
* If something changes, update the list of scopes for the dropdown * If something changes, update the list of scopes for the dropdown
*
* Listen to changes in the configuration
* If something changes, update the current context
*/ */
ngOnInit(): void { ngOnInit(): void {
this.configurationList$ = this.searchConfigService.getAvailableConfigurationOptions(); this.configurationList$ = this.searchConfigService.getAvailableConfigurationOptions();
@@ -126,6 +135,17 @@ export class MyDSpacePageComponent implements OnInit {
switchMap((scopeId) => this.service.getScopes(scopeId)) switchMap((scopeId) => this.service.getScopes(scopeId))
); );
this.context$ = this.searchConfigService.getCurrentConfiguration('workspace')
.pipe(
map((configuration: string) => {
if (configuration === 'workspace') {
return Context.Workspace
} else {
return Context.Workflow
}
})
);
} }
/** /**

View File

@@ -7,19 +7,20 @@ import { MyDspacePageRoutingModule } from './my-dspace-page-routing.module';
import { MyDSpacePageComponent } from './my-dspace-page.component'; import { MyDSpacePageComponent } from './my-dspace-page.component';
import { SearchPageModule } from '../+search-page/search-page.module'; import { SearchPageModule } from '../+search-page/search-page.module';
import { MyDSpaceResultsComponent } from './my-dspace-results/my-dspace-results.component'; import { MyDSpaceResultsComponent } from './my-dspace-results/my-dspace-results.component';
import { WorkspaceitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component'; import { WorkspaceItemSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component';
import { ItemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component'; import { ClaimedSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component';
import { WorkflowitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component'; import { PoolSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component';
import { ClaimedMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component';
import { PoolMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component';
import { MyDSpaceNewSubmissionComponent } from './my-dspace-new-submission/my-dspace-new-submission.component'; import { MyDSpaceNewSubmissionComponent } from './my-dspace-new-submission/my-dspace-new-submission.component';
import { ItemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component'; import { ItemSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component';
import { WorkspaceitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component'; import { WorkspaceItemSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component';
import { WorkflowitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component'; import { WorkflowItemSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component';
import { ClaimedMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component'; import { ClaimedTaskSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component';
import { PoolMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component';
import { MyDSpaceGuard } from './my-dspace.guard'; import { MyDSpaceGuard } from './my-dspace.guard';
import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; import { MyDSpaceConfigurationService } from './my-dspace-configuration.service';
import { SearchResultListElementComponent } from '../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResultListElementSubmissionComponent } from '../shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component';
import { WorkflowItemSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component';
import { PoolSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -31,33 +32,34 @@ import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'
declarations: [ declarations: [
MyDSpacePageComponent, MyDSpacePageComponent,
MyDSpaceResultsComponent, MyDSpaceResultsComponent,
ItemMyDSpaceResultListElementComponent, WorkspaceItemSearchResultListElementComponent,
WorkspaceitemMyDSpaceResultListElementComponent, WorkflowItemSearchResultListElementComponent,
WorkflowitemMyDSpaceResultListElementComponent, ClaimedSearchResultListElementComponent,
ClaimedMyDSpaceResultListElementComponent, PoolSearchResultListElementComponent,
PoolMyDSpaceResultListElementComponent, ItemSearchResultDetailElementComponent,
ItemMyDSpaceResultDetailElementComponent, WorkspaceItemSearchResultDetailElementComponent,
WorkspaceitemMyDSpaceResultDetailElementComponent, WorkflowItemSearchResultDetailElementComponent,
WorkflowitemMyDSpaceResultDetailElementComponent, ClaimedTaskSearchResultDetailElementComponent,
ClaimedMyDSpaceResultDetailElementComponent, PoolSearchResultDetailElementComponent,
PoolMyDSpaceResultDetailElementComponent, MyDSpaceNewSubmissionComponent,
MyDSpaceNewSubmissionComponent ItemSearchResultListElementSubmissionComponent
], ],
providers: [ providers: [
MyDSpaceGuard, MyDSpaceGuard,
MyDSpaceConfigurationService MyDSpaceConfigurationService
], ],
entryComponents: [ entryComponents: [
ItemMyDSpaceResultListElementComponent, SearchResultListElementComponent,
WorkspaceitemMyDSpaceResultListElementComponent, WorkspaceItemSearchResultListElementComponent,
WorkflowitemMyDSpaceResultListElementComponent, WorkflowItemSearchResultListElementComponent,
ClaimedMyDSpaceResultListElementComponent, ClaimedSearchResultListElementComponent,
PoolMyDSpaceResultListElementComponent, PoolSearchResultListElementComponent,
ItemMyDSpaceResultDetailElementComponent, ItemSearchResultDetailElementComponent,
WorkspaceitemMyDSpaceResultDetailElementComponent, WorkspaceItemSearchResultDetailElementComponent,
WorkflowitemMyDSpaceResultDetailElementComponent, WorkflowItemSearchResultDetailElementComponent,
ClaimedMyDSpaceResultDetailElementComponent, ClaimedTaskSearchResultDetailElementComponent,
PoolMyDSpaceResultDetailElementComponent PoolSearchResultDetailElementComponent,
ItemSearchResultListElementSubmissionComponent
] ]
}) })

View File

@@ -1,19 +0,0 @@
import { DSpaceObject } from '../core/shared/dspace-object.model';
import { MetadataMap } from '../core/shared/metadata.models';
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
/**
* Represents a search result object of a certain (<T>) DSpaceObject
*/
export class MyDSpaceResult<T extends DSpaceObject> implements ListableObject {
/**
* The DSpaceObject that was found
*/
indexableObject: T;
/**
* The metadata that was used to find this item, hithighlighted
*/
hitHighlights: MetadataMap;
}

View File

@@ -4,7 +4,8 @@
[hasBorder]="hasBorder" [hasBorder]="hasBorder"
[sortConfig]="searchConfig.sort" [sortConfig]="searchConfig.sort"
[objects]="searchResults" [objects]="searchResults"
[hideGear]="true"> [hideGear]="true"
[context]="context">
</ds-viewable-collection> </ds-viewable-collection>
</div> </div>
<ds-loading *ngIf="isLoading()" message="{{'loading.mydspace-results' | translate}}"></ds-loading> <ds-loading *ngIf="isLoading()" message="{{'loading.mydspace-results' | translate}}"></ds-loading>

View File

@@ -1,13 +1,13 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { RemoteData } from '../../core/data/remote-data'; import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { fadeIn, fadeInOut } from '../../shared/animations/fade'; import { fadeIn, fadeInOut } from '../../shared/animations/fade';
import { MyDSpaceResult } from '../my-dspace-result.model';
import { SearchOptions } from '../../+search-page/search-options.model'; import { SearchOptions } from '../../+search-page/search-options.model';
import { PaginatedList } from '../../core/data/paginated-list'; import { PaginatedList } from '../../core/data/paginated-list';
import { ViewMode } from '../../core/shared/view-mode.model'; import { ViewMode } from '../../core/shared/view-mode.model';
import { isEmpty } from '../../shared/empty.util'; import { isEmpty } from '../../shared/empty.util';
import { SearchResult } from '../../+search-page/search-result.model';
import { Context } from '../../core/shared/context.model';
/** /**
* Component that represents all results for mydspace page * Component that represents all results for mydspace page
@@ -25,7 +25,7 @@ export class MyDSpaceResultsComponent {
/** /**
* The actual search result objects * The actual search result objects
*/ */
@Input() searchResults: RemoteData<PaginatedList<MyDSpaceResult<DSpaceObject>>>; @Input() searchResults: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>;
/** /**
* The current configuration of the search * The current configuration of the search
@@ -37,6 +37,10 @@ export class MyDSpaceResultsComponent {
*/ */
@Input() viewMode: ViewMode; @Input() viewMode: ViewMode;
/**
* The current context for the search results
*/
@Input() context: Context;
/** /**
* A boolean representing if search results entry are separated by a line * A boolean representing if search results entry are separated by a line
*/ */

View File

@@ -1,13 +1,12 @@
import { autoserialize, inheritSerialization } from 'cerialize'; import { autoserialize, inheritSerialization } from 'cerialize';
import { MetadataMap } from '../core/shared/metadata.models'; import { MetadataMap } from '../core/shared/metadata.models';
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
import { NormalizedObject } from '../core/cache/models/normalized-object.model'; import { NormalizedObject } from '../core/cache/models/normalized-object.model';
/** /**
* Represents a normalized version of a search result object of a certain DSpaceObject * Represents a normalized version of a search result object of a certain DSpaceObject
*/ */
@inheritSerialization(NormalizedObject) @inheritSerialization(NormalizedObject)
export class NormalizedSearchResult implements ListableObject { export class NormalizedSearchResult {
/** /**
* The UUID of the DSpaceObject that was found * The UUID of the DSpaceObject that was found
*/ */
@@ -19,5 +18,4 @@ export class NormalizedSearchResult implements ListableObject {
*/ */
@autoserialize @autoserialize
hitHighlights: MetadataMap; hitHighlights: MetadataMap;
} }

View File

@@ -71,7 +71,7 @@ export class SearchFiltersComponent implements OnInit {
/** /**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true * @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/ */
private getSearchLink(): string { getSearchLink(): string {
if (this.inPlaceSearch) { if (this.inPlaceSearch) {
return './'; return './';
} }

View File

@@ -3,14 +3,14 @@ import { URLCombiner } from '../core/url-combiner/url-combiner';
import 'core-js/library/fn/object/entries'; import 'core-js/library/fn/object/entries';
import { SearchFilter } from './search-filter.model'; import { SearchFilter } from './search-filter.model';
import { DSpaceObjectType } from '../core/shared/dspace-object-type.model'; import { DSpaceObjectType } from '../core/shared/dspace-object-type.model';
import { SetViewMode } from '../shared/view-mode'; import { ViewMode } from '../core/shared/view-mode.model';
/** /**
* This model class represents all parameters needed to request information about a certain search request * This model class represents all parameters needed to request information about a certain search request
*/ */
export class SearchOptions { export class SearchOptions {
configuration?: string; configuration?: string;
view?: SetViewMode = SetViewMode.List; view?: ViewMode = ViewMode.ListElement;
scope?: string; scope?: string;
query?: string; query?: string;
dsoType?: DSpaceObjectType; dsoType?: DSpaceObjectType;

View File

@@ -5,7 +5,6 @@ import { SharedModule } from '../shared/shared.module';
import { SearchPageRoutingModule } from './search-page-routing.module'; import { SearchPageRoutingModule } from './search-page-routing.module';
import { SearchPageComponent } from './search-page.component'; import { SearchPageComponent } from './search-page.component';
import { SearchResultsComponent } from './search-results/search-results.component'; import { SearchResultsComponent } from './search-results/search-results.component';
import { ItemSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component';
import { CommunitySearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component' import { CommunitySearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component'
import { CollectionSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component'; import { CollectionSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component';
import { SearchSidebarComponent } from './search-sidebar/search-sidebar.component'; import { SearchSidebarComponent } from './search-sidebar/search-sidebar.component';
@@ -44,9 +43,6 @@ const components = [
SearchResultsComponent, SearchResultsComponent,
SearchSidebarComponent, SearchSidebarComponent,
SearchSettingsComponent, SearchSettingsComponent,
ItemSearchResultGridElementComponent,
CollectionSearchResultGridElementComponent,
CommunitySearchResultGridElementComponent,
SearchFiltersComponent, SearchFiltersComponent,
SearchFilterComponent, SearchFilterComponent,
SearchFacetFilterComponent, SearchFacetFilterComponent,
@@ -84,9 +80,6 @@ const components = [
SearchConfigurationService SearchConfigurationService
], ],
entryComponents: [ entryComponents: [
ItemSearchResultGridElementComponent,
CollectionSearchResultGridElementComponent,
CommunitySearchResultGridElementComponent,
SearchFacetFilterComponent, SearchFacetFilterComponent,
SearchRangeFilterComponent, SearchRangeFilterComponent,
SearchTextFilterComponent, SearchTextFilterComponent,

View File

@@ -1,6 +1,7 @@
import { DSpaceObject } from '../core/shared/dspace-object.model'; import { DSpaceObject } from '../core/shared/dspace-object.model';
import { MetadataMap } from '../core/shared/metadata.models'; import { MetadataMap } from '../core/shared/metadata.models';
import { ListableObject } from '../shared/object-collection/shared/listable-object.model'; import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
import { GenericConstructor } from '../core/shared/generic-constructor';
/** /**
* Represents a search result object of a certain (<T>) DSpaceObject * Represents a search result object of a certain (<T>) DSpaceObject
@@ -16,4 +17,10 @@ export class SearchResult<T extends DSpaceObject> implements ListableObject {
*/ */
hitHighlights: MetadataMap; hitHighlights: MetadataMap;
/**
* Method that returns as which type of object this object should be rendered
*/
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
return [this.constructor as GenericConstructor<ListableObject>];
}
} }

View File

@@ -4,6 +4,7 @@
[config]="searchConfig.pagination" [config]="searchConfig.pagination"
[sortConfig]="searchConfig.sort" [sortConfig]="searchConfig.sort"
[objects]="searchResults" [objects]="searchResults"
[linkType]="linkType"
[hideGear]="true"> [hideGear]="true">
</ds-viewable-collection></div> </ds-viewable-collection></div>
<ds-loading *ngIf="hasNoValue(searchResults) || hasNoValue(searchResults.payload) || searchResults.isLoading" message="{{'loading.search-results' | translate}}"></ds-loading> <ds-loading *ngIf="hasNoValue(searchResults) || hasNoValue(searchResults.payload) || searchResults.isLoading" message="{{'loading.search-results' | translate}}"></ds-loading>

View File

@@ -2,12 +2,13 @@ import { Component, Input } from '@angular/core';
import { RemoteData } from '../../core/data/remote-data'; import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { fadeIn, fadeInOut } from '../../shared/animations/fade'; import { fadeIn, fadeInOut } from '../../shared/animations/fade';
import { SetViewMode } from '../../shared/view-mode';
import { SearchOptions } from '../search-options.model'; import { SearchOptions } from '../search-options.model';
import { SearchResult } from '../search-result.model'; import { SearchResult } from '../search-result.model';
import { PaginatedList } from '../../core/data/paginated-list'; import { PaginatedList } from '../../core/data/paginated-list';
import { hasNoValue, isNotEmpty } from '../../shared/empty.util'; import { hasNoValue, isNotEmpty } from '../../shared/empty.util';
import { SortOptions } from '../../core/cache/models/sort-options.model'; import { SortOptions } from '../../core/cache/models/sort-options.model';
import { ViewMode } from '../../core/shared/view-mode.model';
import { CollectionElementLinkType } from '../../shared/object-collection/collection-element-link.type';
@Component({ @Component({
selector: 'ds-search-results', selector: 'ds-search-results',
@@ -24,6 +25,11 @@ import { SortOptions } from '../../core/cache/models/sort-options.model';
export class SearchResultsComponent { export class SearchResultsComponent {
hasNoValue = hasNoValue; hasNoValue = hasNoValue;
/**
* The link type of the listed search results
*/
@Input() linkType: CollectionElementLinkType;
/** /**
* The actual search result objects * The actual search result objects
*/ */
@@ -42,7 +48,7 @@ export class SearchResultsComponent {
/** /**
* The current view-mode of the list * The current view-mode of the list
*/ */
@Input() viewMode: SetViewMode; @Input() viewMode: ViewMode;
/** /**
* An optional configuration to filter the result on one type * An optional configuration to filter the result on one type

View File

@@ -12,19 +12,12 @@ const searchResultMap = new Map();
* @param {GenericConstructor<ListableObject>} domainConstructor The constructor of the DSpaceObject * @param {GenericConstructor<ListableObject>} domainConstructor The constructor of the DSpaceObject
* @returns Decorator function that performs the actual mapping on initialization of the component * @returns Decorator function that performs the actual mapping on initialization of the component
*/ */
export function searchResultFor(domainConstructor: GenericConstructor<ListableObject>, configuration: string = null) { export function searchResultFor(domainConstructor: GenericConstructor<ListableObject>) {
return function decorator(searchResult: any) { return function decorator(searchResult: any) {
if (!searchResult) { if (!searchResult) {
return; return;
} }
if (isNull(configuration)) { searchResultMap.set(domainConstructor, searchResult);
searchResultMap.set(domainConstructor, searchResult);
} else {
if (!searchResultMap.get(configuration)) {
searchResultMap.set(configuration, new Map());
}
searchResultMap.get(configuration).set(domainConstructor, searchResult);
}
}; };
} }
@@ -33,10 +26,6 @@ export function searchResultFor(domainConstructor: GenericConstructor<ListableOb
* @param {GenericConstructor<ListableObject>} domainConstructor The DSpaceObject's constructor for which the search result component is requested * @param {GenericConstructor<ListableObject>} domainConstructor The DSpaceObject's constructor for which the search result component is requested
* @returns The component's constructor that matches the given DSpaceObject * @returns The component's constructor that matches the given DSpaceObject
*/ */
export function getSearchResultFor(domainConstructor: GenericConstructor<ListableObject>, configuration: string = null) { export function getSearchResultFor(domainConstructor: GenericConstructor<ListableObject>) {
if (isNull(configuration) || configuration === 'default' || hasNoValue(searchResultMap.get(configuration))) {
return searchResultMap.get(domainConstructor); return searchResultMap.get(domainConstructor);
} else {
return searchResultMap.get(configuration).get(domainConstructor);
}
} }

View File

@@ -5,9 +5,6 @@ import { CommonModule } from '@angular/common';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SearchService } from './search.service'; import { SearchService } from './search.service';
import { ItemDataService } from './../../core/data/item-data.service';
import { SetViewMode } from '../../shared/view-mode';
import { GLOBAL_CONFIG } from '../../../config';
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
import { Router, UrlTree } from '@angular/router'; import { Router, UrlTree } from '@angular/router';
import { RequestService } from '../../core/data/request.service'; import { RequestService } from '../../core/data/request.service';
@@ -66,7 +63,7 @@ describe('SearchService', () => {
it('should return list view mode', () => { it('should return list view mode', () => {
searchService.getViewMode().subscribe((viewMode) => { searchService.getViewMode().subscribe((viewMode) => {
expect(viewMode).toBe(ViewMode.List); expect(viewMode).toBe(ViewMode.ListElement);
}); });
}); });
}); });
@@ -125,38 +122,38 @@ describe('SearchService', () => {
}); });
it('should call the navigate method on the Router with view mode list parameter as a parameter when setViewMode is called', () => { it('should call the navigate method on the Router with view mode list parameter as a parameter when setViewMode is called', () => {
searchService.setViewMode(ViewMode.List); searchService.setViewMode(ViewMode.ListElement);
expect(router.navigate).toHaveBeenCalledWith(['/search'], { expect(router.navigate).toHaveBeenCalledWith(['/search'], {
queryParams: { view: ViewMode.List, page: 1 }, queryParams: { view: ViewMode.ListElement, page: 1 },
queryParamsHandling: 'merge' queryParamsHandling: 'merge'
}); });
}); });
it('should call the navigate method on the Router with view mode grid parameter as a parameter when setViewMode is called', () => { it('should call the navigate method on the Router with view mode grid parameter as a parameter when setViewMode is called', () => {
searchService.setViewMode(ViewMode.Grid); searchService.setViewMode(ViewMode.GridElement);
expect(router.navigate).toHaveBeenCalledWith(['/search'], { expect(router.navigate).toHaveBeenCalledWith(['/search'], {
queryParams: { view: ViewMode.Grid, page: 1 }, queryParams: { view: ViewMode.GridElement, page: 1 },
queryParamsHandling: 'merge' queryParamsHandling: 'merge'
}); });
}); });
it('should return ViewMode.List when the viewMode is set to ViewMode.List in the ActivatedRoute', () => { it('should return ViewMode.List when the viewMode is set to ViewMode.List in the ActivatedRoute', () => {
let viewMode = ViewMode.Grid; let viewMode = ViewMode.GridElement;
spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([ spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([
[ 'view', ViewMode.List ], [ 'view', ViewMode.ListElement ],
]))); ])));
searchService.getViewMode().subscribe((mode) => viewMode = mode); searchService.getViewMode().subscribe((mode) => viewMode = mode);
expect(viewMode).toEqual(ViewMode.List); expect(viewMode).toEqual(ViewMode.ListElement);
}); });
it('should return ViewMode.Grid when the viewMode is set to ViewMode.Grid in the ActivatedRoute', () => { it('should return ViewMode.Grid when the viewMode is set to ViewMode.Grid in the ActivatedRoute', () => {
let viewMode = ViewMode.List; let viewMode = ViewMode.ListElement;
spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([ spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([
[ 'view', ViewMode.Grid ], [ 'view', ViewMode.GridElement ],
]))); ])));
searchService.getViewMode().subscribe((mode) => viewMode = mode); searchService.getViewMode().subscribe((mode) => viewMode = mode);
expect(viewMode).toEqual(ViewMode.Grid); expect(viewMode).toEqual(ViewMode.GridElement);
}); });
describe('when search is called', () => { describe('when search is called', () => {

View File

@@ -160,7 +160,7 @@ export class SearchService implements OnDestroy {
let co = DSpaceObject; let co = DSpaceObject;
if (dsos.payload[index]) { if (dsos.payload[index]) {
const constructor: GenericConstructor<ListableObject> = dsos.payload[index].constructor as GenericConstructor<ListableObject>; const constructor: GenericConstructor<ListableObject> = dsos.payload[index].constructor as GenericConstructor<ListableObject>;
co = getSearchResultFor(constructor, searchOptions.configuration); co = getSearchResultFor(constructor);
return Object.assign(new co(), object, { return Object.assign(new co(), object, {
indexableObject: dsos.payload[index] indexableObject: dsos.payload[index]
}); });
@@ -341,7 +341,7 @@ export class SearchService implements OnDestroy {
if (isNotEmpty(params.get('view')) && hasValue(params.get('view'))) { if (isNotEmpty(params.get('view')) && hasValue(params.get('view'))) {
return params.get('view'); return params.get('view');
} else { } else {
return ViewMode.List; return ViewMode.ListElement;
} }
})); }));
} }
@@ -354,7 +354,7 @@ export class SearchService implements OnDestroy {
this.routeService.getQueryParameterValue('pageSize').pipe(first()) this.routeService.getQueryParameterValue('pageSize').pipe(first())
.subscribe((pageSize) => { .subscribe((pageSize) => {
let queryParams = { view: viewMode, page: 1 }; let queryParams = { view: viewMode, page: 1 };
if (viewMode === ViewMode.Detail) { if (viewMode === ViewMode.DetailedListElement) {
queryParams = Object.assign(queryParams, {pageSize: '1'}); queryParams = Object.assign(queryParams, {pageSize: '1'});
} else if (pageSize === '1') { } else if (pageSize === '1') {
queryParams = Object.assign(queryParams, {pageSize: '10'}); queryParams = Object.assign(queryParams, {pageSize: '10'});

View File

@@ -1,7 +1,6 @@
import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
import { CacheableObject } from '../../cache/object-cache.reducer'; import { CacheableObject } from '../../cache/object-cache.reducer';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
import { EPerson } from './eperson.model'; import { EPerson } from './eperson.model';
import { mapsTo, relationship } from '../../cache/builders/build-decorators'; import { mapsTo, relationship } from '../../cache/builders/build-decorators';
@@ -9,7 +8,7 @@ import { Group } from './group.model';
@mapsTo(EPerson) @mapsTo(EPerson)
@inheritSerialization(NormalizedDSpaceObject) @inheritSerialization(NormalizedDSpaceObject)
export class NormalizedEPerson extends NormalizedDSpaceObject<EPerson> implements CacheableObject, ListableObject { export class NormalizedEPerson extends NormalizedDSpaceObject<EPerson> implements CacheableObject {
/** /**
* A string representing the unique handle of this EPerson * A string representing the unique handle of this EPerson
*/ */

View File

@@ -1,14 +1,13 @@
import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
import { CacheableObject } from '../../cache/object-cache.reducer'; import { CacheableObject } from '../../cache/object-cache.reducer';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
import { mapsTo, relationship } from '../../cache/builders/build-decorators'; import { mapsTo, relationship } from '../../cache/builders/build-decorators';
import { Group } from './group.model'; import { Group } from './group.model';
@mapsTo(Group) @mapsTo(Group)
@inheritSerialization(NormalizedDSpaceObject) @inheritSerialization(NormalizedDSpaceObject)
export class NormalizedGroup extends NormalizedDSpaceObject<Group> implements CacheableObject, ListableObject { export class NormalizedGroup extends NormalizedDSpaceObject<Group> implements CacheableObject {
/** /**
* List of Groups that this Group belong to * List of Groups that this Group belong to

View File

@@ -2,6 +2,7 @@ import { ListableObject } from '../../shared/object-collection/shared/listable-o
import { isNotEmpty } from '../../shared/empty.util'; import { isNotEmpty } from '../../shared/empty.util';
import { MetadataSchema } from './metadata-schema.model'; import { MetadataSchema } from './metadata-schema.model';
import { ResourceType } from '../shared/resource-type'; import { ResourceType } from '../shared/resource-type';
import { GenericConstructor } from '../shared/generic-constructor';
/** /**
* Class the represents a metadata field * Class the represents a metadata field
@@ -50,4 +51,11 @@ export class MetadataField implements ListableObject {
} }
return key; return key;
} }
/**
* Method that returns as which type of object this object should be rendered
*/
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
return [this.constructor as GenericConstructor<ListableObject>];
}
} }

View File

@@ -1,5 +1,6 @@
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
import { ResourceType } from '../shared/resource-type'; import { ResourceType } from '../shared/resource-type';
import { GenericConstructor } from '../shared/generic-constructor';
/** /**
* Class that represents a metadata schema * Class that represents a metadata schema
@@ -26,4 +27,11 @@ export class MetadataSchema implements ListableObject {
* The namespace of this metadata schema * The namespace of this metadata schema
*/ */
namespace: string; namespace: string;
/**
* Method that returns as which type of object this object should be rendered
*/
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
return [this.constructor as GenericConstructor<ListableObject>];
}
} }

View File

@@ -10,7 +10,7 @@ import { MetadataSchema } from './metadata-schema.model';
*/ */
@mapsTo(MetadataField) @mapsTo(MetadataField)
@inheritSerialization(NormalizedObject) @inheritSerialization(NormalizedObject)
export class NormalizedMetadataField extends NormalizedObject<MetadataField> implements ListableObject { export class NormalizedMetadataField extends NormalizedObject<MetadataField> {
/** /**
* The identifier of this normalized metadata field * The identifier of this normalized metadata field

View File

@@ -9,7 +9,7 @@ import { MetadataSchema } from './metadata-schema.model';
*/ */
@mapsTo(MetadataSchema) @mapsTo(MetadataSchema)
@inheritSerialization(NormalizedObject) @inheritSerialization(NormalizedObject)
export class NormalizedMetadataSchema extends NormalizedObject<MetadataSchema> implements ListableObject { export class NormalizedMetadataSchema extends NormalizedObject<MetadataSchema> {
/** /**
* The unique identifier for this schema * The unique identifier for this schema
*/ */

View File

@@ -55,22 +55,24 @@ describe('RegistryService', () => {
}); });
const mockSchemasList = [ const mockSchemasList = [
{ Object.assign(new MetadataSchema(), {
id: 1, id: 1,
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1', self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1',
prefix: 'dc', prefix: 'dc',
namespace: 'http://dublincore.org/documents/dcmi-terms/', namespace: 'http://dublincore.org/documents/dcmi-terms/',
type: MetadataSchema.type type: MetadataSchema.type
}, }),
{ Object.assign(new MetadataSchema(), {
id: 2, id: 2,
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2', self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2',
prefix: 'mock', prefix: 'mock',
namespace: 'http://dspace.org/mockschema', namespace: 'http://dspace.org/mockschema',
type: MetadataSchema.type type: MetadataSchema.type
} })
]; ];
const mockFieldsList = [ const mockFieldsList = [
Object.assign(new MetadataField(),
{ {
id: 1, id: 1,
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8', self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8',
@@ -79,8 +81,9 @@ describe('RegistryService', () => {
scopeNote: null, scopeNote: null,
schema: mockSchemasList[0], schema: mockSchemasList[0],
type: MetadataField.type type: MetadataField.type
}, }),
{ Object.assign(new MetadataField(),
{
id: 2, id: 2,
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9', self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9',
element: 'contributor', element: 'contributor',
@@ -88,8 +91,9 @@ describe('RegistryService', () => {
scopeNote: null, scopeNote: null,
schema: mockSchemasList[0], schema: mockSchemasList[0],
type: MetadataField.type type: MetadataField.type
}, }),
{ Object.assign(new MetadataField(),
{
id: 3, id: 3,
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10', self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10',
element: 'contributor', element: 'contributor',
@@ -97,8 +101,9 @@ describe('RegistryService', () => {
scopeNote: 'test scope note', scopeNote: 'test scope note',
schema: mockSchemasList[1], schema: mockSchemasList[1],
type: MetadataField.type type: MetadataField.type
}, }),
{ Object.assign(new MetadataField(),
{
id: 4, id: 4,
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11', self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11',
element: 'contributor', element: 'contributor',
@@ -106,7 +111,7 @@ describe('RegistryService', () => {
scopeNote: null, scopeNote: null,
schema: mockSchemasList[1], schema: mockSchemasList[1],
type: MetadataField.type type: MetadataField.type
} })
]; ];
const pageInfo = new PageInfo(); const pageInfo = new PageInfo();

View File

@@ -400,7 +400,7 @@ export class RegistryService {
distinctUntilChanged() distinctUntilChanged()
); );
const serializedSchema = new DSpaceRESTv2Serializer(getMapsToType(MetadataSchema.type)).serialize(schema as NormalizedMetadataSchema); const serializedSchema = new DSpaceRESTv2Serializer(getMapsToType(MetadataSchema.type)).serialize(schema);
const request$ = endpoint$.pipe( const request$ = endpoint$.pipe(
take(1), take(1),

View File

@@ -1,12 +1,13 @@
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
import { TypedObject } from '../cache/object-cache.reducer'; import { TypedObject } from '../cache/object-cache.reducer';
import { ResourceType } from './resource-type'; import { ResourceType } from './resource-type';
import { GenericConstructor } from './generic-constructor';
/** /**
* Class object representing a browse entry * Class object representing a browse entry
* This class is not normalized because browse entries do not have self links * This class is not normalized because browse entries do not have self links
*/ */
export class BrowseEntry implements ListableObject, TypedObject { export class BrowseEntry implements ListableObject {
static type = new ResourceType('browseEntry'); static type = new ResourceType('browseEntry');
/** /**
@@ -28,4 +29,11 @@ export class BrowseEntry implements ListableObject, TypedObject {
* The count of this browse entry * The count of this browse entry
*/ */
count: number; count: number;
/**
* Method that returns as which type of object this object should be rendered
*/
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
return [this.constructor as GenericConstructor<ListableObject>];
}
} }

View File

@@ -0,0 +1,13 @@
/**
* This enumeration represents all possible ways of representing a group of objects in the UI
*/
export enum Context {
Undefined = 'undefined',
ItemPage = 'itemPage',
Search = 'search',
Workflow = 'workflow',
Workspace = 'workspace',
AdminMenu = 'adminMenu',
SubmissionModal = 'submissionModal',
}

View File

@@ -12,6 +12,7 @@ import { CacheableObject } from '../cache/object-cache.reducer';
import { RemoteData } from '../data/remote-data'; import { RemoteData } from '../data/remote-data';
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
import { ResourceType } from './resource-type'; import { ResourceType } from './resource-type';
import { GenericConstructor } from './generic-constructor';
/** /**
* An abstract model class for a DSpaceObject. * An abstract model class for a DSpaceObject.
@@ -109,7 +110,7 @@ export class DSpaceObject implements CacheableObject, ListableObject {
* Like [[firstMetadata]], but only returns a string value, or `undefined`. * Like [[firstMetadata]], but only returns a string value, or `undefined`.
* *
* @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]].
* @param {MetadataValueFilter} filter The value filter to use. If unspecified, no filtering will be done. * @param {MetadataValueFilter} valueFilter The value filter to use. If unspecified, no filtering will be done.
* @returns {string} the first matching string value, or `undefined`. * @returns {string} the first matching string value, or `undefined`.
*/ */
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string { firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
@@ -146,4 +147,10 @@ export class DSpaceObject implements CacheableObject, ListableObject {
}); });
} }
/**
* Method that returns as which type of object this object should be rendered
*/
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
return [this.constructor as GenericConstructor<ListableObject>];
}
} }

View File

@@ -5,12 +5,18 @@ import { DSpaceObject } from './dspace-object.model';
import { Collection } from './collection.model'; import { Collection } from './collection.model';
import { RemoteData } from '../data/remote-data'; import { RemoteData } from '../data/remote-data';
import { Bitstream } from './bitstream.model'; import { Bitstream } from './bitstream.model';
import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
import { PaginatedList } from '../data/paginated-list'; import { PaginatedList } from '../data/paginated-list';
import { Relationship } from './item-relationships/relationship.model'; import { Relationship } from './item-relationships/relationship.model';
import { ResourceType } from './resource-type'; import { ResourceType } from './resource-type';
import { getSucceededRemoteData } from './operators'; import { getSucceededRemoteData } from './operators';
import { GenericConstructor } from './generic-constructor';
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator';
/**
* Class representing a DSpace Item
*/
export class Item extends DSpaceObject { export class Item extends DSpaceObject {
static type = new ResourceType('item'); static type = new ResourceType('item');
@@ -110,4 +116,14 @@ export class Item extends DSpaceObject {
})); }));
} }
/**
* Method that returns as which type of object this object should be rendered
*/
getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
let entityType = this.firstMetadataValue('relationship.type');
if (isEmpty(entityType)) {
entityType = DEFAULT_ENTITY_TYPE;
}
return [entityType, ...super.getRenderTypes()];
}
} }

View File

@@ -3,7 +3,8 @@
*/ */
export enum ViewMode { export enum ViewMode {
List = 'list', ListElement = 'listElement',
Grid = 'grid', GridElement = 'gridElement',
Detail = 'detail' DetailedListElement = 'detailedListElement',
StandalonePage = 'standalonePage',
} }

View File

@@ -1,30 +1 @@
<ds-truncatable [id]="dso.id"> <ds-journal-issue-search-result-grid-element [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-journal-issue-search-result-grid-element>
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</a>
<div class="card-body">
<ds-item-type-badge [object]="object"></ds-item-type-badge>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dso.firstMetadataValue('dc.title')"></h4>
</ds-truncatable-part>
<p *ngIf="dso.hasMetadata('creativework.datePublished')" class="item-date card-text text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span [innerHTML]="firstMetadataValue('creativework.datePublished')"></span>
</ds-truncatable-part>
</p>
<p *ngIf="dso.hasMetadata('journal.title')" class="item-journal-title card-text">
<ds-truncatable-part [id]="dso.id" [minLines]="3">
<span [innerHTML]="firstMetadataValue('journal.title')"></span>
</ds-truncatable-part>
</p>
<div class="text-center">
<a [routerLink]="['/items/' + dso.id]"
class="lead btn btn-primary viewButton">View</a>
</div>
</div>
</div>
</ds-truncatable>

View File

@@ -1,15 +1,17 @@
import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { of as observableOf } from 'rxjs/internal/observable/of';
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
import { JournalIssueGridElementComponent } from './journal-issue-grid-element.component'; import { JournalIssueGridElementComponent } from './journal-issue-grid-element.component';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { of as observableOf } from 'rxjs';
import { async, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); const mockItem = Object.assign(new Item(), {
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: { metadata: {
'dc.title': [ 'dc.title': [
@@ -33,18 +35,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
} }
}); });
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); describe('JournalIssueGridElementComponent', () => {
mockItemWithoutMetadata.hitHighlights = {}; let comp;
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { let fixture;
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalIssueGridElementComponent', getEntityGridElementTestComponent(JournalIssueGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'journal-title'])); const truncatableServiceStub: any = {
isCollapsed: (id: number) => observableOf(true),
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule],
declarations: [JournalIssueGridElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(JournalIssueGridElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(JournalIssueGridElementComponent);
comp = fixture.componentInstance;
}));
describe(`when the journal issue is rendered`, () => {
beforeEach(() => {
comp.object = mockItem;
fixture.detectChanges();
});
it(`should contain a JournalIssueSearchResultGridElementComponent`, () => {
const journalIssueGridElement = fixture.debugElement.query(By.css(`ds-journal-issue-search-result-grid-element`));
expect(journalIssueGridElement).not.toBeNull();
});
});
});

View File

@@ -1,17 +1,17 @@
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { focusShadow } from '../../../../shared/animations/focus'; import { ViewMode } from '../../../../core/shared/view-mode.model';
import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component';
import { Item } from '../../../../core/shared/item.model';
@rendersItemType('JournalIssue', ItemViewMode.Card) @listableObjectComponent('JournalIssue', ViewMode.GridElement)
@Component({ @Component({
selector: 'ds-journal-issue-grid-element', selector: 'ds-journal-issue-grid-element',
styleUrls: ['./journal-issue-grid-element.component.scss'], styleUrls: ['./journal-issue-grid-element.component.scss'],
templateUrl: './journal-issue-grid-element.component.html', templateUrl: './journal-issue-grid-element.component.html',
animations: [focusShadow]
}) })
/** /**
* The component for displaying a grid element for an item of the type Journal Issue * The component for displaying a grid element for an item of the type Journal Issue
*/ */
export class JournalIssueGridElementComponent extends TypedItemSearchResultGridElementComponent { export class JournalIssueGridElementComponent extends AbstractListableElementComponent<Item> {
} }

View File

@@ -1,30 +1 @@
<ds-truncatable [id]="dso.id"> <ds-journal-volume-search-result-grid-element [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-journal-volume-search-result-grid-element>
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</a>
<div class="card-body">
<ds-item-type-badge [object]="object"></ds-item-type-badge>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dso.firstMetadataValue('dc.title')"></h4>
</ds-truncatable-part>
<p *ngIf="dso.hasMetadata('creativework.datePublished')" class="item-date card-text text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span [innerHTML]="firstMetadataValue('creativework.datePublished')"></span>
</ds-truncatable-part>
</p>
<p *ngIf="dso.hasMetadata('dc.description')" class="item-description card-text">
<ds-truncatable-part [id]="dso.id" [minLines]="3">
<span [innerHTML]="firstMetadataValue('dc.description')"></span>
</ds-truncatable-part>
</p>
<div class="text-center">
<a [routerLink]="['/items/' + dso.id]"
class="lead btn btn-primary viewButton">View</a>
</div>
</div>
</div>
</ds-truncatable>

View File

@@ -1,15 +1,17 @@
import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { of as observableOf } from 'rxjs/internal/observable/of';
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
import { JournalVolumeGridElementComponent } from './journal-volume-grid-element.component'; import { JournalVolumeGridElementComponent } from './journal-volume-grid-element.component';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { of as observableOf } from 'rxjs';
import { async, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); const mockItem = Object.assign(new Item(), {
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: { metadata: {
'dc.title': [ 'dc.title': [
@@ -33,18 +35,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
} }
}); });
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); describe('JournalVolumeGridElementComponent', () => {
mockItemWithoutMetadata.hitHighlights = {}; let comp;
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { let fixture;
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalVolumeGridElementComponent', getEntityGridElementTestComponent(JournalVolumeGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'description'])); const truncatableServiceStub: any = {
isCollapsed: (id: number) => observableOf(true),
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule],
declarations: [JournalVolumeGridElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(JournalVolumeGridElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(JournalVolumeGridElementComponent);
comp = fixture.componentInstance;
}));
describe(`when the journal volume is rendered`, () => {
beforeEach(() => {
comp.object = mockItem;
fixture.detectChanges();
});
it(`should contain a JournalVolumeSearchResultGridElementComponent`, () => {
const journalVolumeGridElement = fixture.debugElement.query(By.css(`ds-journal-volume-search-result-grid-element`));
expect(journalVolumeGridElement).not.toBeNull();
});
});
});

View File

@@ -1,17 +1,17 @@
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { focusShadow } from '../../../../shared/animations/focus'; import { ViewMode } from '../../../../core/shared/view-mode.model';
import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component';
import { Item } from '../../../../core/shared/item.model';
@rendersItemType('JournalVolume', ItemViewMode.Card) @listableObjectComponent('JournalVolume', ViewMode.GridElement)
@Component({ @Component({
selector: 'ds-journal-volume-grid-element', selector: 'ds-journal-volume-grid-element',
styleUrls: ['./journal-volume-grid-element.component.scss'], styleUrls: ['./journal-volume-grid-element.component.scss'],
templateUrl: './journal-volume-grid-element.component.html', templateUrl: './journal-volume-grid-element.component.html',
animations: [focusShadow]
}) })
/** /**
* The component for displaying a grid element for an item of the type Journal Volume * The component for displaying a grid element for an item of the type Journal Volume
*/ */
export class JournalVolumeGridElementComponent extends TypedItemSearchResultGridElementComponent { export class JournalVolumeGridElementComponent extends AbstractListableElementComponent<Item> {
} }

View File

@@ -1,35 +1 @@
<ds-truncatable [id]="dso.id"> <ds-journal-search-result-grid-element [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-journal-search-result-grid-element>
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</a>
<div class="card-body">
<ds-item-type-badge [object]="object"></ds-item-type-badge>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dso.firstMetadataValue('dc.title')"></h4>
</ds-truncatable-part>
<p *ngIf="dso.hasMetadata('creativework.editor')"
class="item-publisher card-text text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span class="item-editor">{{dso.firstMetadataValue('creativework.editor')}}</span>
<span *ngIf="dso.hasMetadata('creativework.publisher')" class="item-publisher">
<span>, </span>
{{dso.firstMetadataValue('creativework.publisher')}}
</span>
</ds-truncatable-part>
</p>
<p *ngIf="dso.hasMetadata('dc.description')" class="item-description card-text">
<ds-truncatable-part [id]="dso.id" [minLines]="3">
<span [innerHTML]="firstMetadataValue('dc.description')"></span>
</ds-truncatable-part>
</p>
<div class="text-center">
<a [routerLink]="['/items/' + dso.id]"
class="lead btn btn-primary viewButton">View</a>
</div>
</div>
</div>
</ds-truncatable>

View File

@@ -1,15 +1,17 @@
import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { of as observableOf } from 'rxjs/internal/observable/of'; import { of as observableOf } from 'rxjs/internal/observable/of';
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
import { JournalGridElementComponent } from './journal-grid-element.component'; import { JournalGridElementComponent } from './journal-grid-element.component';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { async, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); const mockItem = Object.assign(new Item(), {
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: { metadata: {
'dc.title': [ 'dc.title': [
@@ -39,18 +41,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
} }
}); });
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); describe('JournalGridElementComponent', () => {
mockItemWithoutMetadata.hitHighlights = {}; let comp;
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { let fixture;
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalGridElementComponent', getEntityGridElementTestComponent(JournalGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['editor', 'publisher', 'description'])); const truncatableServiceStub: any = {
isCollapsed: (id: number) => observableOf(true),
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule],
declarations: [JournalGridElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(JournalGridElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(JournalGridElementComponent);
comp = fixture.componentInstance;
}));
describe(`when the journal is rendered`, () => {
beforeEach(() => {
comp.object = mockItem;
fixture.detectChanges();
});
it(`should contain a JournalGridElementComponent`, () => {
const journalGridElement = fixture.debugElement.query(By.css(`ds-journal-search-result-grid-element`));
expect(journalGridElement).not.toBeNull();
});
});
});

View File

@@ -1,17 +1,17 @@
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { focusShadow } from '../../../../shared/animations/focus'; import { ViewMode } from '../../../../core/shared/view-mode.model';
import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component';
import { Item } from '../../../../core/shared/item.model';
@rendersItemType('Journal', ItemViewMode.Card) @listableObjectComponent('Journal', ViewMode.GridElement)
@Component({ @Component({
selector: 'ds-journal-grid-element', selector: 'ds-journal-grid-element',
styleUrls: ['./journal-grid-element.component.scss'], styleUrls: ['./journal-grid-element.component.scss'],
templateUrl: './journal-grid-element.component.html', templateUrl: './journal-grid-element.component.html',
animations: [focusShadow]
}) })
/** /**
* The component for displaying a grid element for an item of the type Journal * The component for displaying a grid element for an item of the type Journal
*/ */
export class JournalGridElementComponent extends TypedItemSearchResultGridElementComponent { export class JournalGridElementComponent extends AbstractListableElementComponent<Item> {
} }

View File

@@ -0,0 +1,36 @@
<ds-truncatable [id]="dso.id">
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</span>
<div class="card-body">
<ds-item-type-badge [object]="dso"></ds-item-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('creativework.datePublished')" class="item-date card-text text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span [innerHTML]="firstMetadataValue('creativework.datePublished')"></span>
</ds-truncatable-part>
</p>
<p *ngIf="dso.hasMetadata('journal.title')" class="item-journal-title card-text">
<ds-truncatable-part [id]="dso.id" [minLines]="3">
<span [innerHTML]="firstMetadataValue('journal.title')"></span>
</ds-truncatable-part>
</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]"
class="lead btn btn-primary viewButton">View</a>
</div>
</div>
</div>
</ds-truncatable>

View File

@@ -0,0 +1,49 @@
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
import { PaginatedList } from '../../../../../core/data/paginated-list';
import { PageInfo } from '../../../../../core/shared/page-info.model';
import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec';
import { JournalIssueSearchResultGridElementComponent } from './journal-issue-search-result-grid-element.component';
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
],
'creativework.datePublished': [
{
language: null,
value: '2015-06-26'
}
],
'journal.title': [
{
language: 'en_US',
value: 'The journal title'
}
]
}
});
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalIssueSearchResultGridElementComponent', getEntityGridElementTestComponent(JournalIssueSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'journal-title']));

View File

@@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { focusShadow } from '../../../../../shared/animations/focus';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('JournalIssueSearchResult', ViewMode.GridElement)
@Component({
selector: 'ds-journal-issue-search-result-grid-element',
styleUrls: ['./journal-issue-search-result-grid-element.component.scss'],
templateUrl: './journal-issue-search-result-grid-element.component.html',
animations: [focusShadow]
})
/**
* The component for displaying a grid element for an item search result of the type Journal Issue
*/
export class JournalIssueSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> {
}

View File

@@ -0,0 +1,36 @@
<ds-truncatable [id]="dso.id">
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</span>
<div class="card-body">
<ds-item-type-badge [object]="dso"></ds-item-type-badge>
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
<h4 class="card-title" [innerHTML]="dso.firstMetadataValue('dc.title')"></h4>
</ds-truncatable-part>
<p *ngIf="dso.hasMetadata('creativework.datePublished')" class="item-date card-text text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span [innerHTML]="firstMetadataValue('creativework.datePublished')"></span>
</ds-truncatable-part>
</p>
<p *ngIf="dso.hasMetadata('dc.description')" class="item-description card-text">
<ds-truncatable-part [id]="dso.id" [minLines]="3">
<span [innerHTML]="firstMetadataValue('dc.description')"></span>
</ds-truncatable-part>
</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]"
class="lead btn btn-primary viewButton">View</a>
</div>
</div>
</div>
</ds-truncatable>

View File

@@ -0,0 +1,49 @@
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
import { PaginatedList } from '../../../../../core/data/paginated-list';
import { PageInfo } from '../../../../../core/shared/page-info.model';
import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec';
import { JournalVolumeSearchResultGridElementComponent } from './journal-volume-search-result-grid-element.component';
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
],
'creativework.datePublished': [
{
language: null,
value: '2015-06-26'
}
],
'dc.description': [
{
language: 'en_US',
value: 'A description for the journal volume'
}
]
}
});
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalVolumeSearchResultGridElementComponent', getEntityGridElementTestComponent(JournalVolumeSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'description']));

View File

@@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { focusShadow } from '../../../../../shared/animations/focus';
@listableObjectComponent('JournalVolumeSearchResult', ViewMode.GridElement)
@Component({
selector: 'ds-journal-volume-search-result-grid-element',
styleUrls: ['./journal-volume-search-result-grid-element.component.scss'],
templateUrl: './journal-volume-search-result-grid-element.component.html',
animations: [focusShadow]
})
/**
* The component for displaying a grid element for an item search result of the type Journal Volume
*/
export class JournalVolumeSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> {
}

View File

@@ -0,0 +1,41 @@
<ds-truncatable [id]="dso.id">
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</a>
<span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
<div>
<ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
</ds-grid-thumbnail>
</div>
</span>
<div class="card-body">
<ds-item-type-badge [object]="dso"></ds-item-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('creativework.editor')"
class="item-publisher card-text text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span class="item-editor">{{firstMetadataValue('creativework.editor')}}</span>
<span *ngIf="dso.hasMetadata('creativework.publisher')" class="item-publisher">
<span>, </span>
{{firstMetadataValue('creativework.publisher')}}
</span>
</ds-truncatable-part>
</p>
<p *ngIf="dso.hasMetadata('dc.description')" class="item-description card-text">
<ds-truncatable-part [id]="dso.id" [minLines]="3">
<span [innerHTML]="firstMetadataValue('dc.description')"></span>
</ds-truncatable-part>
</p>
<div *ngIf="linkType != linkTypes.None" class="text-center">
<a [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]"
class="lead btn btn-primary viewButton">View</a>
</div>
</div>
</div>
</ds-truncatable>

View File

@@ -0,0 +1,55 @@
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
import { PaginatedList } from '../../../../../core/data/paginated-list';
import { PageInfo } from '../../../../../core/shared/page-info.model';
import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec';
import { JournalSearchResultGridElementComponent } from './journal-search-result-grid-element.component';
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
],
'creativework.editor': [
{
language: 'en_US',
value: 'Smith, Donald'
}
],
'creativework.publisher': [
{
language: 'en_US',
value: 'A company'
}
],
'dc.description': [
{
language: 'en_US',
value: 'This is the description'
}
]
}
});
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalSearchResultGridElementComponent', getEntityGridElementTestComponent(JournalSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['editor', 'publisher', 'description']));

View File

@@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { focusShadow } from '../../../../../shared/animations/focus';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('JournalSearchResult', ViewMode.GridElement)
@Component({
selector: 'ds-journal-search-result-grid-element',
styleUrls: ['./journal-search-result-grid-element.component.scss'],
templateUrl: './journal-search-result-grid-element.component.html',
animations: [focusShadow]
})
/**
* The component for displaying a grid element for an item search result of the type Journal
*/
export class JournalSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> {
}

View File

@@ -1,21 +1 @@
<ds-truncatable [id]="item.id"> <ds-journal-issue-search-result-list-element [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-journal-issue-search-result-list-element>
<a
[routerLink]="['/items/' + item.id]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a>
<span class="text-muted">
<ds-truncatable-part [id]="item.id" [minLines]="1">
<span *ngIf="item.allMetadata(['publicationvolume.volumeNumber']).length > 0"
class="item-list-journal-issues">
<span *ngFor="let value of allMetadataValues(['publicationvolume.volumeNumber']); let last=last;">
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
<span *ngIf="item.allMetadata(['publicationissue.issueNumber']).length > 0"
class="item-list-journal-issue-numbers">
<span *ngFor="let value of allMetadataValues(['publicationissue.issueNumber']); let last=last;">
<span> - </span><span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
</span>
</span>
</ds-truncatable-part>
</span>
</ds-truncatable>

View File

@@ -1,17 +1,13 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { JournalIssueListElementComponent } from './journal-issue-list-element.component'; import { JournalIssueListElementComponent } from './journal-issue-list-element.component';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
let journalIssueListElementComponent: JournalIssueListElementComponent; const mockItem: Item = Object.assign(new Item(), {
let fixture: ComponentFixture<JournalIssueListElementComponent>;
const mockItemWithMetadata: Item = Object.assign(new Item(), {
bitstreams: observableOf({}), bitstreams: observableOf({}),
metadata: { metadata: {
'dc.title': [ 'dc.title': [
@@ -34,28 +30,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), {
] ]
} }
}); });
const mockItemWithoutMetadata: Item = Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalIssueListElementComponent', () => { describe('JournalIssueListElementComponent', () => {
let comp;
let fixture;
const truncatableServiceStub: any = {
isCollapsed: (id: number) => observableOf(true),
};
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ JournalIssueListElementComponent , TruncatePipe], declarations: [JournalIssueListElementComponent, TruncatePipe],
providers: [ providers: [
{ provide: ITEM, useValue: mockItemWithMetadata}, { provide: TruncatableService, useValue: truncatableServiceStub },
{ provide: TruncatableService, useValue: {} }
], ],
schemas: [NO_ERRORS_SCHEMA]
schemas: [ NO_ERRORS_SCHEMA ]
}).overrideComponent(JournalIssueListElementComponent, { }).overrideComponent(JournalIssueListElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default } set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents(); }).compileComponents();
@@ -63,55 +53,19 @@ describe('JournalIssueListElementComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
fixture = TestBed.createComponent(JournalIssueListElementComponent); fixture = TestBed.createComponent(JournalIssueListElementComponent);
journalIssueListElementComponent = fixture.componentInstance; comp = fixture.componentInstance;
})); }));
describe('When the item has a journal identifier', () => { describe(`when the journal issue is rendered`, () => {
beforeEach(() => { beforeEach(() => {
journalIssueListElementComponent.item = mockItemWithMetadata; comp.object = mockItem;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should show the journal issues span', () => { it(`should contain a JournalIssueListElementComponent`, () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues')); const journalIssueListElement = fixture.debugElement.query(By.css(`ds-journal-issue-search-result-list-element`));
expect(journalIdentifierField).not.toBeNull(); expect(journalIssueListElement).not.toBeNull();
}); });
}); });
describe('When the item has no journal identifier', () => {
beforeEach(() => {
journalIssueListElementComponent.item = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal issues span', () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues'));
expect(journalIdentifierField).toBeNull();
});
});
describe('When the item has a journal number', () => {
beforeEach(() => {
journalIssueListElementComponent.item = mockItemWithMetadata;
fixture.detectChanges();
});
it('should show the journal issue numbers span', () => {
const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers'));
expect(journalNumberField).not.toBeNull();
});
});
describe('When the item has no journal number', () => {
beforeEach(() => {
journalIssueListElementComponent.item = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal issue numbers span', () => {
const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers'));
expect(journalNumberField).toBeNull();
});
});
}); });

View File

@@ -1,8 +1,10 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { ViewMode } from '../../../../core/shared/view-mode.model';
import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component';
import { Item } from '../../../../core/shared/item.model';
@rendersItemType('JournalIssue', ItemViewMode.Element) @listableObjectComponent('JournalIssue', ViewMode.ListElement)
@Component({ @Component({
selector: 'ds-journal-issue-list-element', selector: 'ds-journal-issue-list-element',
styleUrls: ['./journal-issue-list-element.component.scss'], styleUrls: ['./journal-issue-list-element.component.scss'],
@@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob
/** /**
* The component for displaying a list element for an item of the type Journal Issue * The component for displaying a list element for an item of the type Journal Issue
*/ */
export class JournalIssueListElementComponent extends TypedItemSearchResultListElementComponent { export class JournalIssueListElementComponent extends AbstractListableElementComponent<Item> {
} }

View File

@@ -1,21 +1 @@
<ds-truncatable [id]="item.id"> <ds-journal-volume-search-result-list-element [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-journal-volume-search-result-list-element>
<a
[routerLink]="['/items/' + item.id]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a>
<span class="text-muted">
<ds-truncatable-part [id]="item.id" [minLines]="1">
<span *ngIf="item.allMetadata(['journal.title']).length > 0"
class="item-list-journal-volumes">
<span *ngFor="let value of allMetadataValues(['journal.title']); let last=last;">
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
</span>
<span *ngIf="item.allMetadata(['publicationvolume.volumeNumber']).length > 0"
class="item-list-journal-volume-identifiers">
<span *ngFor="let value of allMetadataValues(['publicationvolume.volumeNumber']); let last=last;">
<span> (</span><span [innerHTML]="value"><span [innerHTML]="value"></span></span><span>)</span>
</span>
</span>
</ds-truncatable-part>
</span>
</ds-truncatable>

View File

@@ -1,17 +1,13 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { JournalVolumeListElementComponent } from './journal-volume-list-element.component'; import { JournalVolumeListElementComponent } from './journal-volume-list-element.component';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
let journalVolumeListElementComponent: JournalVolumeListElementComponent; const mockItem: Item = Object.assign(new Item(), {
let fixture: ComponentFixture<JournalVolumeListElementComponent>;
const mockItemWithMetadata: Item = Object.assign(new Item(), {
bitstreams: observableOf({}), bitstreams: observableOf({}),
metadata: { metadata: {
'dc.title': [ 'dc.title': [
@@ -34,28 +30,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), {
] ]
} }
}); });
const mockItemWithoutMetadata: Item = Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalVolumeListElementComponent', () => { describe('JournalVolumeListElementComponent', () => {
let comp;
let fixture;
const truncatableServiceStub: any = {
isCollapsed: (id: number) => observableOf(true),
};
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ JournalVolumeListElementComponent , TruncatePipe], declarations: [JournalVolumeListElementComponent, TruncatePipe],
providers: [ providers: [
{ provide: ITEM, useValue: mockItemWithMetadata}, { provide: TruncatableService, useValue: truncatableServiceStub },
{ provide: TruncatableService, useValue: {} }
], ],
schemas: [NO_ERRORS_SCHEMA]
schemas: [ NO_ERRORS_SCHEMA ]
}).overrideComponent(JournalVolumeListElementComponent, { }).overrideComponent(JournalVolumeListElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default } set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents(); }).compileComponents();
@@ -63,55 +53,18 @@ describe('JournalVolumeListElementComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
fixture = TestBed.createComponent(JournalVolumeListElementComponent); fixture = TestBed.createComponent(JournalVolumeListElementComponent);
journalVolumeListElementComponent = fixture.componentInstance; comp = fixture.componentInstance;
})); }));
describe('When the item has a journal title', () => { describe(`when the journal volume is rendered`, () => {
beforeEach(() => { beforeEach(() => {
journalVolumeListElementComponent.item = mockItemWithMetadata; comp.object = mockItem;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should show the journal title span', () => { it(`should contain a JournalVolumeListElementComponent`, () => {
const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes')); const journalVolumeListElement = fixture.debugElement.query(By.css(`ds-journal-volume-search-result-list-element`));
expect(journalTitleField).not.toBeNull(); expect(journalVolumeListElement).not.toBeNull();
});
});
describe('When the item has no journal title', () => {
beforeEach(() => {
journalVolumeListElementComponent.item = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal title span', () => {
const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes'));
expect(journalTitleField).toBeNull();
});
});
describe('When the item has a journal identifier', () => {
beforeEach(() => {
journalVolumeListElementComponent.item = mockItemWithMetadata;
fixture.detectChanges();
});
it('should show the journal identifiers span', () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers'));
expect(journalIdentifierField).not.toBeNull();
});
});
describe('When the item has no journal identifier', () => {
beforeEach(() => {
journalVolumeListElementComponent.item = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal identifiers span', () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers'));
expect(journalIdentifierField).toBeNull();
}); });
}); });
}); });

View File

@@ -1,8 +1,10 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { ViewMode } from '../../../../core/shared/view-mode.model';
import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component';
import { Item } from '../../../../core/shared/item.model';
@rendersItemType('JournalVolume', ItemViewMode.Element) @listableObjectComponent('JournalVolume', ViewMode.ListElement)
@Component({ @Component({
selector: 'ds-journal-volume-list-element', selector: 'ds-journal-volume-list-element',
styleUrls: ['./journal-volume-list-element.component.scss'], styleUrls: ['./journal-volume-list-element.component.scss'],
@@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob
/** /**
* The component for displaying a list element for an item of the type Journal Volume * The component for displaying a list element for an item of the type Journal Volume
*/ */
export class JournalVolumeListElementComponent extends TypedItemSearchResultListElementComponent { export class JournalVolumeListElementComponent extends AbstractListableElementComponent<Item> {
} }

View File

@@ -1,15 +1 @@
<ds-truncatable [id]="item.id"> <ds-journal-search-result-list-element [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-journal-search-result-list-element>
<a
[routerLink]="['/items/' + item.id]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a>
<span class="text-muted">
<ds-truncatable-part [id]="item.id" [minLines]="1">
<span *ngIf="item.allMetadata(['creativeworkseries.issn']).length > 0"
class="item-list-journals">
<span *ngFor="let value of allMetadataValues(['creativeworkseries.issn']); let last=last;">
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
</span>
</ds-truncatable-part>
</span>
</ds-truncatable>

View File

@@ -1,17 +1,13 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { JournalListElementComponent } from './journal-list-element.component'; import { JournalListElementComponent } from './journal-list-element.component';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
let journalListElementComponent: JournalListElementComponent; const mockItem: Item = Object.assign(new Item(), {
let fixture: ComponentFixture<JournalListElementComponent>;
const mockItemWithMetadata: Item = Object.assign(new Item(), {
bitstreams: observableOf({}), bitstreams: observableOf({}),
metadata: { metadata: {
'dc.title': [ 'dc.title': [
@@ -28,28 +24,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), {
] ]
} }
}); });
const mockItemWithoutMetadata: Item = Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
});
describe('JournalListElementComponent', () => { describe('JournalListElementComponent', () => {
let comp;
let fixture;
const truncatableServiceStub: any = {
isCollapsed: (id: number) => observableOf(true),
};
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ JournalListElementComponent , TruncatePipe], declarations: [JournalListElementComponent, TruncatePipe],
providers: [ providers: [
{ provide: ITEM, useValue: mockItemWithMetadata}, { provide: TruncatableService, useValue: truncatableServiceStub },
{ provide: TruncatableService, useValue: {} }
], ],
schemas: [NO_ERRORS_SCHEMA]
schemas: [ NO_ERRORS_SCHEMA ]
}).overrideComponent(JournalListElementComponent, { }).overrideComponent(JournalListElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default } set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents(); }).compileComponents();
@@ -57,31 +47,18 @@ describe('JournalListElementComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
fixture = TestBed.createComponent(JournalListElementComponent); fixture = TestBed.createComponent(JournalListElementComponent);
journalListElementComponent = fixture.componentInstance; comp = fixture.componentInstance;
})); }));
describe('When the item has an issn', () => { describe(`when the journal is rendered`, () => {
beforeEach(() => { beforeEach(() => {
journalListElementComponent.item = mockItemWithMetadata; comp.object = mockItem;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should show the journals span', () => { it(`should contain a JournalListElementComponent`, () => {
const issnField = fixture.debugElement.query(By.css('span.item-list-journals')); const journalListElement = fixture.debugElement.query(By.css(`ds-journal-search-result-list-element`));
expect(issnField).not.toBeNull(); expect(journalListElement).not.toBeNull();
});
});
describe('When the item has no issn', () => {
beforeEach(() => {
journalListElementComponent.item = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journals span', () => {
const issnField = fixture.debugElement.query(By.css('span.item-list-journals'));
expect(issnField).toBeNull();
}); });
}); });
}); });

View File

@@ -1,8 +1,10 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { ViewMode } from '../../../../core/shared/view-mode.model';
import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component';
import { Item } from '../../../../core/shared/item.model';
@rendersItemType('Journal', ItemViewMode.Element) @listableObjectComponent('Journal', ViewMode.ListElement)
@Component({ @Component({
selector: 'ds-journal-list-element', selector: 'ds-journal-list-element',
styleUrls: ['./journal-list-element.component.scss'], styleUrls: ['./journal-list-element.component.scss'],
@@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob
/** /**
* The component for displaying a list element for an item of the type Journal * The component for displaying a list element for an item of the type Journal
*/ */
export class JournalListElementComponent extends TypedItemSearchResultListElementComponent { export class JournalListElementComponent extends AbstractListableElementComponent<Item> {
} }

View File

@@ -0,0 +1,25 @@
<ds-item-type-badge [object]="dso"></ds-item-type-badge>
<ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None"
class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></span>
<span class="text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span *ngIf="dso.allMetadata(['publicationvolume.volumeNumber']).length > 0"
class="item-list-journal-issues">
<span *ngFor="let value of allMetadataValues(['publicationvolume.volumeNumber']); let last=last;">
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
<span *ngIf="dso.allMetadata(['publicationissue.issueNumber']).length > 0"
class="item-list-journal-issue-numbers">
<span *ngFor="let value of allMetadataValues(['publicationissue.issueNumber']); let last=last;">
<span> - </span><span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
</span>
</span>
</ds-truncatable-part>
</span>
</ds-truncatable>

View File

@@ -0,0 +1,125 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { of as observableOf } from 'rxjs';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { JournalIssueSearchResultListElementComponent } from './journal-issue-search-result-list-element.component';
import { Item } from '../../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
let journalIssueListElementComponent: JournalIssueSearchResultListElementComponent;
let fixture: ComponentFixture<JournalIssueSearchResultListElementComponent>;
const mockItemWithMetadata: ItemSearchResult = Object.assign(
new ItemSearchResult(),
{
indexableObject: Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
],
'publicationvolume.volumeNumber': [
{
language: 'en_US',
value: '1234'
}
],
'publicationissue.issueNumber': [
{
language: 'en_US',
value: '5678'
}
]
}
})
});
const mockItemWithoutMetadata: ItemSearchResult = Object.assign(
new ItemSearchResult(),
{
indexableObject: Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
})
});
describe('JournalIssueSearchResultListElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [JournalIssueSearchResultListElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: {} }
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(JournalIssueSearchResultListElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(JournalIssueSearchResultListElementComponent);
journalIssueListElementComponent = fixture.componentInstance;
}));
describe('When the item has a journal identifier', () => {
beforeEach(() => {
journalIssueListElementComponent.object = mockItemWithMetadata;
fixture.detectChanges();
});
it('should show the journal issues span', () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues'));
expect(journalIdentifierField).not.toBeNull();
});
});
describe('When the item has no journal identifier', () => {
beforeEach(() => {
journalIssueListElementComponent.object = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal issues span', () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues'));
expect(journalIdentifierField).toBeNull();
});
});
describe('When the item has a journal number', () => {
beforeEach(() => {
journalIssueListElementComponent.object = mockItemWithMetadata;
fixture.detectChanges();
});
it('should show the journal issue numbers span', () => {
const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers'));
expect(journalNumberField).not.toBeNull();
});
});
describe('When the item has no journal number', () => {
beforeEach(() => {
journalIssueListElementComponent.object = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal issue numbers span', () => {
const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers'));
expect(journalNumberField).toBeNull();
});
});
});

View File

@@ -0,0 +1,18 @@
import { Component } from '@angular/core';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
@listableObjectComponent('JournalIssueSearchResult', ViewMode.ListElement)
@Component({
selector: 'ds-journal-issue-search-result-list-element',
styleUrls: ['./journal-issue-search-result-list-element.component.scss'],
templateUrl: './journal-issue-search-result-list-element.component.html'
})
/**
* The component for displaying a list element for an item search result of the type Journal Issue
*/
export class JournalIssueSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {
}

View File

@@ -0,0 +1,25 @@
<ds-item-type-badge [object]="dso"></ds-item-type-badge>
<ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None"
class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></span>
<span class="text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span *ngIf="dso.allMetadata(['journal.title']).length > 0"
class="item-list-journal-volumes">
<span *ngFor="let value of allMetadataValues(['journal.title']); let last=last;">
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
</span>
<span *ngIf="dso.allMetadata(['publicationvolume.volumeNumber']).length > 0"
class="item-list-journal-volume-identifiers">
<span *ngFor="let value of allMetadataValues(['publicationvolume.volumeNumber']); let last=last;">
<span> (</span><span [innerHTML]="value"><span [innerHTML]="value"></span></span><span>)</span>
</span>
</span>
</ds-truncatable-part>
</span>
</ds-truncatable>

View File

@@ -0,0 +1,124 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { of as observableOf } from 'rxjs';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { JournalVolumeSearchResultListElementComponent } from './journal-volume-search-result-list-element.component';
import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
let journalVolumeListElementComponent: JournalVolumeSearchResultListElementComponent;
let fixture: ComponentFixture<JournalVolumeSearchResultListElementComponent>;
const mockItemWithMetadata: ItemSearchResult = Object.assign(
new ItemSearchResult(),
{
indexableObject: Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
],
'journal.title': [
{
language: 'en_US',
value: 'This is just another journal title'
}
],
'publicationvolume.volumeNumber': [
{
language: 'en_US',
value: '1234'
}
]
}
})
});
const mockItemWithoutMetadata: ItemSearchResult = Object.assign(
new ItemSearchResult(),
{
indexableObject: Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
})
});
describe('JournalVolumeSearchResultListElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [JournalVolumeSearchResultListElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: {} }
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(JournalVolumeSearchResultListElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(JournalVolumeSearchResultListElementComponent);
journalVolumeListElementComponent = fixture.componentInstance;
}));
describe('When the item has a journal title', () => {
beforeEach(() => {
journalVolumeListElementComponent.object = mockItemWithMetadata;
fixture.detectChanges();
});
it('should show the journal title span', () => {
const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes'));
expect(journalTitleField).not.toBeNull();
});
});
describe('When the item has no journal title', () => {
beforeEach(() => {
journalVolumeListElementComponent.object = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal title span', () => {
const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes'));
expect(journalTitleField).toBeNull();
});
});
describe('When the item has a journal identifier', () => {
beforeEach(() => {
journalVolumeListElementComponent.object = mockItemWithMetadata;
fixture.detectChanges();
});
it('should show the journal identifiers span', () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers'));
expect(journalIdentifierField).not.toBeNull();
});
});
describe('When the item has no journal identifier', () => {
beforeEach(() => {
journalVolumeListElementComponent.object = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journal identifiers span', () => {
const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers'));
expect(journalIdentifierField).toBeNull();
});
});
});

View File

@@ -0,0 +1,18 @@
import { Component } from '@angular/core';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
@listableObjectComponent('JournalVolumeSearchResult', ViewMode.ListElement)
@Component({
selector: 'ds-journal-volume-search-result-list-element',
styleUrls: ['./journal-volume-search-result-list-element.component.scss'],
templateUrl: './journal-volume-search-result-list-element.component.html'
})
/**
* The component for displaying a list element for an item search result of the type Journal Volume
*/
export class JournalVolumeSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {
}

View File

@@ -0,0 +1,19 @@
<ds-item-type-badge [object]="dso"></ds-item-type-badge>
<ds-truncatable [id]="dso.id">
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
[routerLink]="['/items/' + dso.id]" class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></a>
<span *ngIf="linkType == linkTypes.None"
class="lead"
[innerHTML]="firstMetadataValue('dc.title')"></span>
<span class="text-muted">
<ds-truncatable-part [id]="dso.id" [minLines]="1">
<span *ngIf="dso.allMetadata(['creativeworkseries.issn']).length > 0"
class="item-list-journals">
<span *ngFor="let value of allMetadataValues(['creativeworkseries.issn']); let last=last;">
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
</span>
</span>
</ds-truncatable-part>
</span>
</ds-truncatable>

View File

@@ -0,0 +1,96 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { of as observableOf } from 'rxjs';
import { JournalSearchResultListElementComponent } from './journal-search-result-list-element.component';
import { Item } from '../../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
let journalListElementComponent: JournalSearchResultListElementComponent;
let fixture: ComponentFixture<JournalSearchResultListElementComponent>;
const mockItemWithMetadata: ItemSearchResult = Object.assign(
new ItemSearchResult(),
{
indexableObject: Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
],
'creativeworkseries.issn': [
{
language: 'en_US',
value: '1234'
}
]
}
})
});
const mockItemWithoutMetadata: ItemSearchResult = Object.assign(
new ItemSearchResult(),
{
indexableObject: Object.assign(new Item(), {
bitstreams: observableOf({}),
metadata: {
'dc.title': [
{
language: 'en_US',
value: 'This is just another title'
}
]
}
})
}
);
describe('JournalSearchResultListElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [JournalSearchResultListElementComponent, TruncatePipe],
providers: [
{ provide: TruncatableService, useValue: {} }
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(JournalSearchResultListElementComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default }
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(JournalSearchResultListElementComponent);
journalListElementComponent = fixture.componentInstance;
}));
describe('When the item has an issn', () => {
beforeEach(() => {
journalListElementComponent.object = mockItemWithMetadata;
fixture.detectChanges();
});
it('should show the journals span', () => {
const issnField = fixture.debugElement.query(By.css('span.item-list-journals'));
expect(issnField).not.toBeNull();
});
});
describe('When the item has no issn', () => {
beforeEach(() => {
journalListElementComponent.object = mockItemWithoutMetadata;
fixture.detectChanges();
});
it('should not show the journals span', () => {
const issnField = fixture.debugElement.query(By.css('span.item-list-journals'));
expect(issnField).toBeNull();
});
});
});

View File

@@ -0,0 +1,18 @@
import { Component } from '@angular/core';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
@listableObjectComponent('JournalSearchResult', ViewMode.ListElement)
@Component({
selector: 'ds-journal-search-result-list-element',
styleUrls: ['./journal-search-result-list-element.component.scss'],
templateUrl: './journal-search-result-list-element.component.html'
})
/**
* The component for displaying a list element for an item search result of the type Journal
*/
export class JournalSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {
}

View File

@@ -1,54 +1,54 @@
<h2 class="item-page-title-field"> <h2 class="item-page-title-field">
{{'journalissue.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="item?.allMetadata(['dc.title'])"></ds-metadata-values> {{'journalissue.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper> <ds-metadata-field-wrapper>
<ds-thumbnail [thumbnail]="this.item.getThumbnail() | async"></ds-thumbnail> <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['publicationvolume.volumeNumber']" [fields]="['publicationvolume.volumeNumber']"
[label]="'journalvolume.page.volume'"> [label]="'journalvolume.page.volume'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['publicationissue.issueNumber']" [fields]="['publicationissue.issueNumber']"
[label]="'journalissue.page.number'"> [label]="'journalissue.page.number'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['creativework.datePublished']" [fields]="['creativework.datePublished']"
[label]="'journalissue.page.issuedate'"> [label]="'journalissue.page.issuedate'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['journal.title']" [fields]="['journal.title']"
[label]="'journalissue.page.journal-title'"> [label]="'journalissue.page.journal-title'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['creativeworkseries.issn']" [fields]="['creativeworkseries.issn']"
[label]="'journalissue.page.journal-issn'"> [label]="'journalissue.page.journal-issn'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<ds-related-items <ds-related-items
[parentItem]="item" [parentItem]="object"
[relationType]="'isJournalVolumeOfIssue'" [relationType]="'isJournalVolumeOfIssue'"
[label]="'relationships.isSingleVolumeOf' | translate"> [label]="'relationships.isSingleVolumeOf' | translate">
</ds-related-items> </ds-related-items>
<ds-related-items <ds-related-items
class="mb-1 mt-1" class="mb-1 mt-1"
[parentItem]="item" [parentItem]="object"
[relationType]="'isPublicationOfJournalIssue'" [relationType]="'isPublicationOfJournalIssue'"
[label]="'relationships.isPublicationOfJournalIssue' | translate"> [label]="'relationships.isPublicationOfJournalIssue' | translate">
</ds-related-items> </ds-related-items>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['dc.description']" [fields]="['dc.description']"
[label]="'journalissue.page.description'"> [label]="'journalissue.page.description'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['creativework.keywords']" [fields]="['creativework.keywords']"
[label]="'journalissue.page.keyword'"> [label]="'journalissue.page.keyword'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + item.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -1,13 +1,8 @@
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { JournalIssueComponent } from './journal-issue.component'; import { JournalIssueComponent } from './journal-issue.component';
import { of as observableOf } from 'rxjs'; import { createRelationshipsObservable, getItemPageFieldsTest } from '../../../../+item-page/simple/item-types/shared/item.component.spec';
import {
createRelationshipsObservable,
getItemPageFieldsTest
} from '../../../../+item-page/simple/item-types/shared/item.component.spec';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
const mockItem: Item = Object.assign(new Item(), { const mockItem: Item = Object.assign(new Item(), {

View File

@@ -1,8 +1,9 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator';
import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component';
import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../core/shared/view-mode.model';
@rendersItemType('JournalIssue', ItemViewMode.Full) @listableObjectComponent('JournalIssue', ViewMode.StandalonePage)
@Component({ @Component({
selector: 'ds-journal-issue', selector: 'ds-journal-issue',
styleUrls: ['./journal-issue.component.scss'], styleUrls: ['./journal-issue.component.scss'],

View File

@@ -1,37 +1,37 @@
<h2 class="item-page-title-field"> <h2 class="item-page-title-field">
{{'journalvolume.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="item?.allMetadata(['dc.title'])"></ds-metadata-values> {{'journalvolume.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper> <ds-metadata-field-wrapper>
<ds-thumbnail [thumbnail]="this.item.getThumbnail() | async"></ds-thumbnail> <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['publicationvolume.volumeNumber']" [fields]="['publicationvolume.volumeNumber']"
[label]="'journalvolume.page.volume'"> [label]="'journalvolume.page.volume'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['creativework.datePublished']" [fields]="['creativework.datePublished']"
[label]="'journalvolume.page.issuedate'"> [label]="'journalvolume.page.issuedate'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<ds-related-items <ds-related-items
[parentItem]="item" [parentItem]="object"
[relationType]="'isJournalOfVolume'" [relationType]="'isJournalOfVolume'"
[label]="'relationships.isSingleJournalOf' | translate"> [label]="'relationships.isSingleJournalOf' | translate">
</ds-related-items> </ds-related-items>
<ds-related-items <ds-related-items
[parentItem]="item" [parentItem]="object"
[relationType]="'isIssueOfJournalVolume'" [relationType]="'isIssueOfJournalVolume'"
[label]="'relationships.isIssueOf' | translate"> [label]="'relationships.isIssueOf' | translate">
</ds-related-items> </ds-related-items>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['dc.description']" [fields]="['dc.description']"
[label]="'journalvolume.page.description'"> [label]="'journalvolume.page.description'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + item.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>

View File

@@ -1,8 +1,9 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator';
import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component';
import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../core/shared/view-mode.model';
@rendersItemType('JournalVolume', ItemViewMode.Full) @listableObjectComponent('JournalVolume', ViewMode.StandalonePage)
@Component({ @Component({
selector: 'ds-journal-volume', selector: 'ds-journal-volume',
styleUrls: ['./journal-volume.component.scss'], styleUrls: ['./journal-volume.component.scss'],

View File

@@ -1,42 +1,42 @@
<h2 class="item-page-title-field"> <h2 class="item-page-title-field">
{{'journal.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="item?.allMetadata(['dc.title'])"></ds-metadata-values> {{'journal.page.titleprefix' | translate}}<ds-metadata-values [mdValues]="object?.allMetadata(['dc.title'])"></ds-metadata-values>
</h2> </h2>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<ds-metadata-field-wrapper> <ds-metadata-field-wrapper>
<ds-thumbnail [thumbnail]="this.item.getThumbnail() | async"></ds-thumbnail> <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
</ds-metadata-field-wrapper> </ds-metadata-field-wrapper>
<ds-generic-item-page-field class="item-page-fields" [item]="item" <ds-generic-item-page-field class="item-page-fields" [item]="object"
[fields]="['creativeworkseries.issn']" [fields]="['creativeworkseries.issn']"
[label]="'journal.page.issn'"> [label]="'journal.page.issn'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field class="item-page-fields" [item]="item" <ds-generic-item-page-field class="item-page-fields" [item]="object"
[fields]="['creativework.publisher']" [fields]="['creativework.publisher']"
[label]="'journal.page.publisher'"> [label]="'journal.page.publisher'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="object"
[fields]="['creativework.editor']" [fields]="['creativework.editor']"
[label]="'journal.page.editor'"> [label]="'journal.page.editor'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<ds-related-items <ds-related-items
[parentItem]="item" [parentItem]="object"
[relationType]="'isVolumeOfJournal'" [relationType]="'isVolumeOfJournal'"
[label]="'relationships.isVolumeOf' | translate"> [label]="'relationships.isVolumeOf' | translate">
</ds-related-items> </ds-related-items>
<ds-generic-item-page-field class="item-page-fields" [item]="item" <ds-generic-item-page-field class="item-page-fields" [item]="object"
[fields]="['dc.description']" [fields]="['dc.description']"
[label]="'journal.page.description'"> [label]="'journal.page.description'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<div> <div>
<a class="btn btn-outline-primary" [routerLink]="['/items/' + item.id + '/full']"> <a class="btn btn-outline-primary" [routerLink]="['/items/' + object.id + '/full']">
{{"item.page.link.full" | translate}} {{"item.page.link.full" | translate}}
</a> </a>
</div> </div>
</div> </div>
<div class="mt-5 w-100"> <div class="mt-5 w-100">
<ds-related-entities-search [item]="item" <ds-related-entities-search [item]="object"
[relationType]="'isJournalOfPublication'"> [relationType]="'isJournalOfPublication'">
</ds-related-entities-search> </ds-related-entities-search>
</div> </div>

View File

@@ -1,19 +1,16 @@
import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { ItemDataService } from '../../../../core/data/item-data.service'; import { ItemDataService } from '../../../../core/data/item-data.service';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
import { RemoteData } from '../../../../core/data/remote-data';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { PageInfo } from '../../../../core/shared/page-info.model'; import { PageInfo } from '../../../../core/shared/page-info.model';
import { isNotEmpty } from '../../../../shared/empty.util'; import { isNotEmpty } from '../../../../shared/empty.util';
import { JournalComponent } from './journal.component'; import { JournalComponent } from './journal.component';
import { of as observableOf } from 'rxjs';
import { GenericItemPageFieldComponent } from '../../../../+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component'; import { GenericItemPageFieldComponent } from '../../../../+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
@@ -55,7 +52,6 @@ describe('JournalComponent', () => {
})], })],
declarations: [JournalComponent, GenericItemPageFieldComponent, TruncatePipe], declarations: [JournalComponent, GenericItemPageFieldComponent, TruncatePipe],
providers: [ providers: [
{provide: ITEM, useValue: mockItem},
{provide: ItemDataService, useValue: {}}, {provide: ItemDataService, useValue: {}},
{provide: TruncatableService, useValue: {}} {provide: TruncatableService, useValue: {}}
], ],
@@ -69,6 +65,7 @@ describe('JournalComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
fixture = TestBed.createComponent(JournalComponent); fixture = TestBed.createComponent(JournalComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.object = mockItem;
fixture.detectChanges(); fixture.detectChanges();
})); }));

View File

@@ -1,8 +1,9 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator';
import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component';
import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../core/shared/view-mode.model';
@rendersItemType('Journal', ItemViewMode.Full) @listableObjectComponent('Journal', ViewMode.StandalonePage)
@Component({ @Component({
selector: 'ds-journal', selector: 'ds-journal',
styleUrls: ['./journal.component.scss'], styleUrls: ['./journal.component.scss'],

View File

@@ -12,6 +12,12 @@ import { TooltipModule } from 'ngx-bootstrap';
import { JournalIssueGridElementComponent } from './item-grid-elements/journal-issue/journal-issue-grid-element.component'; import { JournalIssueGridElementComponent } from './item-grid-elements/journal-issue/journal-issue-grid-element.component';
import { JournalVolumeGridElementComponent } from './item-grid-elements/journal-volume/journal-volume-grid-element.component'; import { JournalVolumeGridElementComponent } from './item-grid-elements/journal-volume/journal-volume-grid-element.component';
import { JournalGridElementComponent } from './item-grid-elements/journal/journal-grid-element.component'; import { JournalGridElementComponent } from './item-grid-elements/journal/journal-grid-element.component';
import { JournalSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component';
import { JournalSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component';
import { JournalIssueSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component';
import { JournalVolumeSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component';
import { JournalIssueSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component';
import { JournalVolumeSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component';
const ENTRY_COMPONENTS = [ const ENTRY_COMPONENTS = [
JournalComponent, JournalComponent,
@@ -22,7 +28,13 @@ const ENTRY_COMPONENTS = [
JournalVolumeListElementComponent, JournalVolumeListElementComponent,
JournalIssueGridElementComponent, JournalIssueGridElementComponent,
JournalVolumeGridElementComponent, JournalVolumeGridElementComponent,
JournalGridElementComponent JournalGridElementComponent,
JournalSearchResultListElementComponent,
JournalIssueSearchResultListElementComponent,
JournalVolumeSearchResultListElementComponent,
JournalIssueSearchResultGridElementComponent,
JournalVolumeSearchResultGridElementComponent,
JournalSearchResultGridElementComponent
]; ];
@NgModule({ @NgModule({

View File

@@ -0,0 +1 @@
<ds-org-unit-search-result-grid-element [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-org-unit-search-result-grid-element>

Some files were not shown because too many files have changed in this diff Show More