diff --git a/docker/README.md b/docker/README.md index ed0def0480..809a150d86 100644 --- a/docker/README.md +++ b/docker/README.md @@ -5,7 +5,7 @@ - Starts DSpace Angular with Docker Compose from the current branch. This file assumes that a DSpace 7 REST instance will also be started in Docker. - docker-compose-rest.yml - Runs a published instance of the DSpace 7 REST API - persists data in Docker volumes -- docker-compose-travis.yml +- docker-compose-ci.yml - Runs a published instance of the DSpace 7 REST API for CI testing. The database is re-populated from a SQL dump on each startup. - cli.yml - Docker compose file that provides a DSpace CLI container to work with a running DSpace REST container. diff --git a/docker/cli.assetstore.yml b/docker/cli.assetstore.yml index 075c494a6c..592194a752 100644 --- a/docker/cli.assetstore.yml +++ b/docker/cli.assetstore.yml @@ -1,3 +1,17 @@ +# +# The contents of this file are subject to the license and copyright +# detailed in the LICENSE and NOTICE files at the root of the source +# tree and available online at +# +# http://www.dspace.org/license/ +# + +# +# This is a copy of the cli.ingest.yml that is available in the DSpace/DSpace +# (Backend) at: +# https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/cli.assetstore.yml +# +# Therefore, it should be kept in sync with that file version: "3.7" networks: @@ -8,7 +22,7 @@ services: networks: dspacenet: {} environment: - - LOADASSETS=https://www.dropbox.com/s/zv7lj8j2lp3egjs/assetstore.tar.gz?dl=1 + - LOADASSETS=https://www.dropbox.com/s/v3ahfcuatklbmi0/assetstore-2019-11-28.tar.gz?dl=1 entrypoint: - /bin/bash - '-c' @@ -21,3 +35,5 @@ services: fi /dspace/bin/dspace index-discovery + /dspace/bin/dspace oai import + /dspace/bin/dspace oai clean-cache diff --git a/docker/cli.ingest.yml b/docker/cli.ingest.yml index 3972a87d50..1db241af3b 100644 --- a/docker/cli.ingest.yml +++ b/docker/cli.ingest.yml @@ -6,6 +6,12 @@ # http://www.dspace.org/license/ # +# +# This is a copy of the cli.ingest.yml that is available in the DSpace/DSpace +# (Backend) at: +# https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/cli.ingest.yml +# +# Therefore, it should be kept in sync with that file version: "3.7" services: diff --git a/docker/cli.yml b/docker/cli.yml index ea5e3e0595..36f63b2cff 100644 --- a/docker/cli.yml +++ b/docker/cli.yml @@ -1,3 +1,17 @@ +# +# The contents of this file are subject to the license and copyright +# detailed in the LICENSE and NOTICE files at the root of the source +# tree and available online at +# +# http://www.dspace.org/license/ +# + +# +# This is a copy of the docker-compose-cli.yml that is available in the DSpace/DSpace +# (Backend) at: +# https://github.com/DSpace/DSpace/blob/main/docker-compose-cli.yml +# +# Therefore, it should be kept in sync with that file version: "3.7" services: diff --git a/docker/db.entities.yml b/docker/db.entities.yml index 91d96bd72b..d39eedc5c6 100644 --- a/docker/db.entities.yml +++ b/docker/db.entities.yml @@ -6,11 +6,17 @@ # http://www.dspace.org/license/ # +# +# This is a copy of the db.entities.yml that is available in the DSpace/DSpace +# (Backend) at: +# https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/db.entities.yml +# +# # Therefore, it should be kept in sync with that file version: "3.7" services: dspacedb: image: dspace/dspace-postgres-pgcrypto:loadsql environment: - # Double underbars in env names will be replaced with periods for apache commons - - LOADSQL=https://www.dropbox.com/s/xh3ack0vg0922p2/configurable-entities-2019-05-08.sql?dl=1 + # This LOADSQL should be kept in sync with the URL in DSpace/DSpace + - LOADSQL=https://www.dropbox.com/s/4ap1y6deseoc8ws/dspace7-entities-2019-11-28.sql?dl=1 diff --git a/docker/docker-compose-ci.yml b/docker/docker-compose-ci.yml index f440454bb6..ec2d0912cf 100644 --- a/docker/docker-compose-ci.yml +++ b/docker/docker-compose-ci.yml @@ -1,4 +1,13 @@ -# Docker Compose for running the DSpace backend for e2e testing in CI +# +# The contents of this file are subject to the license and copyright +# detailed in the LICENSE and NOTICE files at the root of the source +# tree and available online at +# +# http://www.dspace.org/license/ +# + +# Docker Compose for running the DSpace backend for e2e testing in a CI environment +# This is used by our GitHub CI at .github/workflows/build.yml networks: dspacenet: services: @@ -20,7 +29,9 @@ services: dspacedb: container_name: dspacedb environment: - LOADSQL: https://www.dropbox.com/s/xh3ack0vg0922p2/configurable-entities-2019-05-08.sql?dl=1 + # This LOADSQL should be kept in sync with the LOADSQL in + # https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/db.entities.yml + LOADSQL: https://www.dropbox.com/s/4ap1y6deseoc8ws/dspace7-entities-2019-11-28.sql?dl=1 PGDATA: /pgdata image: dspace/dspace-postgres-pgcrypto:loadsql networks: diff --git a/docker/docker-compose-rest.yml b/docker/docker-compose-rest.yml index 6f5a1d6c83..e6668f3f58 100644 --- a/docker/docker-compose-rest.yml +++ b/docker/docker-compose-rest.yml @@ -1,11 +1,24 @@ +# +# The contents of this file are subject to the license and copyright +# detailed in the LICENSE and NOTICE files at the root of the source +# tree and available online at +# +# http://www.dspace.org/license/ +# + +# Docker Compose for running the DSpace backend for testing/development +# This is based heavily on the docker-compose.yml that is available in the DSpace/DSpace +# (Backend) at: +# https://github.com/DSpace/DSpace/blob/main/docker-compose.yml +version: '3.7' networks: dspacenet: services: dspace: container_name: dspace + image: dspace/dspace:dspace-7_x-test depends_on: - dspacedb - image: dspace/dspace:dspace-7_x-test networks: dspacenet: ports: @@ -16,20 +29,27 @@ services: volumes: - assetstore:/dspace/assetstore - "./local.cfg:/dspace/config/local.cfg" - # Ensure that the database is ready before starting tomcat + # Ensure that the database is ready BEFORE starting tomcat + # 1. While a TCP connection to dspacedb port 5432 is not available, continue to sleep + # 2. Then, run database migration to init database tables + # 3. Finally, start Tomcat entrypoint: - /bin/bash - '-c' - | + while (! /dev/null 2>&1; do sleep 1; done; /dspace/bin/dspace database migrate catalina.sh run dspacedb: container_name: dspacedb - image: dspace/dspace-postgres-pgcrypto environment: PGDATA: /pgdata + image: dspace/dspace-postgres-pgcrypto networks: dspacenet: + ports: + - published: 5432 + target: 5432 stdin_open: true tty: true volumes: @@ -49,7 +69,6 @@ services: - solr_oai:/opt/solr/server/solr/oai/data - solr_search:/opt/solr/server/solr/search/data - solr_statistics:/opt/solr/server/solr/statistics/data -version: '3.7' volumes: assetstore: pgdata: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 33268778f3..7c5c326959 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,3 +1,14 @@ +# +# The contents of this file are subject to the license and copyright +# detailed in the LICENSE and NOTICE files at the root of the source +# tree and available online at +# +# http://www.dspace.org/license/ +# + +# Docker Compose for running the DSpace Angular UI for testing/development +# Requires also running a REST API backend (either locally or remotely), +# for example via 'docker-compose-rest.yml' version: '3.7' networks: dspacenet: diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.spec.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.spec.ts index 7799a3d61d..3ae11e792c 100644 --- a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.spec.ts +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.spec.ts @@ -12,7 +12,7 @@ import { WorkflowItem } from '../../../../../core/submission/models/workflowitem import { LinkService } from '../../../../../core/cache/builders/link.service'; import { followLink } from '../../../../../shared/utils/follow-link-config.model'; import { Item } from '../../../../../core/shared/item.model'; -import { PublicationGridElementComponent } from '../../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component'; +import { ItemGridElementComponent } from '../../../../../shared/object-grid/item-grid-element/item-types/item/item-grid-element.component'; import { ListableObjectDirective } from '../../../../../shared/object-collection/shared/listable-object/listable-object.directive'; import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model'; import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; @@ -43,7 +43,7 @@ describe('WorkflowItemAdminWorkflowGridElementComponent', () => { init(); TestBed.configureTestingModule( { - declarations: [WorkflowItemSearchResultAdminWorkflowGridElementComponent, PublicationGridElementComponent, ListableObjectDirective], + declarations: [WorkflowItemSearchResultAdminWorkflowGridElementComponent, ItemGridElementComponent, ListableObjectDirective], imports: [ NoopAnimationsModule, TranslateModule.forRoot(), @@ -60,7 +60,7 @@ describe('WorkflowItemAdminWorkflowGridElementComponent', () => { }) .overrideComponent(WorkflowItemSearchResultAdminWorkflowGridElementComponent, { set: { - entryComponents: [PublicationGridElementComponent] + entryComponents: [ItemGridElementComponent] } }) .compileComponents(); diff --git a/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.html b/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.html new file mode 100644 index 0000000000..fa66186ece --- /dev/null +++ b/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.spec.ts b/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.spec.ts new file mode 100644 index 0000000000..39f1ee6551 --- /dev/null +++ b/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.spec.ts @@ -0,0 +1,73 @@ +import { CommonModule } from '@angular/common'; +import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; + +import { cold } from 'jasmine-marbles'; +import { of as observableOf } from 'rxjs'; + +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { CollectionAuthorizationsComponent } from './collection-authorizations.component'; +import { Collection } from '../../../core/shared/collection.model'; +import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; + +describe('CollectionAuthorizationsComponent', () => { + let comp: CollectionAuthorizationsComponent; + let fixture: ComponentFixture>; + + const collection = Object.assign(new Collection(), { + uuid: 'collection', + id: 'collection', + _links: { + self: { href: 'collection-selflink' } + } + }); + + const collectionRD = createSuccessfulRemoteDataObject(collection); + + const routeStub = { + parent: { + parent: { + data: observableOf({ + dso: collectionRD + }) + } + } + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CommonModule + ], + declarations: [CollectionAuthorizationsComponent], + providers: [ + { provide: ActivatedRoute, useValue: routeStub }, + ChangeDetectorRef, + CollectionAuthorizationsComponent, + ], + schemas: [NO_ERRORS_SCHEMA], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CollectionAuthorizationsComponent); + comp = fixture.componentInstance; + fixture.detectChanges(); + }); + + afterEach(() => { + comp = null; + fixture.destroy(); + }); + + it('should create', () => { + expect(comp).toBeTruthy(); + }); + + it('should init dso remote data properly', (done) => { + const expected = cold('(a|)', { a: collectionRD }); + expect(comp.dsoRD$).toBeObservable(expected); + done(); + }); +}); diff --git a/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.ts b/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.ts new file mode 100644 index 0000000000..d1b59a0c90 --- /dev/null +++ b/src/app/+collection-page/edit-collection-page/collection-authorizations/collection-authorizations.component.ts @@ -0,0 +1,40 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { Observable } from 'rxjs'; +import { first, map } from 'rxjs/operators'; + +import { RemoteData } from '../../../core/data/remote-data'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; + +@Component({ + selector: 'ds-collection-authorizations', + templateUrl: './collection-authorizations.component.html', +}) +/** + * Component that handles the Collection Authorizations + */ +export class CollectionAuthorizationsComponent implements OnInit { + + /** + * The initial DSO object + */ + public dsoRD$: Observable>; + + /** + * Initialize instance variables + * + * @param {ActivatedRoute} route + */ + constructor( + private route: ActivatedRoute + ) { + } + + /** + * Initialize the component, setting up the collection + */ + ngOnInit(): void { + this.dsoRD$ = this.route.parent.parent.data.pipe(first(), map((data) => data.dso)); + } +} diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.module.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.module.ts index f442aae4d6..6ca0948512 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.module.ts +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.module.ts @@ -8,6 +8,7 @@ import { CollectionPageModule } from '../collection-page.module'; import { CollectionRolesComponent } from './collection-roles/collection-roles.component'; import { CollectionCurateComponent } from './collection-curate/collection-curate.component'; import { CollectionSourceComponent } from './collection-source/collection-source.component'; +import { CollectionAuthorizationsComponent } from './collection-authorizations/collection-authorizations.component'; /** * Module that contains all components related to the Edit Collection page administrator functionality @@ -24,7 +25,8 @@ import { CollectionSourceComponent } from './collection-source/collection-source CollectionMetadataComponent, CollectionRolesComponent, CollectionCurateComponent, - CollectionSourceComponent + CollectionSourceComponent, + CollectionAuthorizationsComponent ] }) export class EditCollectionPageModule { diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts index 0569de9cd9..818f064104 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts @@ -5,7 +5,12 @@ import { CollectionMetadataComponent } from './collection-metadata/collection-me import { CollectionRolesComponent } from './collection-roles/collection-roles.component'; import { CollectionSourceComponent } from './collection-source/collection-source.component'; import { CollectionCurateComponent } from './collection-curate/collection-curate.component'; +import { CollectionAuthorizationsComponent } from './collection-authorizations/collection-authorizations.component'; import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver'; +import { ResourcePolicyTargetResolver } from '../../shared/resource-policies/resolvers/resource-policy-target.resolver'; +import { ResourcePolicyCreateComponent } from '../../shared/resource-policies/create/resource-policy-create.component'; +import { ResourcePolicyResolver } from '../../shared/resource-policies/resolvers/resource-policy.resolver'; +import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit/resource-policy-edit.component'; /** * Routing module that handles the routing for the Edit Collection page administrator functionality @@ -49,10 +54,46 @@ import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.r path: 'curate', component: CollectionCurateComponent, data: { title: 'collection.edit.tabs.curate.title', showBreadcrumbs: true } + }, +/* { + path: 'authorizations', + component: CollectionAuthorizationsComponent, + data: { title: 'collection.edit.tabs.authorizations.title', showBreadcrumbs: true } + },*/ + { + path: 'authorizations', + data: { showBreadcrumbs: true }, + children: [ + { + path: 'create', + resolve: { + resourcePolicyTarget: ResourcePolicyTargetResolver + }, + component: ResourcePolicyCreateComponent, + data: { title: 'resource-policies.create.page.title' } + }, + { + path: 'edit', + resolve: { + resourcePolicy: ResourcePolicyResolver + }, + component: ResourcePolicyEditComponent, + data: { title: 'resource-policies.edit.page.title' } + }, + { + path: '', + component: CollectionAuthorizationsComponent, + data: { title: 'collection.edit.tabs.authorizations.title', showBreadcrumbs: true } + } + ] } ] } ]) + ], + providers: [ + ResourcePolicyResolver, + ResourcePolicyTargetResolver ] }) export class EditCollectionPageRoutingModule { diff --git a/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.html b/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.html new file mode 100644 index 0000000000..abf2f87141 --- /dev/null +++ b/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.spec.ts b/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.spec.ts new file mode 100644 index 0000000000..dd10bdce29 --- /dev/null +++ b/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.spec.ts @@ -0,0 +1,73 @@ +import { CommonModule } from '@angular/common'; +import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; + +import { cold } from 'jasmine-marbles'; +import { of as observableOf } from 'rxjs'; + +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; +import { CommunityAuthorizationsComponent } from './community-authorizations.component'; +import { Collection } from '../../../core/shared/collection.model'; + +describe('CommunityAuthorizationsComponent', () => { + let comp: CommunityAuthorizationsComponent; + let fixture: ComponentFixture>; + + const community = Object.assign(new Collection(), { + uuid: 'community', + id: 'community', + _links: { + self: { href: 'community-selflink' } + } + }); + + const communityRD = createSuccessfulRemoteDataObject(community); + + const routeStub = { + parent: { + parent: { + data: observableOf({ + dso: communityRD + }) + } + } + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + CommonModule + ], + declarations: [CommunityAuthorizationsComponent], + providers: [ + { provide: ActivatedRoute, useValue: routeStub }, + ChangeDetectorRef, + CommunityAuthorizationsComponent, + ], + schemas: [NO_ERRORS_SCHEMA], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CommunityAuthorizationsComponent); + comp = fixture.componentInstance; + fixture.detectChanges(); + }); + + afterEach(() => { + comp = null; + fixture.destroy(); + }); + + it('should create', () => { + expect(comp).toBeTruthy(); + }); + + it('should init dso remote data properly', (done) => { + const expected = cold('(a|)', { a: communityRD }); + expect(comp.dsoRD$).toBeObservable(expected); + done(); + }); +}); diff --git a/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.ts b/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.ts new file mode 100644 index 0000000000..8b241af667 --- /dev/null +++ b/src/app/+community-page/edit-community-page/community-authorizations/community-authorizations.component.ts @@ -0,0 +1,38 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs'; +import { first, map } from 'rxjs/operators'; +import { RemoteData } from 'src/app/core/data/remote-data'; +import { DSpaceObject } from 'src/app/core/shared/dspace-object.model'; + +@Component({ + selector: 'ds-community-authorizations', + templateUrl: './community-authorizations.component.html', +}) +/** + * Component that handles the community Authorizations + */ +export class CommunityAuthorizationsComponent implements OnInit { + + /** + * The initial DSO object + */ + public dsoRD$: Observable>; + + /** + * Initialize instance variables + * + * @param {ActivatedRoute} route + */ + constructor( + private route: ActivatedRoute + ) { + } + + /** + * Initialize the component, setting up the community + */ + ngOnInit(): void { + this.dsoRD$ = this.route.parent.parent.data.pipe(first(), map((data) => data.dso)); + } +} diff --git a/src/app/+community-page/edit-community-page/edit-community-page.module.ts b/src/app/+community-page/edit-community-page/edit-community-page.module.ts index f9a1e11a14..9c4a97eb5e 100644 --- a/src/app/+community-page/edit-community-page/edit-community-page.module.ts +++ b/src/app/+community-page/edit-community-page/edit-community-page.module.ts @@ -7,6 +7,7 @@ import { EditCommunityPageComponent } from './edit-community-page.component'; import { CommunityCurateComponent } from './community-curate/community-curate.component'; import { CommunityMetadataComponent } from './community-metadata/community-metadata.component'; import { CommunityRolesComponent } from './community-roles/community-roles.component'; +import { CommunityAuthorizationsComponent } from './community-authorizations/community-authorizations.component'; /** * Module that contains all components related to the Edit Community page administrator functionality @@ -22,7 +23,8 @@ import { CommunityRolesComponent } from './community-roles/community-roles.compo EditCommunityPageComponent, CommunityCurateComponent, CommunityMetadataComponent, - CommunityRolesComponent + CommunityRolesComponent, + CommunityAuthorizationsComponent ] }) export class EditCommunityPageModule { diff --git a/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts b/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts index 3197e00829..440fa01a30 100644 --- a/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts +++ b/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts @@ -1,4 +1,3 @@ -import { CommunityPageResolver } from '../community-page.resolver'; import { EditCommunityPageComponent } from './edit-community-page.component'; import { RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; @@ -6,6 +5,11 @@ import { CommunityMetadataComponent } from './community-metadata/community-metad import { CommunityRolesComponent } from './community-roles/community-roles.component'; import { CommunityCurateComponent } from './community-curate/community-curate.component'; import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver'; +import { CommunityAuthorizationsComponent } from './community-authorizations/community-authorizations.component'; +import { ResourcePolicyTargetResolver } from '../../shared/resource-policies/resolvers/resource-policy-target.resolver'; +import { ResourcePolicyCreateComponent } from '../../shared/resource-policies/create/resource-policy-create.component'; +import { ResourcePolicyResolver } from '../../shared/resource-policies/resolvers/resource-policy.resolver'; +import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit/resource-policy-edit.component'; /** * Routing module that handles the routing for the Edit Community page administrator functionality @@ -44,11 +48,47 @@ import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.r path: 'curate', component: CommunityCurateComponent, data: { title: 'community.edit.tabs.curate.title', showBreadcrumbs: true } + }, + /*{ + path: 'authorizations', + component: CommunityAuthorizationsComponent, + data: { title: 'community.edit.tabs.authorizations.title', showBreadcrumbs: true } + },*/ + { + path: 'authorizations', + data: { showBreadcrumbs: true }, + children: [ + { + path: 'create', + resolve: { + resourcePolicyTarget: ResourcePolicyTargetResolver + }, + component: ResourcePolicyCreateComponent, + data: { title: 'resource-policies.create.page.title' } + }, + { + path: 'edit', + resolve: { + resourcePolicy: ResourcePolicyResolver + }, + component: ResourcePolicyEditComponent, + data: { title: 'resource-policies.edit.page.title' } + }, + { + path: '', + component: CommunityAuthorizationsComponent, + data: { title: 'community.edit.tabs.authorizations.title', showBreadcrumbs: true, hideReturnButton: true } + } + ] } ] } ]) ], + providers: [ + ResourcePolicyResolver, + ResourcePolicyTargetResolver + ] }) export class EditCommunityPageRoutingModule { diff --git a/src/app/+item-page/edit-item-page/edit-item-page.module.ts b/src/app/+item-page/edit-item-page/edit-item-page.module.ts index c3bd9eb924..17010acab4 100644 --- a/src/app/+item-page/edit-item-page/edit-item-page.module.ts +++ b/src/app/+item-page/edit-item-page/edit-item-page.module.ts @@ -30,8 +30,6 @@ import { PaginatedDragAndDropBitstreamListComponent } from './item-bitstreams/it import { VirtualMetadataComponent } from './virtual-metadata/virtual-metadata.component'; import { ItemVersionHistoryComponent } from './item-version-history/item-version-history.component'; import { ItemAuthorizationsComponent } from './item-authorizations/item-authorizations.component'; -import { ResourcePolicyEditComponent } from '../../shared/resource-policies/edit/resource-policy-edit.component'; -import { ResourcePolicyCreateComponent } from '../../shared/resource-policies/create/resource-policy-create.component'; import { ObjectValuesPipe } from '../../shared/utils/object-values-pipe'; /** @@ -71,9 +69,7 @@ import { ObjectValuesPipe } from '../../shared/utils/object-values-pipe'; ItemMoveComponent, ItemEditBitstreamDragHandleComponent, VirtualMetadataComponent, - ItemAuthorizationsComponent, - ResourcePolicyEditComponent, - ResourcePolicyCreateComponent, + ItemAuthorizationsComponent ], providers: [ BundleDataService, diff --git a/src/app/+item-page/item-page.module.ts b/src/app/+item-page/item-page.module.ts index 76eee25880..ca1924bd5d 100644 --- a/src/app/+item-page/item-page.module.ts +++ b/src/app/+item-page/item-page.module.ts @@ -30,6 +30,7 @@ import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.c import { TabbedRelatedEntitiesSearchComponent } from './simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component'; import { StatisticsModule } from '../statistics/statistics.module'; import { AbstractIncrementalListComponent } from './simple/abstract-incremental-list/abstract-incremental-list.component'; +import { UntypedItemComponent } from './simple/item-types/untyped-item/untyped-item.component'; @NgModule({ imports: [ @@ -54,6 +55,7 @@ import { AbstractIncrementalListComponent } from './simple/abstract-incremental- CollectionsComponent, FullFileSectionComponent, PublicationComponent, + UntypedItemComponent, RelatedItemsComponent, ItemComponent, GenericItemPageFieldComponent, diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.ts b/src/app/+item-page/simple/item-types/publication/publication.component.ts index f01d0f72d3..5ace8d0473 100644 --- a/src/app/+item-page/simple/item-types/publication/publication.component.ts +++ b/src/app/+item-page/simple/item-types/publication/publication.component.ts @@ -1,5 +1,4 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { Item } from '../../../../core/shared/item.model'; import { ItemComponent } from '../shared/item.component'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; @@ -9,7 +8,6 @@ import { listableObjectComponent } from '../../../../shared/object-collection/sh */ @listableObjectComponent('Publication', ViewMode.StandalonePage) -@listableObjectComponent(Item, ViewMode.StandalonePage) @Component({ selector: 'ds-publication', styleUrls: ['./publication.component.scss'], diff --git a/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.html b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.html new file mode 100644 index 0000000000..dcb73fad10 --- /dev/null +++ b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.html @@ -0,0 +1,67 @@ +
+

