diff --git a/resources/i18n/en.json b/resources/i18n/en.json index a06f77463f..5057410ff8 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -26,7 +26,7 @@ }, "item": { "page": { - "author": "Author", + "author": "Authors", "abstract": "Abstract", "date": "Date", "uri": "URI", @@ -45,6 +45,13 @@ } } }, + "relationships": { + "isPublicationOf": "Publications", + "isProjectOf": "Projects", + "isOrgUnitOf": "Org Units", + "isAuthorOf": "Authors", + "isPersonOf": "Authors" + }, "person": { "page": { "jobtitle": "Job Title", @@ -54,7 +61,6 @@ "orcid": "ORCID", "birthdate": "Birth Date", "staffid": "Staff ID", - "publications": "Publications", "link": { "full": "Show all metadata" } diff --git a/src/app/+item-page/full/full-item-page.component.html b/src/app/+item-page/full/full-item-page.component.html index 4c44b72602..d79c4cdc34 100644 --- a/src/app/+item-page/full/full-item-page.component.html +++ b/src/app/+item-page/full/full-item-page.component.html @@ -1,6 +1,6 @@
-
+
+ + + + + + diff --git a/src/app/+item-page/simple/entity-types/orgunit/orgunit-page-fields.component.ts b/src/app/+item-page/simple/entity-types/orgunit/orgunit-page-fields.component.ts index 74e75e1dc9..9f3437c227 100644 --- a/src/app/+item-page/simple/entity-types/orgunit/orgunit-page-fields.component.ts +++ b/src/app/+item-page/simple/entity-types/orgunit/orgunit-page-fields.component.ts @@ -1,8 +1,14 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { ItemDataService } from '../../../../core/data/item-data.service'; import { Item } from '../../../../core/shared/item.model'; import { rendersEntityType } from '../../../../shared/entities/entity-type-decorator'; import { ElementViewMode } from '../../../../shared/view-mode'; import { ITEM } from '../../../../shared/entities/switcher/entity-type-switcher.component'; +import { + EntityPageFieldsComponent, filterRelationsByTypeLabel, + relationsToItems +} from '../shared/entity-page-fields.component'; @rendersEntityType('OrgUnit', ElementViewMode.Full) @Component({ @@ -10,9 +16,34 @@ import { ITEM } from '../../../../shared/entities/switcher/entity-type-switcher. styleUrls: ['./orgunit-page-fields.component.scss'], templateUrl: './orgunit-page-fields.component.html' }) -export class OrgUnitPageFieldsComponent { +export class OrgUnitPageFieldsComponent extends EntityPageFieldsComponent implements OnInit { - constructor(@Inject(ITEM) public item: Item) { + people$: Observable; + projects$: Observable; + publications$: Observable; + + constructor( + @Inject(ITEM) public item: Item, + private ids: ItemDataService + ) { + super(item); } -} + ngOnInit(): void { + super.ngOnInit(); + + this.people$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isPersonOfOrgUnit'), + relationsToItems(this.item.id, this.ids) + ); + + this.projects$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isProjectOfOrgUnit'), + relationsToItems(this.item.id, this.ids) + ); + + this.publications$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isPublicationOfOrgUnit'), + relationsToItems(this.item.id, this.ids) + ); + }} diff --git a/src/app/+item-page/simple/entity-types/person/person-page-fields.component.html b/src/app/+item-page/simple/entity-types/person/person-page-fields.component.html index a19170b77d..16a33a65de 100644 --- a/src/app/+item-page/simple/entity-types/person/person-page-fields.component.html +++ b/src/app/+item-page/simple/entity-types/person/person-page-fields.component.html @@ -24,13 +24,18 @@
- - - - {{publ.name}} - - - + + + + + + diff --git a/src/app/+item-page/simple/entity-types/person/person-page-fields.component.ts b/src/app/+item-page/simple/entity-types/person/person-page-fields.component.ts index dce8fe5dbe..61b2d87389 100644 --- a/src/app/+item-page/simple/entity-types/person/person-page-fields.component.ts +++ b/src/app/+item-page/simple/entity-types/person/person-page-fields.component.ts @@ -1,67 +1,14 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { Observable } from 'rxjs/Observable'; -import { distinctUntilChanged, filter, flatMap, map } from 'rxjs/operators'; import { ItemDataService } from '../../../../core/data/item-data.service'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { RelationshipType } from '../../../../core/shared/entities/relationship-type.model'; -import { Relationship } from '../../../../core/shared/entities/relationship.model'; import { Item } from '../../../../core/shared/item.model'; -import { getRemoteDataPayload } from '../../../../core/shared/operators'; -import { hasValue } from '../../../../shared/empty.util'; import { rendersEntityType } from '../../../../shared/entities/entity-type-decorator'; -import { ElementViewMode } from '../../../../shared/view-mode'; import { ITEM } from '../../../../shared/entities/switcher/entity-type-switcher.component'; - -const compareArraysUsing = (mapFn: (t: T) => any) => - (a: T[], b: T[]): boolean => { - if (!Array.isArray(a) || ! Array.isArray(b)) { - return false - } - - const aIds = a.map(mapFn); - const bIds = b.map(mapFn); - - return aIds.length === bIds.length && - aIds.every((e) => bIds.includes(e)) && - bIds.every((e) => aIds.includes(e)); - }; - -const compareArraysUsingIds = () => - compareArraysUsing((t: T) => hasValue(t) ? t.id : undefined); - -const filterRelationsByTypeLabel = (label: string) => - (source: Observable<[Relationship[], RelationshipType[]]>): Observable => - source.pipe( - map(([relsCurrentPage, relTypesCurrentPage]) => - relsCurrentPage.filter((rel: Relationship, idx: number) => - hasValue(relTypesCurrentPage[idx]) && (relTypesCurrentPage[idx].leftLabel === label || - relTypesCurrentPage[idx].rightLabel === label) - ) - ), - distinctUntilChanged(compareArraysUsingIds()) - ); - -const relationsToItems = (thisId: string, ids: ItemDataService) => - (source: Observable): Observable => - source.pipe( - flatMap((rels: Relationship[]) => - Observable.zip( - ...rels.map((rel: Relationship) => { - let queryId = rel.leftId; - if (rel.leftId === thisId) { - queryId = rel.rightId; - } - return ids.findById(queryId); - }) - ) - ), - map((arr: Array>) => - arr - .filter((d: RemoteData) => d.hasSucceeded) - .map((d: RemoteData) => d.payload)), - distinctUntilChanged(compareArraysUsingIds()), - ); +import { ElementViewMode } from '../../../../shared/view-mode'; +import { + EntityPageFieldsComponent, filterRelationsByTypeLabel, + relationsToItems +} from '../shared/entity-page-fields.component'; @rendersEntityType('Person', ElementViewMode.Full) @Component({ @@ -69,7 +16,7 @@ const relationsToItems = (thisId: string, ids: ItemDataService) => styleUrls: ['./person-page-fields.component.scss'], templateUrl: './person-page-fields.component.html' }) -export class PersonPageFieldsComponent implements OnInit { +export class PersonPageFieldsComponent extends EntityPageFieldsComponent { publications$: Observable; projects$: Observable; orgUnits$: Observable; @@ -77,46 +24,25 @@ export class PersonPageFieldsComponent implements OnInit { constructor( @Inject(ITEM) public item: Item, private ids: ItemDataService - ) {} - + ) { + super(item); + } ngOnInit(): void { - const relsCurrentPage$ = this.item.relationships.pipe( - filter((rd: RemoteData>) => rd.hasSucceeded), - getRemoteDataPayload(), - map((pl: PaginatedList) => pl.page), - distinctUntilChanged(compareArraysUsingIds()) - ); + super.ngOnInit(); - const relTypesCurrentPage$ = relsCurrentPage$.pipe( - flatMap((rels: Relationship[]) => - Observable.zip( - ...rels.map((rel: Relationship) => rel.relationshipType), - (...arr: Array>) => - arr.map((d: RemoteData) => d.payload) - ) - ), - distinctUntilChanged(compareArraysUsingIds()) - ); - - const resolvedRelsAndTypes$ = Observable.combineLatest( - relsCurrentPage$, - relTypesCurrentPage$ - ); - - this.publications$ = resolvedRelsAndTypes$.pipe( + this.publications$ = this.resolvedRelsAndTypes$.pipe( filterRelationsByTypeLabel('isPublicationOfAuthor'), relationsToItems(this.item.id, this.ids) ); - this.projects$ = resolvedRelsAndTypes$.pipe( + this.projects$ = this.resolvedRelsAndTypes$.pipe( filterRelationsByTypeLabel('isProjectOfPerson'), relationsToItems(this.item.id, this.ids) ); - this.orgUnits$ = resolvedRelsAndTypes$.pipe( + this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( filterRelationsByTypeLabel('isOrgUnitOfPerson'), relationsToItems(this.item.id, this.ids) ); } - } diff --git a/src/app/+item-page/simple/entity-types/project/project-page-fields.component.html b/src/app/+item-page/simple/entity-types/project/project-page-fields.component.html index 65a7c7f270..51168011f1 100644 --- a/src/app/+item-page/simple/entity-types/project/project-page-fields.component.html +++ b/src/app/+item-page/simple/entity-types/project/project-page-fields.component.html @@ -20,6 +20,18 @@
+ + + + + + diff --git a/src/app/+item-page/simple/entity-types/project/project-page-fields.component.ts b/src/app/+item-page/simple/entity-types/project/project-page-fields.component.ts index d648247a58..844d0f3808 100644 --- a/src/app/+item-page/simple/entity-types/project/project-page-fields.component.ts +++ b/src/app/+item-page/simple/entity-types/project/project-page-fields.component.ts @@ -1,8 +1,14 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { ItemDataService } from '../../../../core/data/item-data.service'; import { Item } from '../../../../core/shared/item.model'; import { rendersEntityType } from '../../../../shared/entities/entity-type-decorator'; import { ElementViewMode } from '../../../../shared/view-mode'; import { ITEM } from '../../../../shared/entities/switcher/entity-type-switcher.component'; +import { + EntityPageFieldsComponent, filterRelationsByTypeLabel, + relationsToItems +} from '../shared/entity-page-fields.component'; @rendersEntityType('Project', ElementViewMode.Full) @Component({ @@ -10,9 +16,34 @@ import { ITEM } from '../../../../shared/entities/switcher/entity-type-switcher. styleUrls: ['./project-page-fields.component.scss'], templateUrl: './project-page-fields.component.html' }) -export class ProjectPageFieldsComponent { +export class ProjectPageFieldsComponent extends EntityPageFieldsComponent implements OnInit { + people$: Observable; + publications$: Observable; + orgUnits$: Observable; - constructor(@Inject(ITEM) public item: Item) { + constructor( + @Inject(ITEM) public item: Item, + private ids: ItemDataService + ) { + super(item); } + ngOnInit(): void { + super.ngOnInit(); + + this.people$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isPersonOfProject'), + relationsToItems(this.item.id, this.ids) + ); + + this.publications$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isPublicationOfProject'), + relationsToItems(this.item.id, this.ids) + ); + + this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isOrgUnitOfProject'), + relationsToItems(this.item.id, this.ids) + ); + } } diff --git a/src/app/+item-page/simple/entity-types/item/item-page-fields.component.html b/src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.html similarity index 61% rename from src/app/+item-page/simple/entity-types/item/item-page-fields.component.html rename to src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.html index 6301bc1bc9..f83338095a 100644 --- a/src/app/+item-page/simple/entity-types/item/item-page-fields.component.html +++ b/src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.html @@ -6,9 +6,21 @@ - +
+ + + + + + diff --git a/src/app/+item-page/simple/entity-types/item/item-page-fields.component.scss b/src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.scss similarity index 100% rename from src/app/+item-page/simple/entity-types/item/item-page-fields.component.scss rename to src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.scss diff --git a/src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.ts b/src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.ts new file mode 100644 index 0000000000..e65bba2945 --- /dev/null +++ b/src/app/+item-page/simple/entity-types/publication/publication-page-fields.component.ts @@ -0,0 +1,54 @@ +import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { ItemDataService } from '../../../../core/data/item-data.service'; +import { Item } from '../../../../core/shared/item.model'; +import { + DEFAULT_ENTITY_TYPE, + rendersEntityType +} from '../../../../shared/entities/entity-type-decorator'; +import { ITEM } from '../../../../shared/entities/switcher/entity-type-switcher.component'; +import { ElementViewMode } from '../../../../shared/view-mode'; +import { + EntityPageFieldsComponent, + filterRelationsByTypeLabel, relationsToItems +} from '../shared/entity-page-fields.component'; + +@rendersEntityType('Publication', ElementViewMode.Full) +@rendersEntityType(DEFAULT_ENTITY_TYPE, ElementViewMode.Full) +@Component({ + selector: 'ds-publication-page-fields', + styleUrls: ['./publication-page-fields.component.scss'], + templateUrl: './publication-page-fields.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PublicationPageFieldsComponent extends EntityPageFieldsComponent implements OnInit { + authors$: Observable; + projects$: Observable; + orgUnits$: Observable; + + constructor( + @Inject(ITEM) public item: Item, + private ids: ItemDataService + ) { + super(item); + } + + ngOnInit(): void { + super.ngOnInit(); + + this.authors$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isAuthorOfPublication'), + relationsToItems(this.item.id, this.ids) + ); + + this.projects$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isProjectOfPublication'), + relationsToItems(this.item.id, this.ids) + ); + + this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( + filterRelationsByTypeLabel('isOrgUnitOfPublication'), + relationsToItems(this.item.id, this.ids) + ); + } +} diff --git a/src/app/+item-page/simple/entity-types/shared/entity-page-fields.component.ts b/src/app/+item-page/simple/entity-types/shared/entity-page-fields.component.ts new file mode 100644 index 0000000000..712b84a37b --- /dev/null +++ b/src/app/+item-page/simple/entity-types/shared/entity-page-fields.component.ts @@ -0,0 +1,100 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { distinctUntilChanged, filter, flatMap, map } from 'rxjs/operators'; +import { ItemDataService } from '../../../../core/data/item-data.service'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { RelationshipType } from '../../../../core/shared/entities/relationship-type.model'; +import { Relationship } from '../../../../core/shared/entities/relationship.model'; +import { Item } from '../../../../core/shared/item.model'; +import { getRemoteDataPayload } from '../../../../core/shared/operators'; +import { hasValue } from '../../../../shared/empty.util'; +import { ITEM } from '../../../../shared/entities/switcher/entity-type-switcher.component'; + +const compareArraysUsing = (mapFn: (t: T) => any) => + (a: T[], b: T[]): boolean => { + if (!Array.isArray(a) || ! Array.isArray(b)) { + return false + } + + const aIds = a.map(mapFn); + const bIds = b.map(mapFn); + + return aIds.length === bIds.length && + aIds.every((e) => bIds.includes(e)) && + bIds.every((e) => aIds.includes(e)); + }; + +const compareArraysUsingIds = () => + compareArraysUsing((t: T) => hasValue(t) ? t.id : undefined); + +export const filterRelationsByTypeLabel = (label: string) => + (source: Observable<[Relationship[], RelationshipType[]]>): Observable => + source.pipe( + map(([relsCurrentPage, relTypesCurrentPage]) => + relsCurrentPage.filter((rel: Relationship, idx: number) => + hasValue(relTypesCurrentPage[idx]) && (relTypesCurrentPage[idx].leftLabel === label || + relTypesCurrentPage[idx].rightLabel === label) + ) + ), + distinctUntilChanged(compareArraysUsingIds()) + ); + +export const relationsToItems = (thisId: string, ids: ItemDataService) => + (source: Observable): Observable => + source.pipe( + flatMap((rels: Relationship[]) => + Observable.zip( + ...rels.map((rel: Relationship) => { + let queryId = rel.leftId; + if (rel.leftId === thisId) { + queryId = rel.rightId; + } + return ids.findById(queryId); + }) + ) + ), + map((arr: Array>) => + arr + .filter((d: RemoteData) => d.hasSucceeded) + .map((d: RemoteData) => d.payload)), + distinctUntilChanged(compareArraysUsingIds()), + ); + +@Component({ + selector: 'ds-entity-page-fields', + template: '' +}) +export class EntityPageFieldsComponent implements OnInit { + resolvedRelsAndTypes$: Observable<[Relationship[], RelationshipType[]]> + + constructor( + @Inject(ITEM) public item: Item + ) {} + + ngOnInit(): void { + const relsCurrentPage$ = this.item.relationships.pipe( + filter((rd: RemoteData>) => rd.hasSucceeded), + getRemoteDataPayload(), + map((pl: PaginatedList) => pl.page), + distinctUntilChanged(compareArraysUsingIds()) + ); + + const relTypesCurrentPage$ = relsCurrentPage$.pipe( + flatMap((rels: Relationship[]) => + Observable.zip( + ...rels.map((rel: Relationship) => rel.relationshipType), + (...arr: Array>) => + arr.map((d: RemoteData) => d.payload) + ) + ), + distinctUntilChanged(compareArraysUsingIds()) + ); + + this.resolvedRelsAndTypes$ = Observable.combineLatest( + relsCurrentPage$, + relTypesCurrentPage$ + ); + } + +} diff --git a/src/app/+item-page/simple/related-entities/related-entities-component.ts b/src/app/+item-page/simple/related-entities/related-entities-component.ts new file mode 100644 index 0000000000..b49e89c7aa --- /dev/null +++ b/src/app/+item-page/simple/related-entities/related-entities-component.ts @@ -0,0 +1,14 @@ +import { Component, Input } from '@angular/core'; +import { Item } from '../../../core/shared/item.model'; +import * as viewMode from '../../../shared/view-mode'; + +@Component({ + selector: 'ds-related-entities', + styleUrls: ['./related-entities.component.scss'], + templateUrl: './related-entities.component.html' +}) +export class RelatedEntitiesComponent { + @Input() entities: Item[]; + @Input() label: string; + ElementViewMode = viewMode.ElementViewMode +} diff --git a/src/app/+item-page/simple/related-entities/related-entities.component.html b/src/app/+item-page/simple/related-entities/related-entities.component.html new file mode 100644 index 0000000000..f09f0ccdef --- /dev/null +++ b/src/app/+item-page/simple/related-entities/related-entities.component.html @@ -0,0 +1,5 @@ + + + + diff --git a/src/app/+item-page/simple/related-entities/related-entities.component.scss b/src/app/+item-page/simple/related-entities/related-entities.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/object-list/item-list-element/entity-types/orgunit/orgunit-list-element.component.html b/src/app/shared/object-list/item-list-element/entity-types/orgunit/orgunit-list-element.component.html index 901d521033..824a90a3de 100644 --- a/src/app/shared/object-list/item-list-element/entity-types/orgunit/orgunit-list-element.component.html +++ b/src/app/shared/object-list/item-list-element/entity-types/orgunit/orgunit-list-element.component.html @@ -3,7 +3,7 @@ [routerLink]="['/items/' + item.id]" class="lead" [innerHTML]="getFirstValue('orgunit.identifier.name')"> - + - ((, ) + [innerHTML]="getFirstValue('dc.date.issued')">) diff --git a/src/app/shared/object-list/item-list-element/entity-types/item/item-list-element.component.scss b/src/app/shared/object-list/item-list-element/entity-types/publication/publication-list-element.component.scss similarity index 100% rename from src/app/shared/object-list/item-list-element/entity-types/item/item-list-element.component.scss rename to src/app/shared/object-list/item-list-element/entity-types/publication/publication-list-element.component.scss diff --git a/src/app/shared/object-list/item-list-element/entity-types/item/item-list-element.component.ts b/src/app/shared/object-list/item-list-element/entity-types/publication/publication-list-element.component.ts similarity index 54% rename from src/app/shared/object-list/item-list-element/entity-types/item/item-list-element.component.ts rename to src/app/shared/object-list/item-list-element/entity-types/publication/publication-list-element.component.ts index db68ecec7b..3f8b7a59f3 100644 --- a/src/app/shared/object-list/item-list-element/entity-types/item/item-list-element.component.ts +++ b/src/app/shared/object-list/item-list-element/entity-types/publication/publication-list-element.component.ts @@ -3,13 +3,13 @@ import { DEFAULT_ENTITY_TYPE, rendersEntityType } from '../../../../entities/ent import { ElementViewMode } from '../../../../view-mode'; import { EntitySearchResultComponent } from '../entity-search-result-component'; -@rendersEntityType('Item', ElementViewMode.SetElement) +@rendersEntityType('Publication', ElementViewMode.SetElement) @rendersEntityType(DEFAULT_ENTITY_TYPE, ElementViewMode.SetElement) @Component({ - selector: 'ds-item-list-element', - styleUrls: ['./item-list-element.component.scss'], - templateUrl: './item-list-element.component.html' + selector: 'ds-publication-list-element', + styleUrls: ['./publication-list-element.component.scss'], + templateUrl: './publication-list-element.component.html' }) -export class ItemListElementComponent extends EntitySearchResultComponent { +export class PublicationListElementComponent extends EntitySearchResultComponent { } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 90d498eedd..0da82f5e2f 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -10,7 +10,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { NgxPaginationModule } from 'ngx-pagination'; import { EntityTypeSwitcherComponent } from './entities/switcher/entity-type-switcher.component'; import { EntitySearchResultComponent } from './object-list/item-list-element/entity-types/entity-search-result-component'; -import { ItemListElementComponent } from './object-list/item-list-element/entity-types/item/item-list-element.component'; +import { PublicationListElementComponent } from './object-list/item-list-element/entity-types/publication/publication-list-element.component'; import { OrgUnitListElementComponent } from './object-list/item-list-element/entity-types/orgunit/orgunit-list-element.component'; import { PersonListElementComponent } from './object-list/item-list-element/entity-types/person/person-list-element.component'; import { ProjectListElementComponent } from './object-list/item-list-element/entity-types/project/project-list-element.component'; @@ -109,7 +109,7 @@ const ENTRY_COMPONENTS = [ CollectionGridElementComponent, CommunityGridElementComponent, SearchResultGridElementComponent, - ItemListElementComponent, + PublicationListElementComponent, PersonListElementComponent, OrgUnitListElementComponent, ProjectListElementComponent