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-access-control/admin-access-control-routing.module.ts b/src/app/+admin/admin-access-control/admin-access-control-routing.module.ts index d2f2233eee..10ac117b0f 100644 --- a/src/app/+admin/admin-access-control/admin-access-control-routing.module.ts +++ b/src/app/+admin/admin-access-control/admin-access-control-routing.module.ts @@ -13,12 +13,12 @@ import { GROUP_EDIT_PATH } from './admin-access-control-routing-paths'; { path: `${GROUP_EDIT_PATH}/:groupId`, component: GroupFormComponent, - data: {title: 'admin.registries.schema.title'} + data: {title: 'admin.access-control.groups.title.singleGroup'} }, { path: `${GROUP_EDIT_PATH}/newGroup`, component: GroupFormComponent, - data: {title: 'admin.registries.schema.title'} + data: {title: 'admin.access-control.groups.title.addGroup'} }, ]) ] diff --git a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.html b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.html index 5cb8e77a3e..f478557e00 100644 --- a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.html +++ b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.html @@ -40,7 +40,7 @@ { activeEPerson: null, allEpeople: mockEPeople, getEPeople(): Observable>> { - return createSuccessfulRemoteDataObject$(new PaginatedList(null, this.allEpeople)); + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo({ elementsPerPage: this.allEpeople.length, totalElements: this.allEpeople.length, totalPages: 1, currentPage: 1 }), this.allEpeople)); }, getActiveEPerson(): Observable { return observableOf(this.activeEPerson); @@ -54,18 +54,18 @@ describe('EPeopleRegistryComponent', () => { const result = this.allEpeople.find((ePerson: EPerson) => { return ePerson.email === query }); - return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [result])); + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo({ elementsPerPage: [result].length, totalElements: [result].length, totalPages: 1, currentPage: 1 }), [result])); } if (scope === 'metadata') { if (query === '') { - return createSuccessfulRemoteDataObject$(new PaginatedList(null, this.allEpeople)); + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo({ elementsPerPage: this.allEpeople.length, totalElements: this.allEpeople.length, totalPages: 1, currentPage: 1 }), this.allEpeople)); } const result = this.allEpeople.find((ePerson: EPerson) => { return (ePerson.name.includes(query) || ePerson.email.includes(query)) }); - return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [result])); + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo({ elementsPerPage: [result].length, totalElements: [result].length, totalPages: 1, currentPage: 1 }), [result])); } - return createSuccessfulRemoteDataObject$(new PaginatedList(null, this.allEpeople)); + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo({ elementsPerPage: this.allEpeople.length, totalElements: this.allEpeople.length, totalPages: 1, currentPage: 1 }), this.allEpeople)); }, deleteEPerson(ePerson: EPerson): Observable { this.allEpeople = this.allEpeople.filter((ePerson2: EPerson) => { diff --git a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts index 2f989490a7..fe0503bcd7 100644 --- a/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts +++ b/src/app/+admin/admin-access-control/epeople-registry/epeople-registry.component.ts @@ -141,7 +141,8 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { currentPage: this.config.currentPage, elementsPerPage: this.config.pageSize }).subscribe((peopleRD) => { - this.ePeople$.next(peopleRD) + this.ePeople$.next(peopleRD); + this.pageInfoState$.next(peopleRD.payload.pageInfo); } )); diff --git a/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.html b/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.html index 2f76e45429..a0d8a45255 100644 --- a/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.html +++ b/src/app/+admin/admin-access-control/group-registry/group-form/group-form.component.html @@ -1,6 +1,11 @@
+ + +
@@ -18,10 +23,18 @@ [formLayout]="formLayout" (cancel)="onCancel()" (submitForm)="onSubmit()"> +
+ +
- - + +
-
@@ -75,7 +75,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/forbidden/forbidden.component.html b/src/app/forbidden/forbidden.component.html new file mode 100644 index 0000000000..067aad0048 --- /dev/null +++ b/src/app/forbidden/forbidden.component.html @@ -0,0 +1,10 @@ +
+

403

+

{{"403.forbidden" | translate}}

+
+

{{"403.help" | translate}}

+
+

+ {{"403.link.home-page" | translate}} +

+
diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.scss b/src/app/forbidden/forbidden.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/forbidden/forbidden.component.scss diff --git a/src/app/unauthorized/unauthorized.component.ts b/src/app/forbidden/forbidden.component.ts similarity index 50% rename from src/app/unauthorized/unauthorized.component.ts rename to src/app/forbidden/forbidden.component.ts index 280a1ae947..b622a0f066 100644 --- a/src/app/unauthorized/unauthorized.component.ts +++ b/src/app/forbidden/forbidden.component.ts @@ -3,30 +3,30 @@ import { AuthService } from '../core/auth/auth.service'; import { ServerResponseService } from '../core/services/server-response.service'; /** - * This component representing the `Unauthorized` DSpace page. + * This component representing the `Forbidden` DSpace page. */ @Component({ - selector: 'ds-unauthorized', - templateUrl: './unauthorized.component.html', - styleUrls: ['./unauthorized.component.scss'] + selector: 'ds-forbidden', + templateUrl: './forbidden.component.html', + styleUrls: ['./forbidden.component.scss'] }) -export class UnauthorizedComponent implements OnInit { +export class ForbiddenComponent implements OnInit { /** * Initialize instance variables * - * @param {AuthService} authservice + * @param {AuthService} authService * @param {ServerResponseService} responseService */ - constructor(private authservice: AuthService, private responseService: ServerResponseService) { - this.responseService.setUnauthorized(); + constructor(private authService: AuthService, private responseService: ServerResponseService) { + this.responseService.setForbidden(); } /** * Remove redirect url from the state */ ngOnInit(): void { - this.authservice.clearRedirectUrl(); + this.authService.clearRedirectUrl(); } } diff --git a/src/app/process-page/detail/process-detail.component.ts b/src/app/process-page/detail/process-detail.component.ts index c4b94aa729..53dd6dd921 100644 --- a/src/app/process-page/detail/process-detail.component.ts +++ b/src/app/process-page/detail/process-detail.component.ts @@ -12,7 +12,7 @@ import { ProcessDataService } from '../../core/data/processes/process-data.servi import { RemoteData } from '../../core/data/remote-data'; import { Bitstream } from '../../core/shared/bitstream.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { getFirstSucceededRemoteDataPayload, redirectOn404Or401 } from '../../core/shared/operators'; +import { getFirstSucceededRemoteDataPayload, redirectOn4xx } from '../../core/shared/operators'; import { URLCombiner } from '../../core/url-combiner/url-combiner'; import { AlertType } from '../../shared/alert/aletr-type'; import { hasValue } from '../../shared/empty.util'; @@ -84,7 +84,7 @@ export class ProcessDetailComponent implements OnInit { map((data) => { return data.process as RemoteData }), - redirectOn404Or401(this.router) + redirectOn4xx(this.router, this.authService) ); this.filesRD$ = this.processRD$.pipe( diff --git a/src/app/shared/mocks/auth.service.mock.ts b/src/app/shared/mocks/auth.service.mock.ts index 0f3a7d13d1..064af7dade 100644 --- a/src/app/shared/mocks/auth.service.mock.ts +++ b/src/app/shared/mocks/auth.service.mock.ts @@ -12,4 +12,11 @@ export class AuthServiceMock { public getShortlivedToken(): Observable { return observableOf('token'); } + + public isAuthenticated(): Observable { + return observableOf(true); + } + + public setRedirectUrl(url: string) { + } } 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 e2d9b17f1c..de510af0bb 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 @@ describe('ListableObjectComponentLoaderComponent', () => { beforeEach(async(() => { 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 @@ describe('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/search-result-grid-element/item-search-result/publication/publication-search-result-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/search-result-grid-element/item-search-result/publication/publication-search-result-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 85% 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 84f926bbe3..8400023ff4 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/internal/observable/of'; 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/unauthorized/unauthorized.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/unauthorized/unauthorized.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 0688b7c60e..4f86b6146c 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 @@ -24,7 +24,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 = {}; @@ -72,7 +72,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 e1478b5206..bf7f04b9ac 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 56cf840f4a..af6c44786b 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 @@ -153,7 +153,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 83% 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 f75a49363f..e3a1d64f9f 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 @@ -5,11 +5,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'; @@ -41,15 +41,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; })); @@ -71,9 +71,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 017e67841c..2873ba71e5 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 3c933dc607..dceb485fb6 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 5dc930f67f..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 04e810edda..7148682b0e 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 f58a903b0c..4fd9a62bf6 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 376aa7ba3a..54548b0ddf 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 df0c53f543..9ff8663a65 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,7 +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 +304,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 a81d051132..72f2726c85 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -21,7 +21,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'; @@ -160,13 +160,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'; @@ -218,6 +217,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 @@ -383,7 +385,7 @@ const COMPONENTS = [ BrowseByComponent, AbstractTrackableComponent, ComcolMetadataComponent, - ItemTypeBadgeComponent, + TypeBadgeComponent, BrowseByComponent, AbstractTrackableComponent, CustomSwitchComponent, @@ -399,12 +401,14 @@ const COMPONENTS = [ LogInPasswordComponent, LogInContainerComponent, ItemVersionsComponent, - PublicationSearchResultListElementComponent, + ItemSearchResultListElementComponent, ItemVersionsNoticeComponent, ModifyItemOverviewComponent, ImpersonateNavbarComponent, ResourcePoliciesComponent, ResourcePolicyFormComponent, + ResourcePolicyEditComponent, + ResourcePolicyCreateComponent, EpersonGroupListComponent, EpersonSearchBoxComponent, GroupSearchBoxComponent, @@ -428,10 +432,10 @@ const ENTRY_COMPONENTS = [ CommunitySearchResultGridElementComponent, CollectionSearchResultGridElementComponent, SearchResultGridElementComponent, - PublicationListElementComponent, - PublicationGridElementComponent, - PublicationSearchResultListElementComponent, - PublicationSearchResultGridElementComponent, + ItemListElementComponent, + ItemGridElementComponent, + ItemSearchResultListElementComponent, + ItemSearchResultGridElementComponent, BrowseEntryListElementComponent, SearchResultDetailElementComponent, SearchResultGridElementComponent, diff --git a/src/app/shared/testing/group-mock.ts b/src/app/shared/testing/group-mock.ts index d0ee135b98..24a78a58e5 100644 --- a/src/app/shared/testing/group-mock.ts +++ b/src/app/shared/testing/group-mock.ts @@ -12,6 +12,7 @@ export const GroupMock2: Group = Object.assign(new Group(), { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid2', }, subgroups: { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid2/subgroups' }, + object: { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid2/object' }, epersons: { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid2/epersons' } }, _name: 'testgroupname2', @@ -31,6 +32,7 @@ export const GroupMock: Group = Object.assign(new Group(), { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid', }, subgroups: { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid/subgroups' }, + object: { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid2/object' }, epersons: { href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid/epersons' } }, _name: 'testgroupname', 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/app/statistics-page/collection-statistics-page/collection-statistics-page.component.spec.ts b/src/app/statistics-page/collection-statistics-page/collection-statistics-page.component.spec.ts index 110757670c..cf6a8b7cff 100644 --- a/src/app/statistics-page/collection-statistics-page/collection-statistics-page.component.spec.ts +++ b/src/app/statistics-page/collection-statistics-page/collection-statistics-page.component.spec.ts @@ -14,6 +14,7 @@ import { SharedModule } from '../../shared/shared.module'; import { CommonModule } from '@angular/common'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; +import { AuthService } from '../../core/auth/auth.service'; describe('CollectionStatisticsPageComponent', () => { @@ -59,6 +60,11 @@ describe('CollectionStatisticsPageComponent', () => { getName: () => observableOf('test dso name'), }; + const authService = jasmine.createSpyObj('authService', { + isAuthenticated: observableOf(true), + setRedirectUrl: {} + }); + TestBed.configureTestingModule({ imports: [ TranslateModule.forRoot(), @@ -75,6 +81,7 @@ describe('CollectionStatisticsPageComponent', () => { { provide: UsageReportService, useValue: usageReportService }, { provide: DSpaceObjectDataService, useValue: {} }, { provide: DSONameService, useValue: nameService }, + { provide: AuthService, useValue: authService }, ], }) .compileComponents(); diff --git a/src/app/statistics-page/collection-statistics-page/collection-statistics-page.component.ts b/src/app/statistics-page/collection-statistics-page/collection-statistics-page.component.ts index 05f4641d81..41ee47ff88 100644 --- a/src/app/statistics-page/collection-statistics-page/collection-statistics-page.component.ts +++ b/src/app/statistics-page/collection-statistics-page/collection-statistics-page.component.ts @@ -4,6 +4,7 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv import { ActivatedRoute , Router} from '@angular/router'; import { Collection } from '../../core/shared/collection.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { AuthService } from '../../core/auth/auth.service'; /** * Component representing the statistics page for a collection. @@ -30,12 +31,14 @@ export class CollectionStatisticsPageComponent extends StatisticsPageComponent { @@ -59,6 +60,11 @@ describe('CommunityStatisticsPageComponent', () => { getName: () => observableOf('test dso name'), }; + const authService = jasmine.createSpyObj('authService', { + isAuthenticated: observableOf(true), + setRedirectUrl: {} + }); + TestBed.configureTestingModule({ imports: [ TranslateModule.forRoot(), @@ -75,6 +81,7 @@ describe('CommunityStatisticsPageComponent', () => { { provide: UsageReportService, useValue: usageReportService }, { provide: DSpaceObjectDataService, useValue: {} }, { provide: DSONameService, useValue: nameService }, + { provide: AuthService, useValue: authService }, ], }) .compileComponents(); diff --git a/src/app/statistics-page/community-statistics-page/community-statistics-page.component.ts b/src/app/statistics-page/community-statistics-page/community-statistics-page.component.ts index 65d5fe88e5..1a1c8fdf0e 100644 --- a/src/app/statistics-page/community-statistics-page/community-statistics-page.component.ts +++ b/src/app/statistics-page/community-statistics-page/community-statistics-page.component.ts @@ -4,6 +4,7 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv import { ActivatedRoute, Router } from '@angular/router'; import { Community } from '../../core/shared/community.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { AuthService } from '../../core/auth/auth.service'; /** * Component representing the statistics page for a community. @@ -30,12 +31,14 @@ export class CommunityStatisticsPageComponent extends StatisticsPageComponent { @@ -59,6 +60,11 @@ describe('ItemStatisticsPageComponent', () => { getName: () => observableOf('test dso name'), }; + const authService = jasmine.createSpyObj('authService', { + isAuthenticated: observableOf(true), + setRedirectUrl: {} + }); + TestBed.configureTestingModule({ imports: [ TranslateModule.forRoot(), @@ -75,6 +81,7 @@ describe('ItemStatisticsPageComponent', () => { { provide: UsageReportService, useValue: usageReportService }, { provide: DSpaceObjectDataService, useValue: {} }, { provide: DSONameService, useValue: nameService }, + { provide: AuthService, useValue: authService }, ], }) .compileComponents(); diff --git a/src/app/statistics-page/item-statistics-page/item-statistics-page.component.ts b/src/app/statistics-page/item-statistics-page/item-statistics-page.component.ts index fb9ced4520..69a8361a46 100644 --- a/src/app/statistics-page/item-statistics-page/item-statistics-page.component.ts +++ b/src/app/statistics-page/item-statistics-page/item-statistics-page.component.ts @@ -4,6 +4,7 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv import { ActivatedRoute, Router } from '@angular/router'; import { Item } from '../../core/shared/item.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { AuthService } from '../../core/auth/auth.service'; /** * Component representing the statistics page for an item. @@ -31,12 +32,14 @@ export class ItemStatisticsPageComponent extends StatisticsPageComponent { protected router: Router, protected usageReportService: UsageReportService, protected nameService: DSONameService, + protected authService: AuthService ) { super( route, router, usageReportService, nameService, + authService, ); } } diff --git a/src/app/statistics-page/site-statistics-page/site-statistics-page.component.spec.ts b/src/app/statistics-page/site-statistics-page/site-statistics-page.component.spec.ts index 6f2247b433..1a3babc570 100644 --- a/src/app/statistics-page/site-statistics-page/site-statistics-page.component.spec.ts +++ b/src/app/statistics-page/site-statistics-page/site-statistics-page.component.spec.ts @@ -14,6 +14,7 @@ import { CommonModule } from '@angular/common'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { SiteDataService } from '../../core/data/site-data.service'; +import { AuthService } from '../../core/auth/auth.service'; describe('SiteStatisticsPageComponent', () => { @@ -55,6 +56,11 @@ describe('SiteStatisticsPageComponent', () => { })) }; + const authService = jasmine.createSpyObj('authService', { + isAuthenticated: observableOf(true), + setRedirectUrl: {} + }); + TestBed.configureTestingModule({ imports: [ TranslateModule.forRoot(), @@ -72,6 +78,7 @@ describe('SiteStatisticsPageComponent', () => { { provide: DSpaceObjectDataService, useValue: {} }, { provide: DSONameService, useValue: nameService }, { provide: SiteDataService, useValue: siteService }, + { provide: AuthService, useValue: authService }, ], }) .compileComponents(); diff --git a/src/app/statistics-page/site-statistics-page/site-statistics-page.component.ts b/src/app/statistics-page/site-statistics-page/site-statistics-page.component.ts index fd1319723c..59f1be330c 100644 --- a/src/app/statistics-page/site-statistics-page/site-statistics-page.component.ts +++ b/src/app/statistics-page/site-statistics-page/site-statistics-page.component.ts @@ -6,6 +6,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { Site } from '../../core/shared/site.model'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { switchMap } from 'rxjs/operators'; +import { AuthService } from '../../core/auth/auth.service'; /** * Component representing the site-wide statistics page. @@ -30,12 +31,14 @@ export class SiteStatisticsPageComponent extends StatisticsPageComponent { protected usageReportService: UsageReportService, protected nameService: DSONameService, protected siteService: SiteDataService, + protected authService: AuthService, ) { super( route, router, usageReportService, nameService, + authService, ); } diff --git a/src/app/statistics-page/statistics-page/statistics-page.component.ts b/src/app/statistics-page/statistics-page/statistics-page.component.ts index 31cb74eb08..6fa10b437c 100644 --- a/src/app/statistics-page/statistics-page/statistics-page.component.ts +++ b/src/app/statistics-page/statistics-page/statistics-page.component.ts @@ -4,10 +4,11 @@ import { UsageReportService } from '../../core/statistics/usage-report-data.serv import { map, switchMap } from 'rxjs/operators'; import { UsageReport } from '../../core/statistics/models/usage-report.model'; import { RemoteData } from '../../core/data/remote-data'; -import { getRemoteDataPayload, getSucceededRemoteData, redirectOn404Or401 } from '../../core/shared/operators'; +import { getRemoteDataPayload, getSucceededRemoteData, redirectOn4xx } from '../../core/shared/operators'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { ActivatedRoute, Router } from '@angular/router'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { AuthService } from '../../core/auth/auth.service'; /** * Class representing an abstract statistics page component. @@ -36,6 +37,7 @@ export abstract class StatisticsPageComponent implements protected router: Router, protected usageReportService: UsageReportService, protected nameService: DSONameService, + protected authService: AuthService, ) { } @@ -55,7 +57,7 @@ export abstract class StatisticsPageComponent implements protected getScope$(): Observable { return this.route.data.pipe( map((data) => data.scope as RemoteData), - redirectOn404Or401(this.router), + redirectOn4xx(this.router, this.authService), getSucceededRemoteData(), getRemoteDataPayload(), ); diff --git a/src/app/unauthorized/unauthorized.component.html b/src/app/unauthorized/unauthorized.component.html deleted file mode 100644 index a25e271b77..0000000000 --- a/src/app/unauthorized/unauthorized.component.html +++ /dev/null @@ -1,10 +0,0 @@ -
-

401

-

{{"401.unauthorized" | translate}}

-
-

{{"401.help" | translate}}

-
-

- {{"401.link.home-page" | translate}} -

-
diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 9aff481ecc..d9557f8713 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -8,6 +8,14 @@ + "403.help": "You don't have permission to access this page. You can use the button below to get back to the home page.", + + "403.link.home-page": "Take me to the home page", + + "403.forbidden": "forbidden", + + + "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", "404.link.home-page": "Take me to the home page", @@ -280,6 +288,10 @@ "admin.access-control.groups.title": "DSpace Angular :: Groups", + "admin.access-control.groups.title.singleGroup": "DSpace Angular :: Edit Group", + + "admin.access-control.groups.title.addGroup": "DSpace Angular :: New Group", + "admin.access-control.groups.head": "Groups", "admin.access-control.groups.button.add": "Add group", @@ -308,8 +320,15 @@ "admin.access-control.groups.notification.deleted.success": "Successfully deleted group \"{{name}}\"", - "admin.access-control.groups.notification.deleted.failure": "Failed to delete group \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.title": "Failed to delete group \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.content": "Cause: \"{{cause}}\"", + + + + "admin.access-control.groups.form.alert.permanent": "This group is permanent, so it can't be edited or deleted. You can still add and remove group members using this page.", + + "admin.access-control.groups.form.alert.workflowGroup": "This group can’t be modified or deleted because it corresponds to a role in the submission and workflow process in the \"{{name}}\" {{comcol}}. You can delete it from the \"assign roles\" tab on the edit {{comcol}} page. You can still add and remove group members using this page.", "admin.access-control.groups.form.head.create": "Create group", @@ -325,6 +344,28 @@ "admin.access-control.groups.form.notification.created.failure.groupNameInUse": "Failed to create Group with name: \"{{name}}\", make sure the name is not already in use.", + "admin.access-control.groups.form.notification.edited.failure": "Failed to edit Group \"{{name}}\"", + + "admin.access-control.groups.form.notification.edited.failure.groupNameInUse": "Name \"{{name}}\" already in use!", + + "admin.access-control.groups.form.notification.edited.success": "Successfully edited Group \"{{name}}\"", + + "admin.access-control.groups.form.actions.delete": "Delete Group", + + "admin.access-control.groups.form.delete-group.modal.header": "Delete Group \"{{ dsoName }}\"", + + "admin.access-control.groups.form.delete-group.modal.info": "Are you sure you want to delete Group \"{{ dsoName }}\"", + + "admin.access-control.groups.form.delete-group.modal.cancel": "Cancel", + + "admin.access-control.groups.form.delete-group.modal.confirm": "Delete", + + "admin.access-control.groups.form.notification.deleted.success": "Successfully deleted group \"{{ name }}\"", + + "admin.access-control.groups.form.notification.deleted.failure.title": "Failed to delete group \"{{ name }}\"", + + "admin.access-control.groups.form.notification.deleted.failure.content": "Cause: \"{{ cause }}\"", + "admin.access-control.groups.form.members-list.head": "EPeople", "admin.access-control.groups.form.members-list.search.head": "Add EPeople", @@ -674,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", @@ -760,6 +805,10 @@ + "collection.listelement.badge": "Collection", + + + "collection.page.browse.recent.head": "Recent Submissions", "collection.page.browse.recent.empty": "No items to show", @@ -861,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", @@ -1676,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", @@ -2616,6 +2695,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.", @@ -2698,6 +2781,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": "",