+ +

+
+ +
+
+
+
+ + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+
diff --git a/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.scss b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.scss new file mode 100644 index 0000000000..3575cae797 --- /dev/null +++ b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.scss @@ -0,0 +1 @@ +@import '../../../../../styles/variables.scss'; diff --git a/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.spec.ts b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.spec.ts new file mode 100644 index 0000000000..83585dead5 --- /dev/null +++ b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.spec.ts @@ -0,0 +1,112 @@ +import { HttpClient } from '@angular/common/http'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { Store } from '@ngrx/store'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../../core/cache/object-cache.service'; +import { BitstreamDataService } from '../../../../core/data/bitstream-data.service'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; +import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service'; +import { ItemDataService } from '../../../../core/data/item-data.service'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { RelationshipService } from '../../../../core/data/relationship.service'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { Bitstream } from '../../../../core/shared/bitstream.model'; +import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service'; +import { Item } from '../../../../core/shared/item.model'; +import { MetadataMap } from '../../../../core/shared/metadata.models'; +import { PageInfo } from '../../../../core/shared/page-info.model'; +import { UUIDService } from '../../../../core/shared/uuid.service'; +import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component'; +import { createRelationshipsObservable } from '../shared/item.component.spec'; +import { UntypedItemComponent } from './untyped-item.component'; + +const mockItem: Item = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: new MetadataMap(), + relationships: createRelationshipsObservable() +}); + +describe('UntypedItemComponent', () => { + let comp: UntypedItemComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + } + }; + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + })], + declarations: [UntypedItemComponent, GenericItemPageFieldComponent, TruncatePipe], + providers: [ + { provide: ItemDataService, useValue: {} }, + { provide: TruncatableService, useValue: {} }, + { provide: RelationshipService, useValue: {} }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: Store, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: NotificationsService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(UntypedItemComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(UntypedItemComponent); + comp = fixture.componentInstance; + comp.object = mockItem; + fixture.detectChanges(); + })); + + it('should contain a component to display the date', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-date-field')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should contain a component to display the author', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-author-field')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should contain a component to display the abstract', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-abstract-field')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should contain a component to display the uri', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-uri-field')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + + it('should contain a component to display the collections', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-item-page-collections')); + expect(fields.length).toBeGreaterThanOrEqual(1); + }); + +}); diff --git a/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.ts b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.ts new file mode 100644 index 0000000000..3183c42a28 --- /dev/null +++ b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.ts @@ -0,0 +1,20 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { Item } from '../../../../core/shared/item.model'; +import { ItemComponent } from '../shared/item.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; + +/** + * Component that represents a publication Item page + */ + +@listableObjectComponent(Item, ViewMode.StandalonePage) +@Component({ + selector: 'ds-untyped-item', + styleUrls: ['./untyped-item.component.scss'], + templateUrl: './untyped-item.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class UntypedItemComponent extends ItemComponent { + +} diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts index 1b88c47d25..46ab83ad6b 100644 --- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts +++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts @@ -15,7 +15,7 @@ describe('RelatedEntitiesSearchComponent', () => { }); const mockRelationType = 'publicationsOfAuthor'; const mockConfiguration = 'publication'; - const mockFilter= `f.${mockRelationType}=${mockItem.id}`; + const mockFilter= `f.${mockRelationType}=${mockItem.id},equals`; beforeEach(async(() => { TestBed.configureTestingModule({ diff --git a/src/app/core/cache/object-cache.reducer.ts b/src/app/core/cache/object-cache.reducer.ts index 32fdd53da9..8fdbb651b9 100644 --- a/src/app/core/cache/object-cache.reducer.ts +++ b/src/app/core/cache/object-cache.reducer.ts @@ -33,6 +33,21 @@ export abstract class TypedObject { type: ResourceType; } +/** + * Get the string value for an object that may be a string or a ResourceType + * + * @param type the object to get the type value for + */ +export const getResourceTypeValueFor = (type: any): string => { + if (hasValue(type)) { + if (typeof type === 'string') { + return type; + } else if (typeof type.value === 'string') { + return type.value; + } + } +} + /* tslint:disable:max-classes-per-file */ /** * An interface to represent objects that can be cached diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index 5345e715ba..fd903f1ed0 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -1,7 +1,6 @@ import { autoserialize, autoserializeAs, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; import { isEmpty } from '../../shared/empty.util'; -import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { link, typedObject } from '../cache/builders/build-decorators'; import { PaginatedList } from '../data/paginated-list'; @@ -105,9 +104,9 @@ export class Item extends DSpaceObject implements ChildHALResource { * Method that returns as which type of object this object should be rendered */ getRenderTypes(): (string | GenericConstructor)[] { - let entityType = this.firstMetadataValue('relationship.type'); + const entityType = this.firstMetadataValue('relationship.type'); if (isEmpty(entityType)) { - entityType = DEFAULT_ENTITY_TYPE; + return super.getRenderTypes(); } return [entityType, ...super.getRenderTypes()]; } diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index 166f10dd57..01d7a8c193 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -76,6 +76,10 @@ export const getSucceededRemoteWithNotEmptyData = () => (source: Observable>): Observable> => source.pipe(find((rd: RemoteData) => rd.hasSucceeded && isNotEmpty(rd.payload))); +export const getSucceededRemoteWithNotEmptyDataOrFailed = () => + (source: Observable>): Observable> => + source.pipe(find((rd: RemoteData) => (rd.hasSucceeded && isNotEmpty(rd.payload)) || rd.hasFailed)); + export const getSucceededOrNoContentResponse = () => (source: Observable>): Observable> => source.pipe(find((rd: RemoteData) => rd.hasSucceeded || rd.hasNoContent)); diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html index 1ae772a3c3..2ac997bf4d 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html @@ -17,7 +17,7 @@
- +

diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.spec.ts index f65fd97cb0..315df8bdc4 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.spec.ts @@ -3,8 +3,8 @@ import { Item } from '../../../../../core/shared/item.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.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'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html index 75d29781b7..09ca2cb755 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html @@ -17,7 +17,7 @@
- +

diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.spec.ts index a7d5acdd00..b28561451c 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.spec.ts @@ -3,8 +3,8 @@ import { Item } from '../../../../../core/shared/item.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.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'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html index 8c7e5c2f44..584ff37a87 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html @@ -17,7 +17,7 @@
- +

diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.spec.ts index 180b7f4600..9ced5a9e71 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.spec.ts @@ -3,8 +3,8 @@ import { Item } from '../../../../../core/shared/item.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.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'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html index 45482972ec..3ddf3611d1 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html @@ -1,4 +1,4 @@ - + + +
- +

diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.spec.ts index 8dec83295e..5580b98b1e 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.spec.ts @@ -4,7 +4,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote- import { PaginatedList } from '../../../../../core/data/paginated-list'; import { PageInfo } from '../../../../../core/shared/page-info.model'; import { OrgUnitSearchResultGridElementComponent } from './org-unit-search-result-grid-element.component'; -import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html index 1b45c7c4f9..c8470b5725 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html @@ -17,7 +17,7 @@
- +

diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.spec.ts index f56d6c76af..d31d5b092c 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.spec.ts @@ -3,8 +3,8 @@ import { Item } from '../../../../../core/shared/item.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.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 { PersonSearchResultGridElementComponent } from './person-search-result-grid-element.component'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html index ac3c3ea453..95fc98e06f 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html @@ -17,7 +17,7 @@
- +

diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.spec.ts index 5a25eea955..4cc93ea0bb 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.spec.ts @@ -4,7 +4,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote- import { PaginatedList } from '../../../../../core/data/paginated-list'; import { PageInfo } from '../../../../../core/shared/page-info.model'; import { ProjectSearchResultGridElementComponent } from './project-search-result-grid-element.component'; -import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html index 5f570cb021..c0d98ccf43 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html @@ -1,4 +1,4 @@ - +
+ - + diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.spec.ts b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.spec.ts index 12e89ec940..0cf5857aec 100644 --- a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.spec.ts +++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.spec.ts @@ -6,7 +6,7 @@ import { GenericConstructor } from '../../../../core/shared/generic-constructor' import { Context } from '../../../../core/shared/context.model'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import * as listableObjectDecorators from './listable-object.decorator'; -import { PublicationListElementComponent } from '../../../object-list/item-list-element/item-types/publication/publication-list-element.component'; +import { ItemListElementComponent } from '../../../object-list/item-list-element/item-types/item/item-list-element.component'; import { ListableObjectDirective } from './listable-object.directive'; import { spyOnExported } from '../../../testing/utils.test'; @@ -27,13 +27,13 @@ xdescribe('ListableObjectComponentLoaderComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [], - declarations: [ListableObjectComponentLoaderComponent, PublicationListElementComponent, ListableObjectDirective], + declarations: [ListableObjectComponentLoaderComponent, ItemListElementComponent, ListableObjectDirective], schemas: [NO_ERRORS_SCHEMA], providers: [ComponentFactoryResolver] }).overrideComponent(ListableObjectComponentLoaderComponent, { set: { changeDetection: ChangeDetectionStrategy.Default, - entryComponents: [PublicationListElementComponent] + entryComponents: [ItemListElementComponent] } }).compileComponents(); })); @@ -45,7 +45,7 @@ xdescribe('ListableObjectComponentLoaderComponent', () => { comp.object = new TestType(); comp.viewMode = testViewMode; comp.context = testContext; - spyOnExported(listableObjectDecorators, 'getListableObjectComponent').and.returnValue(PublicationListElementComponent); + spyOnExported(listableObjectDecorators, 'getListableObjectComponent').and.returnValue(ItemListElementComponent); fixture.detectChanges(); })); diff --git a/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.html b/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.html new file mode 100644 index 0000000000..434c4b5b5c --- /dev/null +++ b/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.html @@ -0,0 +1,4 @@ + + + + diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.scss b/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.scss similarity index 100% rename from src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.scss rename to src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.scss diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec.ts b/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.spec.ts similarity index 84% rename from src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec.ts rename to src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.spec.ts index 4ff1162fb5..4e774a47ae 100644 --- a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.spec.ts @@ -4,7 +4,7 @@ import { TruncatePipe } from '../../../../utils/truncate.pipe'; import { TruncatableService } from '../../../../truncatable/truncatable.service'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; -import { PublicationGridElementComponent } from './publication-grid-element.component'; +import { ItemGridElementComponent } from './item-grid-element.component'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../../core/shared/item.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils'; @@ -41,7 +41,7 @@ const mockItem = Object.assign(new Item(), { } }); -describe('PublicationGridElementComponent', () => { +describe('ItemGridElementComponent', () => { let comp; let fixture; @@ -52,18 +52,18 @@ describe('PublicationGridElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [PublicationGridElementComponent, TruncatePipe], + declarations: [ItemGridElementComponent, TruncatePipe], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(PublicationGridElementComponent, { + }).overrideComponent(ItemGridElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(PublicationGridElementComponent); + fixture = TestBed.createComponent(ItemGridElementComponent); comp = fixture.componentInstance; })); @@ -74,7 +74,7 @@ describe('PublicationGridElementComponent', () => { }); it(`should contain a PublicationGridElementComponent`, () => { - const publicationGridElement = fixture.debugElement.query(By.css(`ds-publication-search-result-grid-element`)); + const publicationGridElement = fixture.debugElement.query(By.css(`ds-item-search-result-grid-element`)); expect(publicationGridElement).not.toBeNull(); }); }); diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.ts b/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.ts similarity index 74% rename from src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.ts rename to src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.ts index 8450150dcb..c8a58c5a89 100644 --- a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.ts +++ b/src/app/shared/object-grid/item-grid-element/item-types/item/item-grid-element.component.ts @@ -8,13 +8,13 @@ import { Item } from '../../../../../core/shared/item.model'; @listableObjectComponent('Publication', ViewMode.GridElement) @listableObjectComponent(Item, ViewMode.GridElement) @Component({ - selector: 'ds-publication-grid-element', - styleUrls: ['./publication-grid-element.component.scss'], - templateUrl: './publication-grid-element.component.html', + selector: 'ds-item-grid-element', + styleUrls: ['./item-grid-element.component.scss'], + templateUrl: './item-grid-element.component.html', animations: [focusShadow] }) /** * The component for displaying a grid element for an item of the type Publication */ -export class PublicationGridElementComponent extends AbstractListableElementComponent { +export class ItemGridElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.html b/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.html deleted file mode 100644 index e35deda539..0000000000 --- a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html index 09d7a190d9..f8c75fc0d4 100644 --- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html @@ -8,6 +8,7 @@
+

{{dso.name}}

{{dso.shortDescription}}

diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html index 3d4b95739f..8025213b3b 100644 --- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html @@ -8,6 +8,7 @@
+

{{dso.name}}

{{dso.shortDescription}}

diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html similarity index 96% rename from src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html rename to src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html index 125553054e..6bd69e8667 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html @@ -15,7 +15,7 @@
- +

diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.scss similarity index 100% rename from src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.scss rename to src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.scss diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts similarity index 95% rename from src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts rename to src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts index dd79b81427..32c2c3bed8 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts @@ -23,7 +23,7 @@ import { ItemSearchResult } from '../../../../object-collection/shared/item-sear import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils'; import { TruncatableService } from '../../../../truncatable/truncatable.service'; import { TruncatePipe } from '../../../../utils/truncate.pipe'; -import { PublicationSearchResultGridElementComponent } from './publication-search-result-grid-element.component'; +import { ItemSearchResultGridElementComponent } from './item-search-result-grid-element.component'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; @@ -71,7 +71,7 @@ mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { } }); -describe('PublicationGridElementComponent', getEntityGridElementTestComponent(PublicationSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['authors', 'date', 'abstract'])); +describe('ItemGridElementComponent', getEntityGridElementTestComponent(ItemSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['authors', 'date', 'abstract'])); /** * Create test cases for a grid component of an entity. diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts similarity index 71% rename from src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.ts rename to src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts index c96e73d365..e729756452 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts @@ -9,13 +9,13 @@ import { ItemSearchResult } from '../../../../object-collection/shared/item-sear @listableObjectComponent('PublicationSearchResult', ViewMode.GridElement) @listableObjectComponent(ItemSearchResult, ViewMode.GridElement) @Component({ - selector: 'ds-publication-search-result-grid-element', - styleUrls: ['./publication-search-result-grid-element.component.scss'], - templateUrl: './publication-search-result-grid-element.component.html', + selector: 'ds-item-search-result-grid-element', + styleUrls: ['./item-search-result-grid-element.component.scss'], + templateUrl: './item-search-result-grid-element.component.html', animations: [focusShadow] }) /** * The component for displaying a grid element for an item search result of the type Publication */ -export class PublicationSearchResultGridElementComponent extends SearchResultGridElementComponent { +export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent { } diff --git a/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.html b/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.html new file mode 100644 index 0000000000..3877e2f335 --- /dev/null +++ b/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.html @@ -0,0 +1 @@ + diff --git a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.scss b/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.scss similarity index 100% rename from src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.scss rename to src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.scss diff --git a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.spec.ts b/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.spec.ts similarity index 83% rename from src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.spec.ts rename to src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.spec.ts index 85b964c083..6897b81f0a 100644 --- a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.spec.ts +++ b/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.spec.ts @@ -1,7 +1,7 @@ import { async, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; -import { PublicationListElementComponent } from './publication-list-element.component'; +import { ItemListElementComponent } from './item-list-element.component'; import { Item } from '../../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../utils/truncate.pipe'; import { TruncatableService } from '../../../../truncatable/truncatable.service'; @@ -43,7 +43,7 @@ const mockItem: Item = Object.assign(new Item(), { } }); -describe('PublicationListElementComponent', () => { +describe('ItemListElementComponent', () => { let comp; let fixture; @@ -53,18 +53,18 @@ describe('PublicationListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [PublicationListElementComponent, TruncatePipe], + declarations: [ItemListElementComponent, TruncatePipe], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(PublicationListElementComponent, { + }).overrideComponent(ItemListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(PublicationListElementComponent); + fixture = TestBed.createComponent(ItemListElementComponent); comp = fixture.componentInstance; })); @@ -75,7 +75,7 @@ describe('PublicationListElementComponent', () => { }); it(`should contain a PublicationListElementComponent`, () => { - const publicationListElement = fixture.debugElement.query(By.css(`ds-publication-search-result-list-element`)); + const publicationListElement = fixture.debugElement.query(By.css(`ds-item-search-result-list-element`)); expect(publicationListElement).not.toBeNull(); }); }); diff --git a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.ts b/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.ts similarity index 72% rename from src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.ts rename to src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.ts index 59d0249aef..a3bd2a1ce0 100644 --- a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.ts +++ b/src/app/shared/object-list/item-list-element/item-types/item/item-list-element.component.ts @@ -7,12 +7,12 @@ import { Item } from '../../../../../core/shared/item.model'; @listableObjectComponent('Publication', ViewMode.ListElement) @listableObjectComponent(Item, ViewMode.ListElement) @Component({ - selector: 'ds-publication-list-element', - styleUrls: ['./publication-list-element.component.scss'], - templateUrl: './publication-list-element.component.html' + selector: 'ds-item-list-element', + styleUrls: ['./item-list-element.component.scss'], + templateUrl: './item-list-element.component.html' }) /** * The component for displaying a list element for an item of the type Publication */ -export class PublicationListElementComponent extends AbstractListableElementComponent { +export class ItemListElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.html b/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.html deleted file mode 100644 index dcebcfd56a..0000000000 --- a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-list/item-type-badge/item-type-badge.component.html b/src/app/shared/object-list/item-type-badge/item-type-badge.component.html deleted file mode 100644 index 947970b7e1..0000000000 --- a/src/app/shared/object-list/item-type-badge/item-type-badge.component.html +++ /dev/null @@ -1,3 +0,0 @@ -
- {{ type.toLowerCase() + '.listelement.badge' | translate }} -
diff --git a/src/app/shared/object-list/item-type-badge/item-type-badge.component.ts b/src/app/shared/object-list/item-type-badge/item-type-badge.component.ts deleted file mode 100644 index 88fe2d7f54..0000000000 --- a/src/app/shared/object-list/item-type-badge/item-type-badge.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; - -@Component({ - selector: 'ds-item-type-badge', - templateUrl: './item-type-badge.component.html' -}) -/** - * Component rendering the type of an item as a badge - */ -export class ItemTypeBadgeComponent { - /** - * The component used to retrieve the type from - */ - @Input() object: DSpaceObject; -} diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html index c2ca8acb2f..c518d39bd9 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html @@ -2,7 +2,7 @@ - +

diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts index 7d43a99e91..9aec785f08 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts @@ -155,7 +155,7 @@ describe('ItemListPreviewComponent', () => { }); it('should show the entity type span', () => { - const entityField = fixture.debugElement.query(By.css('ds-item-type-badge')); + const entityField = fixture.debugElement.query(By.css('ds-type-badge')); expect(entityField).not.toBeNull(); }); }); diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html index 3c787c47ce..1c081e2805 100644 --- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html @@ -1,3 +1,4 @@ +
diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html index 32834fefee..08b02d123a 100644 --- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html @@ -1,3 +1,4 @@ +
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html similarity index 95% rename from src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.html rename to src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html index 1bc723200a..880f4393cd 100644 --- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.html +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html @@ -1,4 +1,4 @@ - + ; +let publicationListElementComponent: ItemSearchResultListElementComponent; +let fixture: ComponentFixture; const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), { indexableObject: @@ -64,22 +64,22 @@ const mockItemWithoutMetadata: ItemSearchResult = Object.assign(new ItemSearchRe }) }); -describe('PublicationListElementComponent', () => { +describe('ItemListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [PublicationSearchResultListElementComponent, TruncatePipe], + declarations: [ItemSearchResultListElementComponent, TruncatePipe], providers: [ { provide: TruncatableService, useValue: {} } ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(PublicationSearchResultListElementComponent, { + }).overrideComponent(ItemSearchResultListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(PublicationSearchResultListElementComponent); + fixture = TestBed.createComponent(ItemSearchResultListElementComponent); publicationListElementComponent = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.ts similarity index 70% rename from src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.ts rename to src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.ts index 3e0db60b4c..b4b658cb96 100644 --- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.ts @@ -8,12 +8,12 @@ import { Item } from '../../../../../../core/shared/item.model'; @listableObjectComponent('PublicationSearchResult', ViewMode.ListElement) @listableObjectComponent(ItemSearchResult, ViewMode.ListElement) @Component({ - selector: 'ds-publication-search-result-list-element', - styleUrls: ['./publication-search-result-list-element.component.scss'], - templateUrl: './publication-search-result-list-element.component.html' + selector: 'ds-item-search-result-list-element', + styleUrls: ['./item-search-result-list-element.component.scss'], + templateUrl: './item-search-result-list-element.component.html' }) /** * The component for displaying a list element for an item search result of the type Publication */ -export class PublicationSearchResultListElementComponent extends SearchResultListElementComponent { +export class ItemSearchResultListElementComponent extends SearchResultListElementComponent { } diff --git a/src/app/shared/object-list/type-badge/type-badge.component.html b/src/app/shared/object-list/type-badge/type-badge.component.html new file mode 100644 index 0000000000..18aeeb4bca --- /dev/null +++ b/src/app/shared/object-list/type-badge/type-badge.component.html @@ -0,0 +1,3 @@ +
+ {{ typeMessage | translate }} +
diff --git a/src/app/shared/object-list/item-type-badge/item-type-badge.component.spec.ts b/src/app/shared/object-list/type-badge/type-badge.component.spec.ts similarity index 82% rename from src/app/shared/object-list/item-type-badge/item-type-badge.component.spec.ts rename to src/app/shared/object-list/type-badge/type-badge.component.spec.ts index 1dad7afd7e..e516fe353e 100644 --- a/src/app/shared/object-list/item-type-badge/item-type-badge.component.spec.ts +++ b/src/app/shared/object-list/type-badge/type-badge.component.spec.ts @@ -4,11 +4,11 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { TruncatePipe } from '../../utils/truncate.pipe'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ItemTypeBadgeComponent } from './item-type-badge.component'; import { By } from '@angular/platform-browser'; +import { TypeBadgeComponent } from './type-badge.component'; -let comp: ItemTypeBadgeComponent; -let fixture: ComponentFixture; +let comp: TypeBadgeComponent; +let fixture: ComponentFixture; const type = 'authorOfPublication'; @@ -40,15 +40,15 @@ describe('ItemTypeBadgeComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot()], - declarations: [ItemTypeBadgeComponent, TruncatePipe], + declarations: [TypeBadgeComponent, TruncatePipe], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ItemTypeBadgeComponent, { + }).overrideComponent(TypeBadgeComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(ItemTypeBadgeComponent); + fixture = TestBed.createComponent(TypeBadgeComponent); comp = fixture.componentInstance; })); @@ -70,9 +70,9 @@ describe('ItemTypeBadgeComponent', () => { fixture.detectChanges(); }); - it('should not show a badge', () => { + it('should show an item badge', () => { const badge = fixture.debugElement.query(By.css('span.badge')); - expect(badge).toBeNull(); + expect(badge.nativeElement.textContent).toContain('item'); }); }); }); diff --git a/src/app/shared/object-list/type-badge/type-badge.component.ts b/src/app/shared/object-list/type-badge/type-badge.component.ts new file mode 100644 index 0000000000..8e843af1e7 --- /dev/null +++ b/src/app/shared/object-list/type-badge/type-badge.component.ts @@ -0,0 +1,47 @@ +import { Component, Input } from '@angular/core'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { hasValue, isEmpty } from '../../empty.util'; +import { getResourceTypeValueFor } from '../../../core/cache/object-cache.reducer'; + +@Component({ + selector: 'ds-type-badge', + templateUrl: './type-badge.component.html' +}) +/** + * Component rendering the type of an item as a badge + */ +export class TypeBadgeComponent { + + private _object: DSpaceObject; + private _typeMessage: string; + + /** + * The component used to retrieve the type from + */ + @Input() set object(object: DSpaceObject) { + this._object = object; + + const renderTypes = this._object.getRenderTypes(); + if (!isEmpty(renderTypes.length)) { + const renderType = renderTypes[0]; + if (renderType instanceof Function) { + const resourceTypeValue = getResourceTypeValueFor(object.type); + if (hasValue(resourceTypeValue)) { + this._typeMessage = `${resourceTypeValue.toLowerCase()}.listelement.badge`; + } else { + this._typeMessage = `${renderType.name.toLowerCase()}.listelement.badge`; + } + } else { + this._typeMessage = `${renderType.toLowerCase()}.listelement.badge`; + } + } + } + + get object(): DSpaceObject { + return this._object; + } + + get typeMessage(): string { + return this._typeMessage; + } +} diff --git a/src/app/shared/resource-policies/create/resource-policy-create.component.spec.ts b/src/app/shared/resource-policies/create/resource-policy-create.component.spec.ts index 1c41280bab..d7453fcf0e 100644 --- a/src/app/shared/resource-policies/create/resource-policy-create.component.spec.ts +++ b/src/app/shared/resource-policies/create/resource-policy-create.component.spec.ts @@ -152,29 +152,33 @@ describe('ResourcePolicyCreateComponent test suite', () => { fixture.destroy(); }); - it('should init component properly', () => { + it('should init component properly', (done) => { fixture.detectChanges(); expect(compAsAny.targetResourceUUID).toBe('itemUUID'); expect(compAsAny.targetResourceName).toBe('test item'); + done(); }); - it('should redirect to authorizations page', () => { + it('should redirect to authorizations page', (done) => { comp.redirectToAuthorizationsPage(); expect(compAsAny.router.navigate).toHaveBeenCalled(); + done(); }); - it('should return true when is Processing', () => { + it('should return true when is Processing', (done) => { compAsAny.processing$.next(true); expect(comp.isProcessing()).toBeObservable(cold('a', { a: true })); + done(); }); - it('should return false when is not Processing', () => { + it('should return false when is not Processing', (done) => { compAsAny.processing$.next(false); expect(comp.isProcessing()).toBeObservable(cold('a', { a: false })); + done(); }); describe('when target type is group', () => { diff --git a/src/app/shared/resource-policies/create/resource-policy-create.component.ts b/src/app/shared/resource-policies/create/resource-policy-create.component.ts index 30bf0c9e56..104a5e592c 100644 --- a/src/app/shared/resource-policies/create/resource-policy-create.component.ts +++ b/src/app/shared/resource-policies/create/resource-policy-create.component.ts @@ -101,7 +101,9 @@ export class ResourcePolicyCreateComponent implements OnInit { first((response: RemoteData) => !response.isResponsePending) ).subscribe((responseRD: RemoteData) => { this.processing$.next(false); - if (responseRD.hasSucceeded) { + // NOTE Currently due to a bug a successful 201 response has failed + // TODO review it when https://github.com/DSpace/dspace-angular/issues/739 is fixed + if (responseRD.hasSucceeded || responseRD.statusCode === 201) { this.notificationsService.success(null, this.translate.get('resource-policies.create.page.success.content')); this.redirectToAuthorizationsPage(); } else { diff --git a/src/app/shared/resource-policies/edit/resource-policy-edit.component.spec.ts b/src/app/shared/resource-policies/edit/resource-policy-edit.component.spec.ts index b124da0219..366f705fd6 100644 --- a/src/app/shared/resource-policies/edit/resource-policy-edit.component.spec.ts +++ b/src/app/shared/resource-policies/edit/resource-policy-edit.component.spec.ts @@ -137,28 +137,32 @@ describe('ResourcePolicyEditComponent test suite', () => { fixture.destroy(); }); - it('should init component properly', () => { + it('should init component properly', (done) => { fixture.detectChanges(); expect(compAsAny.resourcePolicy).toEqual(resourcePolicy); + done(); }); - it('should redirect to authorizations page', () => { + it('should redirect to authorizations page', (done) => { comp.redirectToAuthorizationsPage(); expect(compAsAny.router.navigate).toHaveBeenCalled(); + done(); }); - it('should return true when is Processing', () => { + it('should return true when is Processing', (done) => { compAsAny.processing$.next(true); expect(comp.isProcessing()).toBeObservable(cold('a', { a: true })); + done(); }); - it('should return false when is not Processing', () => { + it('should return false when is not Processing', (done) => { compAsAny.processing$.next(false); expect(comp.isProcessing()).toBeObservable(cold('a', { a: false })); + done(); }); describe('', () => { diff --git a/src/app/shared/resource-policies/edit/resource-policy-edit.component.ts b/src/app/shared/resource-policies/edit/resource-policy-edit.component.ts index b6d13a9b1f..a2dd957bb7 100644 --- a/src/app/shared/resource-policies/edit/resource-policy-edit.component.ts +++ b/src/app/shared/resource-policies/edit/resource-policy-edit.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { BehaviorSubject, Observable } from 'rxjs'; -import { first, map, take } from 'rxjs/operators'; +import { map, take } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { ResourcePolicyService } from '../../../core/resource-policy/resource-policy.service'; @@ -12,6 +12,7 @@ import { ResourcePolicy } from '../../../core/resource-policy/models/resource-po import { ResourcePolicyEvent } from '../form/resource-policy-form.component'; import { RESOURCE_POLICY } from '../../../core/resource-policy/models/resource-policy.resource-type'; import { ITEM_EDIT_AUTHORIZATIONS_PATH } from '../../../+item-page/edit-item-page/edit-item-page.routing-paths'; +import { getSucceededRemoteWithNotEmptyDataOrFailed } from '../../../core/shared/operators'; @Component({ selector: 'ds-resource-policy-edit', @@ -88,10 +89,11 @@ export class ResourcePolicyEditComponent implements OnInit { _links: this.resourcePolicy._links }); this.resourcePolicyService.update(updatedObject).pipe( - first((response: RemoteData) => !response.isResponsePending) + getSucceededRemoteWithNotEmptyDataOrFailed(), + take(1) ).subscribe((responseRD: RemoteData) => { this.processing$.next(false); - if (responseRD.hasSucceeded) { + if (responseRD && responseRD.hasSucceeded) { this.notificationsService.success(null, this.translate.get('resource-policies.edit.page.success.content')); this.redirectToAuthorizationsPage(); } else { diff --git a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts index 9671b41ec4..7a20fd5ff0 100644 --- a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts @@ -1,9 +1,7 @@ import { Component, OnInit } from '@angular/core'; - import { FilterType } from '../../../filter-type.model'; import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; import { renderFacetFor } from '../search-filter-type-decorator'; -import { FacetValue } from '../../../facet-value.model'; @Component({ selector: 'ds-search-authority-filter', @@ -17,20 +15,4 @@ import { FacetValue } from '../../../facet-value.model'; */ @renderFacetFor(FilterType.authority) export class SearchAuthorityFilterComponent extends SearchFacetFilterComponent implements OnInit { - - /** - * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved - * Retrieve facet value from search link - */ - protected getFacetValue(facet: FacetValue): string { - const search = facet._links.search.href; - const hashes = search.slice(search.indexOf('?') + 1).split('&'); - const params = {}; - hashes.map((hash) => { - const [key, val] = hash.split('='); - params[key] = decodeURIComponent(val); - }); - - return params[this.filterConfig.paramName]; - } } diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts index 4f85411d85..ba6eceeede 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts @@ -130,7 +130,7 @@ describe('SearchFacetOptionComponent', () => { comp.addQueryParams = {}; (comp as any).updateAddParams(selectedValues); expect(comp.addQueryParams).toEqual({ - [mockFilterConfig.paramName]: [value1, value.value], + [mockFilterConfig.paramName]: [`${value1},${operator}`, value.value + ',equals'], page: 1 }); }); @@ -145,7 +145,7 @@ describe('SearchFacetOptionComponent', () => { comp.addQueryParams = {}; (comp as any).updateAddParams(selectedValues); expect(comp.addQueryParams).toEqual({ - [mockAuthorityFilterConfig.paramName]: [value1, `${value2},${operator}`], + [mockAuthorityFilterConfig.paramName]: [value1 + ',equals', `${value2},${operator}`], page: 1 }); }); diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts index ca4ab10fc3..c6d7f4ac7c 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts @@ -8,8 +8,8 @@ import { SearchService } from '../../../../../../core/shared/search/search.servi import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; import { hasValue } from '../../../../../empty.util'; -import { FilterType } from '../../../../filter-type.model'; import { currentPath } from '../../../../../utils/route.utils'; +import { getFacetValueForType } from '../../../../search.utils'; @Component({ selector: 'ds-search-facet-option', @@ -102,7 +102,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { */ private updateAddParams(selectedValues: FacetValue[]): void { this.addQueryParams = { - [this.filterConfig.paramName]: [...selectedValues.map((facetValue: FacetValue) => facetValue.label), this.getFacetValue()], + [this.filterConfig.paramName]: [...selectedValues.map((facetValue: FacetValue) => getFacetValueForType(facetValue, this.filterConfig)), this.getFacetValue()], page: 1 }; } @@ -112,19 +112,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { * Retrieve facet value related to facet type */ private getFacetValue(): string { - if (this.filterConfig.type === FilterType.authority) { - const search = this.filterValue._links.search.href; - const hashes = search.slice(search.indexOf('?') + 1).split('&'); - const params = {}; - hashes.map((hash) => { - const [key, val] = hash.split('='); - params[key] = decodeURIComponent(val); - }); - - return params[this.filterConfig.paramName]; - } else { - return this.filterValue.value; - } + return getFacetValueForType(this.filterValue, this.filterConfig); } /** diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html index a27a5d3d86..4bcfc02966 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html @@ -3,6 +3,6 @@ [queryParams]="removeQueryParams" queryParamsHandling="merge"> - {{ 'search.filters.' + filterConfig.name + '.' + selectedValue.value | translate: {default: selectedValue.value} }} + {{ 'search.filters.' + filterConfig.name + '.' + selectedValue.value | translate: {default: selectedValue.label} }}
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts index b085ef7bf5..159effe751 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts @@ -7,8 +7,8 @@ import { SearchFilterService } from '../../../../../../core/shared/search/search import { hasValue } from '../../../../../empty.util'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; import { FacetValue } from '../../../../facet-value.model'; -import { FilterType } from '../../../../filter-type.model'; import { currentPath } from '../../../../../utils/route.utils'; +import { getFacetValueForType } from '../../../../search.utils'; @Component({ selector: 'ds-search-facet-selected-option', @@ -101,19 +101,7 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy { * Retrieve facet value related to facet type */ private getFacetValue(facetValue: FacetValue): string { - if (this.filterConfig.type === FilterType.authority) { - const search = facetValue._links.search.href; - const hashes = search.slice(search.indexOf('?') + 1).split('&'); - const params = {}; - hashes.map((hash) => { - const [key, val] = hash.split('='); - params[key] = decodeURIComponent(val); - }); - - return params[this.filterConfig.paramName]; - } else { - return facetValue.value; - } + return getFacetValueForType(facetValue, this.filterConfig); } /** diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index 9e35f346ce..385f2e9492 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -208,7 +208,7 @@ describe('SearchFacetFilterComponent', () => { it('should call navigate on the router with the right searchlink and parameters', () => { expect(router.navigate).toHaveBeenCalledWith(searchUrl.split('/'), { - queryParams: { [mockFilterConfig.paramName]: [...selectedValues, testValue] }, + queryParams: { [mockFilterConfig.paramName]: [...selectedValues.map((value) => `${value},equals`), testValue] }, queryParamsHandling: 'merge' }); }); diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index a3d899fbf9..1f38e700a2 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -25,6 +25,7 @@ import { InputSuggestion } from '../../../../input-suggestions/input-suggestions import { SearchOptions } from '../../../search-options.model'; import { SEARCH_CONFIG_SERVICE } from '../../../../../+my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../../../utils/route.utils'; +import { getFacetValueForType, stripOperatorFromFilterValue } from '../../../search.utils'; @Component({ selector: 'ds-search-facet-filter', @@ -148,7 +149,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { if (hasValue(fValue)) { return fValue; } - return Object.assign(new FacetValue(), { label: value, value: value }); + return Object.assign(new FacetValue(), { label: stripOperatorFromFilterValue(value), value: value }); }); }) ); @@ -287,9 +288,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { return rd.payload.page.map((facet) => { return { displayValue: this.getDisplayValue(facet, data), - value: this.getFacetValue(facet) - }; - }); + value: stripOperatorFromFilterValue(this.getFacetValue(facet)) } )); } @@ -303,7 +302,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { * Retrieve facet value */ protected getFacetValue(facet: FacetValue): string { - return facet.value; + return getFacetValueForType(facet, this.filterConfig); } /** diff --git a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts index 678cbbfdd5..b2b44ce219 100644 --- a/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-text-filter/search-text-filter.component.ts @@ -5,6 +5,9 @@ import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; import { renderFacetFor } from '../search-filter-type-decorator'; +import { + addOperatorToFilterValue, +} from '../../../search.utils'; /** * This component renders a simple item page. @@ -24,4 +27,12 @@ import { renderFacetFor } from '../search-filter-type-decorator'; */ @renderFacetFor(FilterType.text) export class SearchTextFilterComponent extends SearchFacetFilterComponent implements OnInit { + /** + * Submits a new active custom value to the filter from the input field + * Overwritten method from parent component, adds the "query" operator to the received data before passing it on + * @param data The string from the input field + */ + onSubmit(data: any) { + super.onSubmit(addOperatorToFilterValue(data, 'query')); + } } diff --git a/src/app/shared/search/search-labels/search-labels.component.ts b/src/app/shared/search/search-labels/search-labels.component.ts index 154b888269..2322c80acf 100644 --- a/src/app/shared/search/search-labels/search-labels.component.ts +++ b/src/app/shared/search/search-labels/search-labels.component.ts @@ -3,6 +3,8 @@ import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.c import { Observable } from 'rxjs'; import { Params, Router } from '@angular/router'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; +import { map } from 'rxjs/operators'; +import { stripOperatorFromFilterValue } from '../search.utils'; @Component({ selector: 'ds-search-labels', @@ -30,6 +32,15 @@ export class SearchLabelsComponent { constructor( protected router: Router, @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) { - this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters(); + this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters().pipe( + map((params) => { + const labels = {}; + Object.keys(params) + .forEach((key) => { + labels[key] = [...params[key].map((value) => stripOperatorFromFilterValue(value))]; + }); + return labels; + }) + ); } } diff --git a/src/app/shared/search/search.utils.spec.ts b/src/app/shared/search/search.utils.spec.ts new file mode 100644 index 0000000000..a14085c2d3 --- /dev/null +++ b/src/app/shared/search/search.utils.spec.ts @@ -0,0 +1,52 @@ +import { FacetValue } from './facet-value.model'; +import { SearchFilterConfig } from './search-filter-config.model'; +import { addOperatorToFilterValue, getFacetValueForType, stripOperatorFromFilterValue } from './search.utils'; + +describe('Search Utils', () => { + describe('getFacetValueForType', () => { + let facetValueWithSearchHref: FacetValue; + let facetValueWithoutSearchHref: FacetValue; + let searchFilterConfig: SearchFilterConfig; + + beforeEach(() => { + facetValueWithSearchHref = Object.assign(new FacetValue(), { + value: 'Value with search href', + _links: { + search: { + href: 'rest/api/search?f.otherFacet=Other facet value,operator&f.facetName=Value with search href,operator' + } + } + }); + facetValueWithoutSearchHref = Object.assign(new FacetValue(), { + value: 'Value without search href' + }); + searchFilterConfig = Object.assign(new SearchFilterConfig(), { + name: 'facetName' + }); + }); + + it('should retrieve the correct value from the search href', () => { + expect(getFacetValueForType(facetValueWithSearchHref, searchFilterConfig)).toEqual('Value with search href,operator'); + }); + + it('should return the facet value with an equals operator by default', () => { + expect(getFacetValueForType(facetValueWithoutSearchHref, searchFilterConfig)).toEqual('Value without search href,equals'); + }); + }); + + describe('stripOperatorFromFilterValue', () => { + it('should strip the operator from the value', () => { + expect(stripOperatorFromFilterValue('value,operator')).toEqual('value'); + }); + }); + + describe('addOperatorToFilterValue', () => { + it('should add the operator to the value', () => { + expect(addOperatorToFilterValue('value', 'operator')).toEqual('value,operator'); + }); + + it('shouldn\'t add the operator to the value if it already contains the operator', () => { + expect(addOperatorToFilterValue('value,operator', 'operator')).toEqual('value,operator'); + }); + }); +}); diff --git a/src/app/shared/search/search.utils.ts b/src/app/shared/search/search.utils.ts new file mode 100644 index 0000000000..05a9711435 --- /dev/null +++ b/src/app/shared/search/search.utils.ts @@ -0,0 +1,44 @@ +import { FacetValue } from './facet-value.model'; +import { SearchFilterConfig } from './search-filter-config.model'; +import { isNotEmpty } from '../empty.util'; + +/** + * Get a facet's value by matching its parameter in the search href, this will include the operator of the facet value + * If the {@link FacetValue} doesn't contain a search link, its raw value will be returned as a fallback + * @param facetValue + * @param searchFilterConfig + */ +export function getFacetValueForType(facetValue: FacetValue, searchFilterConfig: SearchFilterConfig): string { + const regex = new RegExp(`[?|&]${searchFilterConfig.paramName}=(${facetValue.value}[^&]*)`, 'g'); + if (isNotEmpty(facetValue._links)) { + const values = regex.exec(facetValue._links.search.href); + if (isNotEmpty(values)) { + return values[1]; + } + } + return addOperatorToFilterValue(facetValue.value, 'equals'); +} + +/** + * Strip the operator from a filter value + * Warning: This expects the value to end with an operator, otherwise it might strip unwanted content + * @param value + */ +export function stripOperatorFromFilterValue(value: string) { + if (value.lastIndexOf(',') > -1) { + return value.substring(0, value.lastIndexOf(',')); + } + return value; +} + +/** + * Add an operator to a string + * @param value + * @param operator + */ +export function addOperatorToFilterValue(value: string, operator: string) { + if (!value.endsWith(`,${operator}`)) { + return `${value},${operator}`; + } + return value; +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 35a9260dae..78a6f476cd 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -20,7 +20,7 @@ import { ComcolRoleComponent } from './comcol-forms/edit-comcol-page/comcol-role import { ConfirmationModalComponent } from './confirmation-modal/confirmation-modal.component'; import { ExportMetadataSelectorComponent } from './dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component'; import { FileDropzoneNoUploaderComponent } from './file-dropzone-no-uploader/file-dropzone-no-uploader.component'; -import { PublicationListElementComponent } from './object-list/item-list-element/item-types/publication/publication-list-element.component'; +import { ItemListElementComponent } from './object-list/item-list-element/item-types/item/item-list-element.component'; import { EnumKeysPipe } from './utils/enum-keys-pipe'; import { FileSizePipe } from './utils/file-size-pipe'; import { MetadataFieldValidator } from './utils/metadatafield-validator.directive'; @@ -158,13 +158,12 @@ import { ItemSelectComponent } from './object-select/item-select/item-select.com import { CollectionSelectComponent } from './object-select/collection-select/collection-select.component'; import { FilterInputSuggestionsComponent } from './input-suggestions/filter-suggestions/filter-input-suggestions.component'; import { DsoInputSuggestionsComponent } from './input-suggestions/dso-input-suggestions/dso-input-suggestions.component'; -import { PublicationGridElementComponent } from './object-grid/item-grid-element/item-types/publication/publication-grid-element.component'; -import { ItemTypeBadgeComponent } from './object-list/item-type-badge/item-type-badge.component'; +import { ItemGridElementComponent } from './object-grid/item-grid-element/item-types/item/item-grid-element.component'; +import { TypeBadgeComponent } from './object-list/type-badge/type-badge.component'; import { MetadataRepresentationLoaderComponent } from './metadata-representation/metadata-representation-loader.component'; import { MetadataRepresentationDirective } from './metadata-representation/metadata-representation.directive'; import { ListableObjectComponentLoaderComponent } from './object-collection/shared/listable-object/listable-object-component-loader.component'; -import { PublicationSearchResultListElementComponent } from './object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component'; -import { PublicationSearchResultGridElementComponent } from './object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component'; +import { ItemSearchResultListElementComponent } from './object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { ListableObjectDirective } from './object-collection/shared/listable-object/listable-object.directive'; import { SearchLabelComponent } from './search/search-labels/search-label/search-label.component'; import { ItemMetadataRepresentationListElementComponent } from './object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component'; @@ -216,6 +215,9 @@ import { AuthorizedCollectionSelectorComponent } from './dso-selector/dso-select import { DsoPageEditButtonComponent } from './dso-page/dso-page-edit-button/dso-page-edit-button.component'; import { HoverClassDirective } from './hover-class.directive'; import { ValidationSuggestionsComponent } from './input-suggestions/validation-suggestions/validation-suggestions.component'; +import { ItemSearchResultGridElementComponent } from './object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component'; +import { ResourcePolicyEditComponent } from './resource-policies/edit/resource-policy-edit.component'; +import { ResourcePolicyCreateComponent } from './resource-policies/create/resource-policy-create.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -376,7 +378,7 @@ const COMPONENTS = [ BrowseByComponent, AbstractTrackableComponent, ComcolMetadataComponent, - ItemTypeBadgeComponent, + TypeBadgeComponent, BrowseByComponent, AbstractTrackableComponent, CustomSwitchComponent, @@ -392,12 +394,14 @@ const COMPONENTS = [ LogInPasswordComponent, LogInContainerComponent, ItemVersionsComponent, - PublicationSearchResultListElementComponent, + ItemSearchResultListElementComponent, ItemVersionsNoticeComponent, ModifyItemOverviewComponent, ImpersonateNavbarComponent, ResourcePoliciesComponent, ResourcePolicyFormComponent, + ResourcePolicyEditComponent, + ResourcePolicyCreateComponent, EpersonGroupListComponent, EpersonSearchBoxComponent, GroupSearchBoxComponent, @@ -411,6 +415,11 @@ const COMPONENTS = [ PublicationListElementComponent, SearchResultListElementComponent, SearchResultGridElementComponent, + ItemListElementComponent, + ItemGridElementComponent, + ItemSearchResultListElementComponent, + ItemSearchResultGridElementComponent, + BrowseEntryListElementComponent, SearchResultDetailElementComponent, BrowseEntryListElementComponent, PlainTextMetadataListElementComponent, diff --git a/src/app/shared/utils/relation-query.utils.spec.ts b/src/app/shared/utils/relation-query.utils.spec.ts index f70e904422..f40c331497 100644 --- a/src/app/shared/utils/relation-query.utils.spec.ts +++ b/src/app/shared/utils/relation-query.utils.spec.ts @@ -6,13 +6,13 @@ describe('Relation Query Utils', () => { describe('getQueryByRelations', () => { it('Should return the correct query based on relationtype and uuid', () => { const result = getQueryByRelations(relationtype, itemUUID); - expect(result).toEqual('query=relation.isAuthorOfPublication:a7939af0-36ad-430d-af09-7be8b0a4dadd'); + expect(result).toEqual('query=relation.isAuthorOfPublication:"a7939af0-36ad-430d-af09-7be8b0a4dadd"'); }); }); describe('getFilterByRelation', () => { it('Should return the correct query based on relationtype and uuid', () => { const result = getFilterByRelation(relationtype, itemUUID); - expect(result).toEqual('f.isAuthorOfPublication=a7939af0-36ad-430d-af09-7be8b0a4dadd'); + expect(result).toEqual('f.isAuthorOfPublication=a7939af0-36ad-430d-af09-7be8b0a4dadd,equals'); }); }); }); diff --git a/src/app/shared/utils/relation-query.utils.ts b/src/app/shared/utils/relation-query.utils.ts index 74f9e64cc9..13248c5a6b 100644 --- a/src/app/shared/utils/relation-query.utils.ts +++ b/src/app/shared/utils/relation-query.utils.ts @@ -5,7 +5,7 @@ * @returns {string} Query */ export function getQueryByRelations(relationType: string, itemUUID: string): string { - return `query=relation.${relationType}:${itemUUID}`; + return `query=relation.${relationType}:"${itemUUID}"`; } /** @@ -14,5 +14,5 @@ export function getQueryByRelations(relationType: string, itemUUID: string): str * @param itemUUID The item's UUID */ export function getFilterByRelation(relationType: string, itemUUID: string): string { - return `f.${relationType}=${itemUUID}`; + return `f.${relationType}=${itemUUID},equals`; } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 908ed25c47..cf2df7c9df 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -715,6 +715,10 @@ "collection.edit.tabs.curate.title": "Collection Edit - Curate", + "collection.edit.tabs.authorizations.head": "Authorizations", + + "collection.edit.tabs.authorizations.title": "Collection Edit - Authorizations", + "collection.edit.tabs.metadata.head": "Edit Metadata", "collection.edit.tabs.metadata.title": "Collection Edit - Metadata", @@ -801,6 +805,10 @@ + "collection.listelement.badge": "Collection", + + + "collection.page.browse.recent.head": "Recent Submissions", "collection.page.browse.recent.empty": "No items to show", @@ -902,6 +910,14 @@ "community.edit.tabs.roles.title": "Community Edit - Roles", + "community.edit.tabs.authorizations.head": "Authorizations", + + "community.edit.tabs.authorizations.title": "Community Edit - Authorizations", + + + + "community.listelement.badge": "Community", + "comcol-role.edit.no-group": "None", @@ -1717,6 +1733,28 @@ + "item.listelement.badge": "Item", + + "item.page.description": "Description", + + "item.page.edit": "Edit this item", + + "item.page.journal-issn": "Journal ISSN", + + "item.page.journal-title": "Journal Title", + + "item.page.publisher": "Publisher", + + "item.page.titleprefix": "Item: ", + + "item.page.volume-title": "Volume Title", + + "item.search.results.head": "Item Search Results", + + "item.search.title": "DSpace Angular :: Item Search", + + + "item.page.abstract": "Abstract", "item.page.author": "Authors", @@ -2650,6 +2688,10 @@ "resource-policies.add.for.item": "Add a new Item policy", + "resource-policies.add.for.community": "Add a new Community policy", + + "resource-policies.add.for.collection": "Add a new Collection policy", + "resource-policies.create.page.heading": "Create new resource policy for ", "resource-policies.create.page.failure.content": "An error occurred while creating the resource policy.", @@ -2732,6 +2774,10 @@ "resource-policies.table.headers.title.for.item": "Policies for Item", + "resource-policies.table.headers.title.for.community": "Policies for Community", + + "resource-policies.table.headers.title.for.collection": "Policies for Collection", + "search.description": "",