diff --git a/.browserslistrc b/.browserslistrc
deleted file mode 100644
index 427441dc93..0000000000
--- a/.browserslistrc
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
-# For additional information regarding the format and rule options, please see:
-# https://github.com/browserslist/browserslist#queries
-
-# For the full list of supported browsers by the Angular framework, please see:
-# https://angular.io/guide/browser-support
-
-# You can see what browsers were selected by your queries by running:
-# npx browserslist
-
-last 1 Chrome version
-last 1 Firefox version
-last 2 Edge major versions
-last 2 Safari major versions
-last 2 iOS major versions
-Firefox ESR
-not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6fae54f1f9..219074780e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -31,6 +31,8 @@ jobs:
# When Chrome version is specified, we pin to a specific version of Chrome
# Comment this out to use the latest release
#CHROME_VERSION: "90.0.4430.212-1"
+ # Bump Node heap size (OOM in CI after upgrading to Angular 15)
+ NODE_OPTIONS: '--max-old-space-size=4096'
strategy:
# Create a matrix of Node versions to test against (in parallel)
matrix:
diff --git a/angular.json b/angular.json
index 56c75d7b2d..5e597d4d30 100644
--- a/angular.json
+++ b/angular.json
@@ -274,9 +274,18 @@
}
}
},
- "defaultProject": "dspace-angular",
"cli": {
"analytics": false,
- "defaultCollection": "@angular-eslint/schematics"
+ "schematicCollections": [
+ "@angular-eslint/schematics"
+ ]
+ },
+ "schematics": {
+ "@angular-eslint/schematics:application": {
+ "setParserOptionsProject": true
+ },
+ "@angular-eslint/schematics:library": {
+ "setParserOptionsProject": true
+ }
}
}
diff --git a/config/config.example.yml b/config/config.example.yml
index f1e6be76aa..ea38303fa3 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -187,6 +187,9 @@ languages:
- code: gd
label: Gàidhlig
active: true
+ - code: it
+ label: Italiano
+ active: true
- code: lv
label: Latviešu
active: true
@@ -214,6 +217,9 @@ languages:
- code: tr
label: Türkçe
active: true
+ - code: vi
+ label: Tiếng Việt
+ active: true
- code: kk
label: Қазақ
active: true
diff --git a/package.json b/package.json
index e1bedeb02b..59766e993b 100644
--- a/package.json
+++ b/package.json
@@ -17,9 +17,9 @@
"build:stats": "ng build --stats-json",
"build:prod": "yarn run build:ssr",
"build:ssr": "ng build --configuration production && ng run dspace-angular:server:production",
- "test": "ng test --sourceMap=true --watch=false --configuration test",
- "test:watch": "nodemon --exec \"ng test --sourceMap=true --watch=true --configuration test\"",
- "test:headless": "ng test --sourceMap=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage",
+ "test": "ng test --source-map=true --watch=false --configuration test",
+ "test:watch": "nodemon --exec \"ng test --source-map=true --watch=true --configuration test\"",
+ "test:headless": "ng test --source-map=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage",
"lint": "ng lint",
"lint-fix": "ng lint --fix=true",
"e2e": "ng e2e",
@@ -55,136 +55,136 @@
"ts-node": "10.2.1"
},
"dependencies": {
- "@angular/animations": "~13.3.12",
- "@angular/cdk": "^13.2.6",
- "@angular/common": "~13.3.12",
- "@angular/compiler": "~13.3.12",
- "@angular/core": "~13.3.12",
- "@angular/forms": "~13.3.12",
- "@angular/localize": "13.3.12",
- "@angular/platform-browser": "~13.3.12",
- "@angular/platform-browser-dynamic": "~13.3.12",
- "@angular/platform-server": "~13.3.12",
- "@angular/router": "~13.3.12",
- "@babel/runtime": "7.17.2",
+ "@angular/animations": "^15.2.8",
+ "@angular/cdk": "^15.2.8",
+ "@angular/common": "^15.2.8",
+ "@angular/compiler": "^15.2.8",
+ "@angular/core": "^15.2.8",
+ "@angular/forms": "^15.2.8",
+ "@angular/localize": "15.2.8",
+ "@angular/platform-browser": "^15.2.8",
+ "@angular/platform-browser-dynamic": "^15.2.8",
+ "@angular/platform-server": "^15.2.8",
+ "@angular/router": "^15.2.8",
+ "@babel/runtime": "7.21.0",
"@kolkov/ngx-gallery": "^2.0.1",
"@material-ui/core": "^4.11.0",
- "@material-ui/icons": "^4.9.1",
+ "@material-ui/icons": "^4.11.3",
"@ng-bootstrap/ng-bootstrap": "^11.0.0",
"@ng-dynamic-forms/core": "^15.0.0",
"@ng-dynamic-forms/ui-ng-bootstrap": "^15.0.0",
- "@ngrx/effects": "^13.0.2",
- "@ngrx/router-store": "^13.0.2",
- "@ngrx/store": "^13.0.2",
- "@nguniversal/express-engine": "^13.0.2",
- "@ngx-translate/core": "^13.0.0",
- "@nicky-lenaers/ngx-scroll-to": "^13.0.0",
+ "@ngrx/effects": "^15.4.0",
+ "@ngrx/router-store": "^15.4.0",
+ "@ngrx/store": "^15.4.0",
+ "@nguniversal/express-engine": "^15.2.1",
+ "@ngx-translate/core": "^14.0.0",
+ "@nicky-lenaers/ngx-scroll-to": "^14.0.0",
"@types/grecaptcha": "^3.0.4",
"angular-idle-preload": "3.0.0",
- "angulartics2": "^12.0.0",
+ "angulartics2": "^12.2.0",
"axios": "^0.27.2",
"bootstrap": "^4.6.1",
"cerialize": "0.1.18",
- "cli-progress": "^3.8.0",
+ "cli-progress": "^3.12.0",
"colors": "^1.4.0",
"compression": "^1.7.4",
- "cookie-parser": "1.4.5",
- "core-js": "^3.7.0",
+ "cookie-parser": "1.4.6",
+ "core-js": "^3.30.1",
"date-fns": "^2.29.3",
"date-fns-tz": "^1.3.7",
- "deepmerge": "^4.2.2",
- "ejs": "^3.1.8",
- "express": "^4.17.1",
+ "deepmerge": "^4.3.1",
+ "ejs": "^3.1.9",
+ "express": "^4.18.2",
"express-rate-limit": "^5.1.3",
- "fast-json-patch": "^3.0.0-1",
+ "fast-json-patch": "^3.1.1",
"filesize": "^6.1.0",
"http-proxy-middleware": "^1.0.5",
- "isbot": "^3.6.5",
+ "isbot": "^3.6.10",
"js-cookie": "2.2.1",
"js-yaml": "^4.1.0",
- "json5": "^2.2.2",
- "jsonschema": "1.4.0",
+ "json5": "^2.2.3",
+ "jsonschema": "1.4.1",
"jwt-decode": "^3.1.2",
"klaro": "^0.7.18",
"lodash": "^4.17.21",
"lru-cache": "^7.14.1",
"markdown-it": "^13.0.1",
- "markdown-it-mathjax3": "^4.3.1",
+ "markdown-it-mathjax3": "^4.3.2",
"mirador": "^3.3.0",
"mirador-dl-plugin": "^0.13.0",
"mirador-share-plugin": "^0.11.0",
"morgan": "^1.10.0",
- "ng-mocks": "^13.1.1",
+ "ng-mocks": "^14.10.0",
"ng2-file-upload": "1.4.0",
"ng2-nouislider": "^1.8.3",
- "ngx-infinite-scroll": "^10.0.1",
- "ngx-pagination": "5.0.0",
+ "ngx-infinite-scroll": "^15.0.0",
+ "ngx-pagination": "6.0.3",
"ngx-sortablejs": "^11.1.0",
- "ngx-ui-switch": "^13.0.2",
+ "ngx-ui-switch": "^14.0.3",
"nouislider": "^14.6.3",
- "pem": "1.14.4",
- "prop-types": "^15.7.2",
- "react-copy-to-clipboard": "^5.0.1",
+ "pem": "1.14.7",
+ "prop-types": "^15.8.1",
+ "react-copy-to-clipboard": "^5.1.0",
"reflect-metadata": "^0.1.13",
- "rxjs": "^7.5.5",
- "sanitize-html": "^2.7.2",
- "sortablejs": "1.13.0",
+ "rxjs": "^7.8.0",
+ "sanitize-html": "^2.10.0",
+ "sortablejs": "1.15.0",
"uuid": "^8.3.2",
"webfontloader": "1.6.28",
"zone.js": "~0.11.5"
},
"devDependencies": {
- "@angular-builders/custom-webpack": "~13.1.0",
- "@angular-devkit/build-angular": "~13.3.10",
- "@angular-eslint/builder": "13.1.0",
- "@angular-eslint/eslint-plugin": "13.1.0",
- "@angular-eslint/eslint-plugin-template": "13.1.0",
- "@angular-eslint/schematics": "13.1.0",
- "@angular-eslint/template-parser": "13.1.0",
- "@angular/cli": "~13.3.10",
- "@angular/compiler-cli": "~13.3.12",
- "@angular/language-service": "~13.3.12",
+ "@angular-builders/custom-webpack": "~15.0.0",
+ "@angular-devkit/build-angular": "^15.2.6",
+ "@angular-eslint/builder": "15.2.1",
+ "@angular-eslint/eslint-plugin": "15.2.1",
+ "@angular-eslint/eslint-plugin-template": "15.2.1",
+ "@angular-eslint/schematics": "15.2.1",
+ "@angular-eslint/template-parser": "15.2.1",
+ "@angular/cli": "^15.2.6",
+ "@angular/compiler-cli": "^15.2.8",
+ "@angular/language-service": "^15.2.8",
"@cypress/schematic": "^1.5.0",
- "@fortawesome/fontawesome-free": "^6.2.1",
- "@ngrx/store-devtools": "^13.0.2",
- "@ngtools/webpack": "^13.2.6",
- "@nguniversal/builders": "^13.1.1",
+ "@fortawesome/fontawesome-free": "^6.4.0",
+ "@ngrx/store-devtools": "^15.4.0",
+ "@ngtools/webpack": "^15.2.6",
+ "@nguniversal/builders": "^15.2.1",
"@types/deep-freeze": "0.1.2",
- "@types/ejs": "^3.1.1",
- "@types/express": "^4.17.9",
+ "@types/ejs": "^3.1.2",
+ "@types/express": "^4.17.17",
"@types/jasmine": "~3.6.0",
"@types/js-cookie": "2.2.6",
- "@types/lodash": "^4.14.165",
+ "@types/lodash": "^4.14.194",
"@types/node": "^14.14.9",
- "@types/sanitize-html": "^2.6.2",
- "@typescript-eslint/eslint-plugin": "5.11.0",
- "@typescript-eslint/parser": "5.11.0",
- "axe-core": "^4.4.3",
+ "@types/sanitize-html": "^2.9.0",
+ "@typescript-eslint/eslint-plugin": "^5.59.1",
+ "@typescript-eslint/parser": "^5.59.1",
+ "axe-core": "^4.7.0",
"compression-webpack-plugin": "^9.2.0",
"copy-webpack-plugin": "^6.4.1",
"cross-env": "^7.0.3",
- "cypress": "12.9.0",
- "cypress-axe": "^1.1.0",
+ "cypress": "12.10.0",
+ "cypress-axe": "^1.4.0",
"deep-freeze": "0.0.1",
- "eslint": "^8.2.0",
- "eslint-plugin-deprecation": "^1.3.2",
- "eslint-plugin-import": "^2.25.4",
+ "eslint": "^8.39.0",
+ "eslint-plugin-deprecation": "^1.4.1",
+ "eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsdoc": "^39.6.4",
"eslint-plugin-jsonc": "^2.6.0",
"eslint-plugin-lodash": "^7.4.0",
"eslint-plugin-unused-imports": "^2.0.0",
- "express-static-gzip": "^2.1.5",
+ "express-static-gzip": "^2.1.7",
"jasmine-core": "^3.8.0",
"jasmine-marbles": "0.9.2",
- "karma": "^6.3.14",
- "karma-chrome-launcher": "~3.1.0",
- "karma-coverage-istanbul-reporter": "~3.0.2",
+ "karma": "^6.4.2",
+ "karma-chrome-launcher": "~3.2.0",
+ "karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"karma-mocha-reporter": "2.2.5",
"ngx-mask": "^13.1.7",
- "nodemon": "^2.0.20",
- "postcss": "^8.1",
+ "nodemon": "^2.0.22",
+ "postcss": "^8.4",
"postcss-apply": "0.12.0",
"postcss-import": "^14.0.0",
"postcss-loader": "^4.0.3",
@@ -194,14 +194,14 @@
"react-dom": "^16.14.0",
"rimraf": "^3.0.2",
"rxjs-spy": "^8.0.2",
- "sass": "~1.33.0",
+ "sass": "~1.62.0",
"sass-loader": "^12.6.0",
- "sass-resources-loader": "^2.1.1",
+ "sass-resources-loader": "^2.2.5",
"ts-node": "^8.10.2",
- "typescript": "~4.5.5",
- "webpack": "^5.76.0",
- "webpack-bundle-analyzer": "^4.4.0",
+ "typescript": "~4.8.4",
+ "webpack": "5.76.1",
+ "webpack-bundle-analyzer": "^4.8.0",
"webpack-cli": "^4.2.0",
- "webpack-dev-server": "^4.5.0"
+ "webpack-dev-server": "^4.13.3"
}
}
diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.html b/src/app/access-control/epeople-registry/epeople-registry.component.html
index 3a7806a231..e3a8e2c590 100644
--- a/src/app/access-control/epeople-registry/epeople-registry.component.html
+++ b/src/app/access-control/epeople-registry/epeople-registry.component.html
@@ -68,18 +68,18 @@
{{epersonDto.eperson.id}} |
- {{epersonDto.eperson.name}} |
+ {{ dsoNameService.getName(epersonDto.eperson) }} |
{{epersonDto.eperson.email}} |
diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.ts b/src/app/access-control/epeople-registry/epeople-registry.component.ts
index 55233d8173..706dcab690 100644
--- a/src/app/access-control/epeople-registry/epeople-registry.component.ts
+++ b/src/app/access-control/epeople-registry/epeople-registry.component.ts
@@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
-import { FormBuilder } from '@angular/forms';
+import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs';
@@ -21,6 +21,7 @@ import { RequestService } from '../../core/data/request.service';
import { PageInfo } from '../../core/shared/page-info.model';
import { NoContent } from '../../core/shared/NoContent.model';
import { PaginationService } from '../../core/pagination/pagination.service';
+import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-epeople-registry',
@@ -89,11 +90,13 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
private translateService: TranslateService,
private notificationsService: NotificationsService,
private authorizationService: AuthorizationDataService,
- private formBuilder: FormBuilder,
+ private formBuilder: UntypedFormBuilder,
private router: Router,
private modalService: NgbModal,
private paginationService: PaginationService,
- public requestService: RequestService) {
+ public requestService: RequestService,
+ public dsoNameService: DSONameService,
+ ) {
this.currentSearchQuery = '';
this.currentSearchScope = 'metadata';
this.searchForm = this.formBuilder.group(({
@@ -121,7 +124,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
this.subs.push(this.ePeople$.pipe(
switchMap((epeople: PaginatedList) => {
if (epeople.pageInfo.totalElements > 0) {
- return combineLatest(...epeople.page.map((eperson) => {
+ return combineLatest([...epeople.page.map((eperson: EPerson) => {
return this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined).pipe(
map((authorized) => {
const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel();
@@ -130,7 +133,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
return epersonDtoModel;
})
);
- })).pipe(map((dtos: EpersonDtoModel[]) => {
+ })]).pipe(map((dtos: EpersonDtoModel[]) => {
return buildPaginatedList(epeople.pageInfo, dtos);
}));
} else {
@@ -237,7 +240,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
if (hasValue(ePerson.id)) {
this.epersonService.deleteEPerson(ePerson).pipe(getFirstCompletedRemoteData()).subscribe((restResponse: RemoteData) => {
if (restResponse.hasSucceeded) {
- this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', {name: ePerson.name}));
+ this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', {name: this.dsoNameService.getName(ePerson)}));
} else {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + ePerson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.errorMessage);
}
diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html
index 7386177ea0..228449a8a5 100644
--- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html
+++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html
@@ -65,9 +65,13 @@
{{group.id}} |
- {{group.name}} |
- {{(group.object | async)?.payload?.name}} |
+
+
+ {{ dsoNameService.getName(group) }}
+
+ |
+ {{ dsoNameService.getName(undefined) }} |
diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts
index bf03e1defb..fb911e709c 100644
--- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts
+++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts
@@ -2,7 +2,7 @@ import { Observable, of as observableOf } from 'rxjs';
import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
-import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
+import { UntypedFormControl, UntypedFormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
@@ -116,9 +116,9 @@ describe('EPersonFormComponent', () => {
const controlModel = model;
const controlState = { value: controlModel.value, disabled: controlModel.disabled };
const controlOptions = this.createAbstractControlOptions(controlModel.validators, controlModel.asyncValidators, controlModel.updateOn);
- controls[model.id] = new FormControl(controlState, controlOptions);
+ controls[model.id] = new UntypedFormControl(controlState, controlOptions);
});
- return new FormGroup(controls, options);
+ return new UntypedFormGroup(controls, options);
},
createAbstractControlOptions(validatorsConfig = null, asyncValidatorsConfig = null, updateOn = null) {
return {
diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts
index 5a7ab735ca..c60de00aed 100644
--- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts
+++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
-import { FormGroup } from '@angular/forms';
+import { UntypedFormGroup } from '@angular/forms';
import {
DynamicCheckboxModel,
DynamicFormControlModel,
@@ -37,6 +37,7 @@ import { ValidateEmailNotTaken } from './validators/email-taken.validator';
import { Registration } from '../../../core/shared/registration.model';
import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service';
import { TYPE_REQUEST_FORGOT } from '../../../register-email-form/register-email-form.component';
+import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-eperson-form',
@@ -108,7 +109,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
/**
* A FormGroup that combines all inputs
*/
- formGroup: FormGroup;
+ formGroup: UntypedFormGroup;
/**
* An EventEmitter that's fired whenever the form is being submitted
@@ -192,6 +193,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
private paginationService: PaginationService,
public requestService: RequestService,
private epersonRegistrationService: EpersonRegistrationService,
+ public dsoNameService: DSONameService,
) {
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
this.epersonInitial = eperson;
@@ -212,14 +214,14 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
*/
initialisePage() {
- observableCombineLatest(
+ observableCombineLatest([
this.translateService.get(`${this.messagePrefix}.firstName`),
this.translateService.get(`${this.messagePrefix}.lastName`),
this.translateService.get(`${this.messagePrefix}.email`),
this.translateService.get(`${this.messagePrefix}.canLogIn`),
this.translateService.get(`${this.messagePrefix}.requireCertificate`),
this.translateService.get(`${this.messagePrefix}.emailHint`),
- ).subscribe(([firstName, lastName, email, canLogIn, requireCertificate, emailHint]) => {
+ ]).subscribe(([firstName, lastName, email, canLogIn, requireCertificate, emailHint]) => {
this.firstName = new DynamicInputModel({
id: 'firstName',
label: firstName,
@@ -386,10 +388,10 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
getFirstCompletedRemoteData()
).subscribe((rd: RemoteData) => {
if (rd.hasSucceeded) {
- this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.created.success', { name: ePersonToCreate.name }));
+ this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.created.success', { name: this.dsoNameService.getName(ePersonToCreate) }));
this.submitForm.emit(ePersonToCreate);
} else {
- this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.created.failure', { name: ePersonToCreate.name }));
+ this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.created.failure', { name: this.dsoNameService.getName(ePersonToCreate) }));
this.cancelForm.emit();
}
});
@@ -425,10 +427,10 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
const response = this.epersonService.updateEPerson(editedEperson);
response.pipe(getFirstCompletedRemoteData()).subscribe((rd: RemoteData) => {
if (rd.hasSucceeded) {
- this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.edited.success', { name: editedEperson.name }));
+ this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.edited.success', { name: this.dsoNameService.getName(editedEperson) }));
this.submitForm.emit(editedEperson);
} else {
- this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.edited.failure', { name: editedEperson.name }));
+ this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.edited.failure', { name: this.dsoNameService.getName(editedEperson) }));
this.cancelForm.emit();
}
});
@@ -476,7 +478,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
if (hasValue(eperson.id)) {
this.epersonService.deleteEPerson(eperson).pipe(getFirstCompletedRemoteData()).subscribe((restResponse: RemoteData) => {
if (restResponse.hasSucceeded) {
- this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: eperson.name }));
+ this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: this.dsoNameService.getName(eperson) }));
this.submitForm.emit();
} else {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + eperson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.errorMessage);
@@ -554,7 +556,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
.subscribe((list: PaginatedList) => {
if (list.totalElements > 0) {
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.' + notificationSection + '.failure.emailInUse', {
- name: ePerson.name,
+ name: this.dsoNameService.getName(ePerson),
email: ePerson.email
}));
}
diff --git a/src/app/access-control/group-registry/group-form/group-form.component.html b/src/app/access-control/group-registry/group-form/group-form.component.html
index d86adc674b..77a81a8daa 100644
--- a/src/app/access-control/group-registry/group-form/group-form.component.html
+++ b/src/app/access-control/group-registry/group-form/group-form.component.html
@@ -26,7 +26,7 @@
+ [content]="(messagePrefix + '.alert.workflowGroup' | translate:{ name: dsoNameService.getName((getLinkedDSO(groupBeingEdited) | async)?.payload), comcol: (getLinkedDSO(groupBeingEdited) | async)?.payload?.type, comcolEditRolesRoute: (getLinkedEditRolesRoute(groupBeingEdited) | async) })">
{
let component: GroupFormComponent;
@@ -130,9 +132,9 @@ describe('GroupFormComponent', () => {
const controlModel = model;
const controlState = { value: controlModel.value, disabled: controlModel.disabled };
const controlOptions = this.createAbstractControlOptions(controlModel.validators, controlModel.asyncValidators, controlModel.updateOn);
- controls[model.id] = new FormControl(controlState, controlOptions);
+ controls[model.id] = new UntypedFormControl(controlState, controlOptions);
});
- return new FormGroup(controls, options);
+ return new UntypedFormGroup(controls, options);
},
createAbstractControlOptions(validatorsConfig = null, asyncValidatorsConfig = null, updateOn = null) {
return {
@@ -188,7 +190,7 @@ describe('GroupFormComponent', () => {
translateService = getMockTranslateService();
router = new RouterMock();
notificationService = new NotificationsServiceStub();
- TestBed.configureTestingModule({
+ return TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
@@ -198,7 +200,8 @@ describe('GroupFormComponent', () => {
}),
],
declarations: [GroupFormComponent],
- providers: [GroupFormComponent,
+ providers: [
+ { provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: DSpaceObjectDataService, useValue: dsoDataServiceStub },
@@ -240,8 +243,8 @@ describe('GroupFormComponent', () => {
fixture.detectChanges();
});
- it('should emit a new group using the correct values', waitForAsync(() => {
- fixture.whenStable().then(() => {
+ it('should emit a new group using the correct values', (async () => {
+ await fixture.whenStable().then(() => {
expect(component.submitForm.emit).toHaveBeenCalledWith(expected);
});
}));
@@ -303,8 +306,8 @@ describe('GroupFormComponent', () => {
expect(groupsDataServiceStub.patch).toHaveBeenCalledWith(expected, operations);
});
- it('should emit the existing group using the correct new values', waitForAsync(() => {
- fixture.whenStable().then(() => {
+ it('should emit the existing group using the correct new values', (async () => {
+ await fixture.whenStable().then(() => {
expect(component.submitForm.emit).toHaveBeenCalledWith(expected2);
});
}));
diff --git a/src/app/access-control/group-registry/group-form/group-form.component.ts b/src/app/access-control/group-registry/group-form/group-form.component.ts
index 4302d126ea..3c0547cca5 100644
--- a/src/app/access-control/group-registry/group-form/group-form.component.ts
+++ b/src/app/access-control/group-registry/group-form/group-form.component.ts
@@ -1,5 +1,5 @@
import { Component, EventEmitter, HostListener, OnDestroy, OnInit, Output, ChangeDetectorRef } from '@angular/core';
-import { FormGroup } from '@angular/forms';
+import { UntypedFormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
@@ -46,6 +46,7 @@ import { followLink } from '../../../shared/utils/follow-link-config.model';
import { NoContent } from '../../../core/shared/NoContent.model';
import { Operation } from 'fast-json-patch';
import { ValidateGroupExists } from './validators/group-exists.validator';
+import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { environment } from '../../../../environments/environment';
@Component({
@@ -95,7 +96,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
/**
* A FormGroup that combines all inputs
*/
- formGroup: FormGroup;
+ formGroup: UntypedFormGroup;
/**
* An EventEmitter that's fired whenever the form is being submitted
@@ -134,7 +135,8 @@ export class GroupFormComponent implements OnInit, OnDestroy {
groupNameValueChangeSubscribe: Subscription;
- constructor(public groupDataService: GroupDataService,
+ constructor(
+ public groupDataService: GroupDataService,
private ePersonDataService: EPersonDataService,
private dSpaceObjectDataService: DSpaceObjectDataService,
private formBuilderService: FormBuilderService,
@@ -145,7 +147,9 @@ export class GroupFormComponent implements OnInit, OnDestroy {
private authorizationService: AuthorizationDataService,
private modalService: NgbModal,
public requestService: RequestService,
- protected changeDetectorRef: ChangeDetectorRef) {
+ protected changeDetectorRef: ChangeDetectorRef,
+ public dsoNameService: DSONameService,
+ ) {
}
ngOnInit() {
@@ -331,7 +335,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
.subscribe((list: PaginatedList) => {
if (list.totalElements > 0) {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.' + notificationSection + '.failure.groupNameInUse', {
- name: group.name
+ name: this.dsoNameService.getName(group),
}));
}
}));
@@ -364,10 +368,10 @@ export class GroupFormComponent implements OnInit, OnDestroy {
getFirstCompletedRemoteData()
).subscribe((rd: RemoteData) => {
if (rd.hasSucceeded) {
- this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.edited.success', { name: rd.payload.name }));
+ this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.edited.success', { name: this.dsoNameService.getName(rd.payload) }));
this.submitForm.emit(rd.payload);
} else {
- this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.edited.failure', { name: group.name }));
+ this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.edited.failure', { name: this.dsoNameService.getName(group) }));
this.cancelForm.emit();
}
});
@@ -427,11 +431,11 @@ export class GroupFormComponent implements OnInit, OnDestroy {
this.groupDataService.delete(group.id).pipe(getFirstCompletedRemoteData())
.subscribe((rd: RemoteData) => {
if (rd.hasSucceeded) {
- this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.deleted.success', { name: group.name }));
+ this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.deleted.success', { name: this.dsoNameService.getName(group) }));
this.onCancel();
} else {
this.notificationsService.error(
- this.translateService.get(this.messagePrefix + '.notification.deleted.failure.title', { name: group.name }),
+ this.translateService.get(this.messagePrefix + '.notification.deleted.failure.title', { name: this.dsoNameService.getName(group) }),
this.translateService.get(this.messagePrefix + '.notification.deleted.failure.content', { cause: rd.errorMessage }));
}
});
diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html
index 282ee89674..cc9bf34d64 100644
--- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html
+++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html
@@ -57,8 +57,12 @@
{{ePerson.eperson.id}} |
- {{ePerson.eperson.name}} |
+
+
+ {{ dsoNameService.getName(ePerson.eperson) }}
+
+ |
{{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}
{{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }}
@@ -69,7 +73,7 @@
(click)="deleteMemberFromGroup(ePerson)"
[disabled]="actionConfig.remove.disabled"
[ngClass]="['btn btn-sm', actionConfig.remove.css]"
- title="{{messagePrefix + '.table.edit.buttons.remove' | translate: {name: ePerson.eperson.name} }}">
+ title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}">
@@ -77,7 +81,7 @@
(click)="addMemberToGroup(ePerson)"
[disabled]="actionConfig.add.disabled"
[ngClass]="['btn btn-sm', actionConfig.add.css]"
- title="{{messagePrefix + '.table.edit.buttons.add' | translate: {name: ePerson.eperson.name} }}">
+ title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}">
@@ -117,8 +121,12 @@
|
{{ePerson.eperson.id}} |
- {{ePerson.eperson.name}} |
+
+
+ {{ dsoNameService.getName(ePerson.eperson) }}
+
+ |
{{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}
{{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }}
@@ -129,14 +137,14 @@
(click)="deleteMemberFromGroup(ePerson)"
[disabled]="actionConfig.remove.disabled"
[ngClass]="['btn btn-sm', actionConfig.remove.css]"
- title="{{messagePrefix + '.table.edit.buttons.remove' | translate: {name: ePerson.eperson.name} }}">
+ title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}">
diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts
index 4b65535fce..7c8db399bc 100644
--- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts
+++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts
@@ -28,6 +28,8 @@ import { NotificationsServiceStub } from '../../../../shared/testing/notificatio
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
+import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
+import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
describe('MembersListComponent', () => {
let component: MembersListComponent;
@@ -118,7 +120,7 @@ describe('MembersListComponent', () => {
translateService = getMockTranslateService();
paginationService = new PaginationServiceStub();
- TestBed.configureTestingModule({
+ return TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
@@ -135,6 +137,7 @@ describe('MembersListComponent', () => {
{ provide: FormBuilderService, useValue: builderService },
{ provide: Router, useValue: new RouterMock() },
{ provide: PaginationService, useValue: paginationService },
+ { provide: DSONameService, useValue: new DSONameServiceMock() },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts
index d0fc046093..b3e686c012 100644
--- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts
+++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts
@@ -1,5 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
-import { FormBuilder } from '@angular/forms';
+import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import {
@@ -27,6 +27,7 @@ import { NotificationsService } from '../../../../shared/notifications/notificat
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { EpersonDtoModel } from '../../../../core/eperson/models/eperson-dto.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
+import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
/**
* Keys to keep track of specific subscriptions
@@ -141,9 +142,10 @@ export class MembersListComponent implements OnInit, OnDestroy {
public ePersonDataService: EPersonDataService,
protected translateService: TranslateService,
protected notificationsService: NotificationsService,
- protected formBuilder: FormBuilder,
+ protected formBuilder: UntypedFormBuilder,
protected paginationService: PaginationService,
- private router: Router
+ protected router: Router,
+ public dsoNameService: DSONameService,
) {
this.currentSearchQuery = '';
this.currentSearchScope = 'metadata';
@@ -253,7 +255,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => {
if (activeGroup != null) {
const response = this.groupDataService.deleteMemberFromGroup(activeGroup, ePerson.eperson);
- this.showNotifications('deleteMember', response, ePerson.eperson.name, activeGroup);
+ this.showNotifications('deleteMember', response, this.dsoNameService.getName(ePerson.eperson), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup'));
}
@@ -269,7 +271,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => {
if (activeGroup != null) {
const response = this.groupDataService.addMemberToGroup(activeGroup, ePerson.eperson);
- this.showNotifications('addMember', response, ePerson.eperson.name, activeGroup);
+ this.showNotifications('addMember', response, this.dsoNameService.getName(ePerson.eperson), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup'));
}
diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html
index d1574b0dba..d009f0283e 100644
--- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html
+++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html
@@ -53,15 +53,19 @@
|
{{group.id}} |
- {{group.name}} |
- {{(group.object | async)?.payload?.name}} |
+
+
+ {{ dsoNameService.getName(group) }}
+
+ |
+ {{ dsoNameService.getName((group.object | async)?.payload) }} |
@@ -70,7 +74,7 @@
@@ -108,14 +112,18 @@
|
{{group.id}} |
- {{group.name}} |
- {{(group.object | async)?.payload?.name}} |
+
+
+ {{ dsoNameService.getName(group) }}
+
+ |
+ {{ dsoNameService.getName((group.object | async)?.payload)}} |
diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts
index ff0fd121af..ac5750dcac 100644
--- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts
+++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts
@@ -29,6 +29,8 @@ import { NotificationsServiceStub } from '../../../../shared/testing/notificatio
import { map } from 'rxjs/operators';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
+import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
+import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
describe('SubgroupsListComponent', () => {
let component: SubgroupsListComponent;
@@ -108,6 +110,7 @@ describe('SubgroupsListComponent', () => {
],
declarations: [SubgroupsListComponent],
providers: [SubgroupsListComponent,
+ { provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: FormBuilderService, useValue: builderService },
diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts
index 5f1700e07d..0cff730c62 100644
--- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts
+++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts
@@ -1,5 +1,5 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
-import { FormBuilder } from '@angular/forms';
+import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs';
@@ -18,6 +18,7 @@ import { PaginationComponentOptions } from '../../../../shared/pagination/pagina
import { NoContent } from '../../../../core/shared/NoContent.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { followLink } from '../../../../shared/utils/follow-link-config.model';
+import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
/**
* Keys to keep track of specific subscriptions
@@ -86,9 +87,11 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
constructor(public groupDataService: GroupDataService,
private translateService: TranslateService,
private notificationsService: NotificationsService,
- private formBuilder: FormBuilder,
+ private formBuilder: UntypedFormBuilder,
private paginationService: PaginationService,
- private router: Router) {
+ private router: Router,
+ public dsoNameService: DSONameService,
+ ) {
this.currentSearchQuery = '';
}
@@ -177,7 +180,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => {
if (activeGroup != null) {
const response = this.groupDataService.deleteSubGroupFromGroup(activeGroup, subgroup);
- this.showNotifications('deleteSubgroup', response, subgroup.name, activeGroup);
+ this.showNotifications('deleteSubgroup', response, this.dsoNameService.getName(subgroup), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup'));
}
@@ -193,7 +196,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
if (activeGroup != null) {
if (activeGroup.uuid !== subgroup.uuid) {
const response = this.groupDataService.addSubGroupToGroup(activeGroup, subgroup);
- this.showNotifications('addSubgroup', response, subgroup.name, activeGroup);
+ this.showNotifications('addSubgroup', response, this.dsoNameService.getName(subgroup), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.subgroupToAddIsActiveGroup'));
}
diff --git a/src/app/access-control/group-registry/groups-registry.component.html b/src/app/access-control/group-registry/groups-registry.component.html
index bf14034d4f..828aadc95a 100644
--- a/src/app/access-control/group-registry/groups-registry.component.html
+++ b/src/app/access-control/group-registry/groups-registry.component.html
@@ -56,8 +56,8 @@
|
{{groupDto.group.id}} |
- {{groupDto.group.name}} |
- {{(groupDto.group.object | async)?.payload?.name}} |
+ {{ dsoNameService.getName(groupDto.group) }} |
+ {{ dsoNameService.getName((groupDto.group.object | async)?.payload) }} |
{{groupDto.epersons?.totalElements + groupDto.subgroups?.totalElements}} |
@@ -65,7 +65,7 @@
@@ -80,7 +80,7 @@
diff --git a/src/app/access-control/group-registry/groups-registry.component.spec.ts b/src/app/access-control/group-registry/groups-registry.component.spec.ts
index 239939e70d..635ba727c2 100644
--- a/src/app/access-control/group-registry/groups-registry.component.spec.ts
+++ b/src/app/access-control/group-registry/groups-registry.component.spec.ts
@@ -32,8 +32,10 @@ import { PaginationService } from '../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { NoContent } from '../../core/shared/NoContent.model';
+import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
+import { DSONameServiceMock, UNDEFINED_NAME } from '../../shared/mocks/dso-name.service.mock';
-describe('GroupRegistryComponent', () => {
+describe('GroupsRegistryComponent', () => {
let component: GroupsRegistryComponent;
let fixture: ComponentFixture;
let ePersonDataServiceStub: any;
@@ -160,7 +162,7 @@ describe('GroupRegistryComponent', () => {
authorizationService = jasmine.createSpyObj('authorizationService', ['isAuthorized']);
setIsAuthorized(true, true);
paginationService = new PaginationServiceStub();
- TestBed.configureTestingModule({
+ return TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
@@ -171,6 +173,7 @@ describe('GroupRegistryComponent', () => {
],
declarations: [GroupsRegistryComponent],
providers: [GroupsRegistryComponent,
+ { provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: DSpaceObjectDataService, useValue: dsoDataServiceStub },
@@ -208,7 +211,7 @@ describe('GroupRegistryComponent', () => {
it('should display community/collection name if present', () => {
const collectionNamesFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(3)'));
expect(collectionNamesFound.length).toEqual(2);
- expect(collectionNamesFound[0].nativeElement.textContent).toEqual('');
+ expect(collectionNamesFound[0].nativeElement.textContent).toEqual(UNDEFINED_NAME);
expect(collectionNamesFound[1].nativeElement.textContent).toEqual('testgroupid2objectName');
});
diff --git a/src/app/access-control/group-registry/groups-registry.component.ts b/src/app/access-control/group-registry/groups-registry.component.ts
index 70c9b22852..ccfd155e39 100644
--- a/src/app/access-control/group-registry/groups-registry.component.ts
+++ b/src/app/access-control/group-registry/groups-registry.component.ts
@@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
-import { FormBuilder } from '@angular/forms';
+import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import {
@@ -37,6 +37,7 @@ import { PaginationComponentOptions } from '../../shared/pagination/pagination-c
import { NoContent } from '../../core/shared/NoContent.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { followLink } from '../../shared/utils/follow-link-config.model';
+import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-groups-registry',
@@ -99,12 +100,14 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
private dSpaceObjectDataService: DSpaceObjectDataService,
private translateService: TranslateService,
private notificationsService: NotificationsService,
- private formBuilder: FormBuilder,
+ private formBuilder: UntypedFormBuilder,
protected routeService: RouteService,
private router: Router,
private authorizationService: AuthorizationDataService,
private paginationService: PaginationService,
- public requestService: RequestService) {
+ public requestService: RequestService,
+ public dsoNameService: DSONameService,
+ ) {
this.currentSearchQuery = '';
this.searchForm = this.formBuilder.group(({
query: this.currentSearchQuery,
@@ -201,10 +204,10 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
.subscribe((rd: RemoteData) => {
if (rd.hasSucceeded) {
this.deletedGroupsIds = [...this.deletedGroupsIds, group.group.id];
- this.notificationsService.success(this.translateService.get(this.messagePrefix + 'notification.deleted.success', { name: group.group.name }));
+ this.notificationsService.success(this.translateService.get(this.messagePrefix + 'notification.deleted.success', { name: this.dsoNameService.getName(group.group) }));
} else {
this.notificationsService.error(
- this.translateService.get(this.messagePrefix + 'notification.deleted.failure.title', { name: group.group.name }),
+ this.translateService.get(this.messagePrefix + 'notification.deleted.failure.title', { name: this.dsoNameService.getName(group.group) }),
this.translateService.get(this.messagePrefix + 'notification.deleted.failure.content', { cause: rd.errorMessage }));
}
});
diff --git a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts
index 5c6885ae72..6d3138987a 100644
--- a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts
+++ b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts
@@ -5,7 +5,7 @@ import {
DynamicFormLayout,
DynamicInputModel
} from '@ng-dynamic-forms/core';
-import { FormGroup } from '@angular/forms';
+import { UntypedFormGroup } from '@angular/forms';
import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { take } from 'rxjs/operators';
@@ -66,7 +66,7 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
/**
* A FormGroup that combines all inputs
*/
- formGroup: FormGroup;
+ formGroup: UntypedFormGroup;
/**
* An EventEmitter that's fired whenever the form is being submitted
diff --git a/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts b/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts
index 1c000c3c76..0beb306d6c 100644
--- a/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts
+++ b/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts
@@ -5,7 +5,7 @@ import {
DynamicFormLayout,
DynamicInputModel
} from '@ng-dynamic-forms/core';
-import { FormGroup } from '@angular/forms';
+import { UntypedFormGroup } from '@angular/forms';
import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { take } from 'rxjs/operators';
@@ -82,7 +82,7 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
/**
* A FormGroup that combines all inputs
*/
- formGroup: FormGroup;
+ formGroup: UntypedFormGroup;
/**
* An EventEmitter that's fired whenever the form is being submitted
diff --git a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts
index e478aa3ef3..ee3de42131 100644
--- a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts
+++ b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts
@@ -19,7 +19,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-
import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock';
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
import { AccessStatusDataService } from '../../../../../core/data/access-status-data.service';
-import { AccessStatusObject } from '../../../../../shared/object-list/access-status-badge/access-status.model';
+import { AccessStatusObject } from '../../../../../shared/object-collection/shared/badges/access-status-badge/access-status.model';
import { AuthService } from '../../../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../../../shared/testing/auth-service.stub';
import { FileService } from '../../../../../core/shared/file.service';
diff --git a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.ts b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.ts
index 1ab8fee8c2..dab6694f36 100644
--- a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.ts
+++ b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.ts
@@ -13,6 +13,7 @@ import { BitstreamDataService } from '../../../../../core/data/bitstream-data.se
import { GenericConstructor } from '../../../../../core/shared/generic-constructor';
import { ListableObjectDirective } from '../../../../../shared/object-collection/shared/listable-object/listable-object.directive';
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
+import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
@listableObjectComponent(ItemSearchResult, ViewMode.GridElement, Context.AdminSearch)
@Component({
@@ -28,12 +29,14 @@ export class ItemAdminSearchResultGridElementComponent extends SearchResultGridE
@ViewChild('badges', { static: true }) badges: ElementRef;
@ViewChild('buttons', { static: true }) buttons: ElementRef;
- constructor(protected truncatableService: TruncatableService,
- protected bitstreamDataService: BitstreamDataService,
- private themeService: ThemeService,
- private componentFactoryResolver: ComponentFactoryResolver
+ constructor(
+ public dsoNameService: DSONameService,
+ protected truncatableService: TruncatableService,
+ protected bitstreamDataService: BitstreamDataService,
+ private themeService: ThemeService,
+ private componentFactoryResolver: ComponentFactoryResolver,
) {
- super(truncatableService, bitstreamDataService);
+ super(dsoNameService, truncatableService, bitstreamDataService);
}
/**
diff --git a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-list-element/item-search-result/item-admin-search-result-list-element.component.html b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-list-element/item-search-result/item-admin-search-result-list-element.component.html
index 259512552c..991508335f 100644
--- a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-list-element/item-search-result/item-admin-search-result-list-element.component.html
+++ b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-list-element/item-search-result/item-admin-search-result-list-element.component.html
@@ -2,6 +2,5 @@
[viewMode]="viewModes.ListElement"
[index]="index"
[linkType]="linkType"
- [listID]="listID"
- [hideBadges]="true">
+ [listID]="listID">
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts
index bbb1df3c49..2eec0cfd0c 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts
@@ -82,7 +82,7 @@ export class SupervisionOrderGroupSelectorComponent {
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData) => {
if (rd.state === 'Success') {
- this.notificationsService.success(this.translateService.get('supervision-group-selector.notification.create.success.title', { name: this.selectedGroup.name }));
+ this.notificationsService.success(this.translateService.get('supervision-group-selector.notification.create.success.title', { name: this.dsoNameService.getName(this.selectedGroup) }));
this.create.emit(rd.payload);
this.close();
} else {
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.html b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.html
index fa6a2eafff..84d8c052cd 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.html
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.html
@@ -7,7 +7,7 @@
- {{supervisionOrder.group.name}}
+ {{ dsoNameService.getName(supervisionOrder.group) }}
×
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.ts
index 11b6400ffd..93c6441e92 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-status/supervision-order-status.component.ts
@@ -8,6 +8,7 @@ import { Group } from '../../../../../../core/eperson/models/group.model';
import { getFirstCompletedRemoteData } from '../../../../../../core/shared/operators';
import { isNotEmpty } from '../../../../../../shared/empty.util';
import { RemoteData } from '../../../../../../core/data/remote-data';
+import { DSONameService } from '../../../../../../core/breadcrumbs/dso-name.service';
export interface SupervisionOrderListEntry {
supervisionOrder: SupervisionOrder;
@@ -33,6 +34,11 @@ export class SupervisionOrderStatusComponent implements OnChanges {
@Output() delete: EventEmitter = new EventEmitter();
+ constructor(
+ public dsoNameService: DSONameService,
+ ) {
+ }
+
ngOnChanges(changes: SimpleChanges): void {
if (changes && changes.supervisionOrderList) {
this.getSupervisionOrderEntries(changes.supervisionOrderList.currentValue)
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.spec.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.spec.ts
index 628fc3f89c..a8f0581ec0 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.spec.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.spec.ts
@@ -11,7 +11,7 @@ import { URLCombiner } from '../../../../../core/url-combiner/url-combiner';
import { WorkspaceItemAdminWorkflowActionsComponent } from './workspace-item-admin-workflow-actions.component';
import { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model';
import {
- getWorkflowItemDeleteRoute,
+ getWorkspaceItemDeleteRoute,
} from '../../../../../workflowitems-edit-page/workflowitems-edit-page-routing-paths';
import { Item } from '../../../../../core/shared/item.model';
import { RemoteData } from '../../../../../core/data/remote-data';
@@ -83,7 +83,7 @@ describe('WorkspaceItemAdminWorkflowActionsComponent', () => {
it('should render a delete button with the correct link', () => {
const button = fixture.debugElement.query(By.css('a.delete-link'));
const link = button.nativeElement.href;
- expect(link).toContain(new URLCombiner(getWorkflowItemDeleteRoute(wsi.id)).toString());
+ expect(link).toContain(new URLCombiner(getWorkspaceItemDeleteRoute(wsi.id)).toString());
});
it('should render a policies button with the correct link', () => {
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts
index adbd421628..36678460da 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts
@@ -11,7 +11,7 @@ import {
SupervisionOrderGroupSelectorComponent
} from './supervision-order-group-selector/supervision-order-group-selector.component';
import {
- getWorkflowItemDeleteRoute
+ getWorkspaceItemDeleteRoute
} from '../../../../../workflowitems-edit-page/workflowitems-edit-page-routing-paths';
import { ITEM_EDIT_AUTHORIZATIONS_PATH } from '../../../../../item-page/edit-item-page/edit-item-page.routing-paths';
import { WorkspaceItem } from '../../../../../core/submission/models/workspaceitem.model';
@@ -105,10 +105,10 @@ export class WorkspaceItemAdminWorkflowActionsComponent implements OnInit {
}
/**
- * Returns the path to the delete page of this workflow item
+ * Returns the path to the delete page of this workspace item
*/
getDeleteRoute(): string {
- return getWorkflowItemDeleteRoute(this.wsi.id);
+ return getWorkspaceItemDeleteRoute(this.wsi.id);
}
/**
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.ts
index 68f10916d5..fd9d21e227 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workflow-item/workflow-item-search-result-admin-workflow-grid-element.component.ts
@@ -23,6 +23,7 @@ import {
import { take } from 'rxjs/operators';
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
+import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch)
@Component({
@@ -55,13 +56,14 @@ export class WorkflowItemSearchResultAdminWorkflowGridElementComponent extends S
public item$: Observable- ;
constructor(
+ public dsoNameService: DSONameService,
private componentFactoryResolver: ComponentFactoryResolver,
private linkService: LinkService,
protected truncatableService: TruncatableService,
private themeService: ThemeService,
protected bitstreamDataService: BitstreamDataService
) {
- super(truncatableService, bitstreamDataService);
+ super(dsoNameService, truncatableService, bitstreamDataService);
}
/**
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workspace-item/workspace-item-search-result-admin-workflow-grid-element.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workspace-item/workspace-item-search-result-admin-workflow-grid-element.component.ts
index f18c18ca1c..d6f39e79fe 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workspace-item/workspace-item-search-result-admin-workflow-grid-element.component.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/workspace-item/workspace-item-search-result-admin-workflow-grid-element.component.ts
@@ -1,4 +1,4 @@
-import { Component, ComponentFactoryResolver, ElementRef, ViewChild } from '@angular/core';
+import { Component, ComponentFactoryResolver, ElementRef, ViewChild, OnInit } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, mergeMap, take, tap } from 'rxjs/operators';
@@ -36,6 +36,7 @@ import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
import { SupervisionOrder } from '../../../../../core/supervision-order/models/supervision-order.model';
import { PaginatedList } from '../../../../../core/data/paginated-list.model';
import { SupervisionOrderDataService } from '../../../../../core/supervision-order/supervision-order-data.service';
+import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch)
@Component({
@@ -46,7 +47,7 @@ import { SupervisionOrderDataService } from '../../../../../core/supervision-ord
/**
* The component for displaying a grid element for an workflow item on the admin workflow search page
*/
-export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent {
+export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent implements OnInit {
/**
* The item linked to the workspace item
@@ -79,6 +80,7 @@ export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends
@ViewChild('buttons', { static: true }) buttons: ElementRef;
constructor(
+ public dsoNameService: DSONameService,
private componentFactoryResolver: ComponentFactoryResolver,
private linkService: LinkService,
protected truncatableService: TruncatableService,
@@ -86,7 +88,7 @@ export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends
protected bitstreamDataService: BitstreamDataService,
protected supervisionOrderDataService: SupervisionOrderDataService,
) {
- super(truncatableService, bitstreamDataService);
+ super(dsoNameService, truncatableService, bitstreamDataService);
}
/**
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component.ts
index b1db3f99ce..d0e773d696 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component.ts
@@ -39,7 +39,7 @@ export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends S
constructor(private linkService: LinkService,
protected truncatableService: TruncatableService,
- protected dsoNameService: DSONameService,
+ public dsoNameService: DSONameService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(truncatableService, dsoNameService, appConfig);
diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workspace-item/workspace-item-search-result-admin-workflow-list-element.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workspace-item/workspace-item-search-result-admin-workflow-list-element.component.ts
index 597ed8bbe7..3d6d1c8e44 100644
--- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workspace-item/workspace-item-search-result-admin-workflow-list-element.component.ts
+++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/workspace-item/workspace-item-search-result-admin-workflow-list-element.component.ts
@@ -59,7 +59,7 @@ export class WorkspaceItemSearchResultAdminWorkflowListElementComponent extends
public supervisionOrder$: BehaviorSubject = new BehaviorSubject([]);
constructor(private linkService: LinkService,
- protected dsoNameService: DSONameService,
+ public dsoNameService: DSONameService,
protected supervisionOrderDataService: SupervisionOrderDataService,
protected truncatableService: TruncatableService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index b69e47c82c..deb68f1ea9 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -209,7 +209,7 @@ import { ThemedPageErrorComponent } from './page-error/themed-page-error.compone
{
path: REQUEST_COPY_MODULE_PATH,
loadChildren: () => import('./request-copy/request-copy.module').then((m) => m.RequestCopyModule),
- canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard]
+ canActivate: [EndUserAgreementCurrentUserGuard]
},
{
path: FORBIDDEN_PATH,
diff --git a/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html b/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html
index eddc5e345a..af3afe98f8 100644
--- a/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html
+++ b/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html
@@ -1,5 +1,5 @@
- {{'bitstream.download.page' | translate:{bitstream: (bitstream$ | async)?.name} }}
+ {{'bitstream.download.page' | translate:{ bitstream: dsoNameService.getName((bitstream$ | async)) } }}
|
diff --git a/src/app/shared/object-select/item-select/item-select.component.ts b/src/app/shared/object-select/item-select/item-select.component.ts
index 5cf32c2953..dd0266ff83 100644
--- a/src/app/shared/object-select/item-select/item-select.component.ts
+++ b/src/app/shared/object-select/item-select/item-select.component.ts
@@ -8,6 +8,7 @@ import { getAllSucceededRemoteDataPayload } from '../../../core/shared/operators
import { map } from 'rxjs/operators';
import { getItemPageRoute } from '../../../item-page/item-page-routing-paths';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
+import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-item-select',
@@ -34,8 +35,11 @@ export class ItemSelectComponent extends ObjectSelectComponent- {
[itemId: string]: string
}>;
- constructor(protected objectSelectService: ObjectSelectService,
- protected authorizationService: AuthorizationDataService ) {
+ constructor(
+ protected objectSelectService: ObjectSelectService,
+ protected authorizationService: AuthorizationDataService,
+ public dsoNameService: DSONameService,
+ ) {
super(objectSelectService, authorizationService);
}
diff --git a/src/app/shared/search-form/search-form.component.html b/src/app/shared/search-form/search-form.component.html
index 226962cc61..f916785804 100644
--- a/src/app/shared/search-form/search-form.component.html
+++ b/src/app/shared/search-form/search-form.component.html
@@ -2,9 +2,14 @@
diff --git a/src/app/shared/search/search-sidebar/themed-search-sidebar.component.ts b/src/app/shared/search/search-sidebar/themed-search-sidebar.component.ts
new file mode 100644
index 0000000000..935f797532
--- /dev/null
+++ b/src/app/shared/search/search-sidebar/themed-search-sidebar.component.ts
@@ -0,0 +1,54 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { ThemedComponent } from '../../theme-support/themed.component';
+import { SearchSidebarComponent } from './search-sidebar.component';
+import { SearchConfigurationOption } from '../search-switch-configuration/search-configuration-option.model';
+import { SortOptions } from '../../../core/cache/models/sort-options.model';
+import { ViewMode } from '../../../core/shared/view-mode.model';
+import { PaginatedSearchOptions } from '../models/paginated-search-options.model';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { RemoteData } from '../../../core/data/remote-data';
+import { SearchFilterConfig } from '../models/search-filter-config.model';
+
+/**
+ * Themed wrapper for SearchSidebarComponent
+ */
+@Component({
+ selector: 'ds-themed-search-sidebar',
+ styleUrls: [],
+ templateUrl: '../../theme-support/themed.component.html',
+})
+export class ThemedSearchSidebarComponent extends ThemedComponent {
+
+ @Input() configuration;
+ @Input() configurationList: SearchConfigurationOption[];
+ @Input() currentScope: string;
+ @Input() currentSortOption: SortOptions;
+ @Input() filters: Observable>;
+ @Input() resultCount;
+ @Input() viewModeList: ViewMode[];
+ @Input() showViewModes = true;
+ @Input() inPlaceSearch;
+ @Input() searchOptions: PaginatedSearchOptions;
+ @Input() sortOptionsList: SortOptions[];
+ @Input() refreshFilters: BehaviorSubject;
+ @Output() toggleSidebar = new EventEmitter();
+ @Output() changeConfiguration: EventEmitter = new EventEmitter();
+ @Output() changeViewMode: EventEmitter = new EventEmitter();
+
+ protected inAndOutputNames: (keyof SearchSidebarComponent & keyof this)[] = [
+ 'configuration', 'configurationList', 'currentScope', 'currentSortOption',
+ 'resultCount', 'filters', 'viewModeList', 'showViewModes', 'inPlaceSearch',
+ 'searchOptions', 'sortOptionsList', 'refreshFilters', 'toggleSidebar', 'changeConfiguration', 'changeViewMode'];
+
+ protected getComponentName(): string {
+ return 'SearchSidebarComponent';
+ }
+
+ protected importThemedComponent(themeName: string): Promise {
+ return import(`../../../../themes/${themeName}/app/shared/search/search-sidebar/search-sidebar.component`);
+ }
+
+ protected importUnthemedComponent(): Promise {
+ return import('./search-sidebar.component');
+ }
+}
diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html
index ed834c65bc..e7523cd277 100644
--- a/src/app/shared/search/search.component.html
+++ b/src/app/shared/search/search.component.html
@@ -46,7 +46,7 @@
-
-
+
diff --git a/src/app/shared/search/search.component.spec.ts b/src/app/shared/search/search.component.spec.ts
index 3f00cf354f..d0d9bdda86 100644
--- a/src/app/shared/search/search.component.spec.ts
+++ b/src/app/shared/search/search.component.spec.ts
@@ -31,6 +31,8 @@ import { SearchObjects } from './models/search-objects.model';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { SearchFilterConfig } from './models/search-filter-config.model';
import { FilterType } from './models/filter-type.model';
+import { getCommunityPageRoute } from '../../community-page/community-page-routing-paths';
+import { getCollectionPageRoute } from '../../collection-page/collection-page-routing-paths';
let comp: SearchComponent;
let fixture: ComponentFixture;
@@ -101,8 +103,9 @@ const searchServiceStub = jasmine.createSpyObj('SearchService', {
search: mockResultsRD$,
getSearchLink: '/search',
getScopes: observableOf(['test-scope']),
- getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig)
-});
+ getSearchConfigurationFor: createSuccessfulRemoteDataObject$(searchConfig),
+ trackSearch: {},
+}) as SearchService;
const configurationParam = 'default';
const queryParam = 'test query';
const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
@@ -327,4 +330,64 @@ describe('SearchComponent', () => {
}));
});
+
+ describe('getDsoUUIDFromUrl', () => {
+ let url: string;
+ let result: string;
+
+ describe('when the navigated URL is an entity route', () => {
+ beforeEach(() => {
+ url = '/entities/publication/9a364471-3f19-4e7b-916a-a24a44ff48e3';
+ result = (comp as any).getDsoUUIDFromUrl(url);
+ });
+
+ it('should return the UUID', () => {
+ expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
+ });
+ });
+
+ describe('when the navigated URL is a community route', () => {
+ beforeEach(() => {
+ url = `${getCommunityPageRoute('9a364471-3f19-4e7b-916a-a24a44ff48e3')}`;
+ result = (comp as any).getDsoUUIDFromUrl(url);
+ });
+
+ it('should return the UUID', () => {
+ expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
+ });
+ });
+
+ describe('when the navigated URL is a collection route', () => {
+ beforeEach(() => {
+ url = `${getCollectionPageRoute('9a364471-3f19-4e7b-916a-a24a44ff48e3')}`;
+ result = (comp as any).getDsoUUIDFromUrl(url);
+ });
+
+ it('should return the UUID', () => {
+ expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
+ });
+ });
+
+ describe('when the navigated URL is an item route', () => {
+ beforeEach(() => {
+ url = '/items/9a364471-3f19-4e7b-916a-a24a44ff48e3';
+ result = (comp as any).getDsoUUIDFromUrl(url);
+ });
+
+ it('should return the UUID', () => {
+ expect(result).toEqual('9a364471-3f19-4e7b-916a-a24a44ff48e3');
+ });
+ });
+
+ describe('when the navigated URL is an invalid route', () => {
+ beforeEach(() => {
+ url = '/invalid/object/route/9a364471-3f19-4e7b-916a-a24a44ff48e3';
+ result = (comp as any).getDsoUUIDFromUrl(url);
+ });
+
+ it('should return null', () => {
+ expect(result).toBeNull();
+ });
+ });
+ });
});
diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts
index a5b9fb9c7d..2195d428c9 100644
--- a/src/app/shared/search/search.component.ts
+++ b/src/app/shared/search/search.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
-import { Router } from '@angular/router';
+import { NavigationStart, Router } from '@angular/router';
import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators';
@@ -11,7 +11,7 @@ import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { pushInOut } from '../animations/push';
import { HostWindowService } from '../host-window.service';
import { SidebarService } from '../sidebar/sidebar.service';
-import { hasValue } from '../empty.util';
+import { hasValue, hasValueOperator, isNotEmpty } from '../empty.util';
import { RouteService } from '../../core/services/route.service';
import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component';
import { PaginatedSearchOptions } from './models/paginated-search-options.model';
@@ -35,6 +35,9 @@ import { environment } from 'src/environments/environment';
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
import { SearchFilterConfig } from './models/search-filter-config.model';
import { WorkspaceItem } from '../..//core/submission/models/workspaceitem.model';
+import { ITEM_MODULE_PATH } from '../../item-page/item-page-routing-paths';
+import { COLLECTION_MODULE_PATH } from '../../collection-page/collection-page-routing-paths';
+import { COMMUNITY_MODULE_PATH } from '../../community-page/community-page-routing-paths';
@Component({
selector: 'ds-search',
@@ -229,9 +232,21 @@ export class SearchComponent implements OnInit {
searchLink: string;
/**
- * Subscription to unsubscribe from
+ * Regex to match UUIDs
*/
- sub: Subscription;
+ uuidRegex = /\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/g;
+
+ /**
+ * List of paths that are considered to be the start of a route to an object page (excluding "/", e.g. "items")
+ * These are expected to end on an object UUID
+ * If they match the route we're navigating to, an object property will be added to the search event sent
+ */
+ allowedObjectPaths: string[] = ['entities', ITEM_MODULE_PATH, COLLECTION_MODULE_PATH, COMMUNITY_MODULE_PATH];
+
+ /**
+ * Subscriptions to unsubscribe from
+ */
+ subs: Subscription[] = [];
/**
* Emits an event with the current search result entries
@@ -301,7 +316,7 @@ export class SearchComponent implements OnInit {
);
const searchOptions$: Observable = this.getSearchOptions().pipe(distinctUntilChanged());
- this.sub = combineLatest([configuration$, searchSortOptions$, searchOptions$, sortOption$]).pipe(
+ this.subs.push(combineLatest([configuration$, searchSortOptions$, searchOptions$, sortOption$]).pipe(
filter(([configuration, searchSortOptions, searchOptions, sortOption]: [string, SortOptions[], PaginatedSearchOptions, SortOptions]) => {
// filter for search options related to instanced paginated id
return searchOptions.pagination.id === this.paginationId;
@@ -332,7 +347,9 @@ export class SearchComponent implements OnInit {
this.retrieveSearchResults(newSearchOptions);
this.retrieveFilters(searchOptions);
}
- });
+ }));
+
+ this.subscribeToRoutingEvents();
}
/**
@@ -374,12 +391,10 @@ export class SearchComponent implements OnInit {
}
/**
- * Unsubscribe from the subscription
+ * Unsubscribe from the subscriptions
*/
ngOnDestroy(): void {
- if (hasValue(this.sub)) {
- this.sub.unsubscribe();
- }
+ this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
}
/**
@@ -440,6 +455,43 @@ export class SearchComponent implements OnInit {
});
}
+ /**
+ * Subscribe to routing events to detect when a user moves away from the search page
+ * When the user is routing to an object page, it needs to send out a separate search event containing that object's UUID
+ * This method should only be called once and is essentially what SearchTrackingComponent used to do (now removed)
+ * @private
+ */
+ private subscribeToRoutingEvents() {
+ this.subs.push(
+ this.router.events.pipe(
+ filter((event) => event instanceof NavigationStart),
+ map((event: NavigationStart) => this.getDsoUUIDFromUrl(event.url)),
+ hasValueOperator(),
+ ).subscribe((uuid) => {
+ if (this.resultsRD$.value.hasSucceeded) {
+ this.service.trackSearch(this.searchOptions$.value, this.resultsRD$.value.payload as SearchObjects, uuid);
+ }
+ }),
+ );
+ }
+
+ /**
+ * Get the UUID from a DSO url
+ * Return null if the url isn't an object page (allowedObjectPaths) or the UUID couldn't be found
+ * @param url
+ */
+ private getDsoUUIDFromUrl(url: string): string {
+ if (isNotEmpty(url)) {
+ if (this.allowedObjectPaths.some((path) => url.startsWith(`/${path}`))) {
+ const uuid = url.substring(url.lastIndexOf('/') + 1);
+ if (uuid.match(this.uuidRegex)) {
+ return uuid;
+ }
+ }
+ }
+ return null;
+ }
+
/**
* Check if the sidebar is collapsed
* @returns {Observable} emits true if the sidebar is currently collapsed, false if it is expanded
diff --git a/src/app/shared/search/search.module.ts b/src/app/shared/search/search.module.ts
index 713b9925a6..69500999a8 100644
--- a/src/app/shared/search/search.module.ts
+++ b/src/app/shared/search/search.module.ts
@@ -32,6 +32,8 @@ import { ThemedSearchComponent } from './themed-search.component';
import { ThemedSearchResultsComponent } from './search-results/themed-search-results.component';
import { ThemedSearchSettingsComponent } from './search-settings/themed-search-settings.component';
import { NouisliderModule } from 'ng2-nouislider';
+import { ThemedSearchFiltersComponent } from './search-filters/themed-search-filters.component';
+import { ThemedSearchSidebarComponent } from './search-sidebar/themed-search-sidebar.component';
const COMPONENTS = [
SearchComponent,
@@ -58,6 +60,8 @@ const COMPONENTS = [
ThemedConfigurationSearchPageComponent,
ThemedSearchResultsComponent,
ThemedSearchSettingsComponent,
+ ThemedSearchFiltersComponent,
+ ThemedSearchSidebarComponent,
];
const ENTRY_COMPONENTS = [
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index dafbcb703d..5245f244c4 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -50,6 +50,7 @@ import { ErrorComponent } from './error/error.component';
import { LoadingComponent } from './loading/loading.component';
import { PaginationComponent } from './pagination/pagination.component';
import { ThumbnailComponent } from '../thumbnail/thumbnail.component';
+import { ThemedThumbnailComponent } from '../thumbnail/themed-thumbnail.component';
import { SearchFormComponent } from './search-form/search-form.component';
import { ThemedSearchFormComponent } from './search-form/themed-search-form.component';
import {
@@ -164,8 +165,8 @@ import {
DsoInputSuggestionsComponent
} from './input-suggestions/dso-input-suggestions/dso-input-suggestions.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 { AccessStatusBadgeComponent } from './object-list/access-status-badge/access-status-badge.component';
+import { TypeBadgeComponent } from './object-collection/shared/badges/type-badge/type-badge.component';
+import { AccessStatusBadgeComponent } from './object-collection/shared/badges/access-status-badge/access-status-badge.component';
import {
MetadataRepresentationLoaderComponent
} from './metadata-representation/metadata-representation-loader.component';
@@ -251,6 +252,16 @@ import {
} from './object-list/listable-notification-object/listable-notification-object.component';
import { ThemedCollectionDropdownComponent } from './collection-dropdown/themed-collection-dropdown.component';
import { MetadataFieldWrapperComponent } from './metadata-field-wrapper/metadata-field-wrapper.component';
+
+import { StatusBadgeComponent } from './object-collection/shared/badges/status-badge/status-badge.component';
+import { BadgesComponent } from './object-collection/shared/badges/badges.component';
+import { ThemedBadgesComponent } from './object-collection/shared/badges/themed-badges.component';
+import { ThemedStatusBadgeComponent } from './object-collection/shared/badges/status-badge/themed-status-badge.component';
+import { ThemedTypeBadgeComponent } from './object-collection/shared/badges/type-badge/themed-type-badge.component';
+import { ThemedMyDSpaceStatusBadgeComponent } from './object-collection/shared/badges/my-dspace-status-badge/themed-my-dspace-status-badge.component';
+import { ThemedAccessStatusBadgeComponent } from './object-collection/shared/badges/access-status-badge/themed-access-status-badge.component';
+import { MyDSpaceStatusBadgeComponent } from './object-collection/shared/badges/my-dspace-status-badge/my-dspace-status-badge.component';
+
import { ShortNumberPipe } from './utils/short-number.pipe';
import {
LogInExternalProviderComponent
@@ -338,6 +349,9 @@ const COMPONENTS = [
PageWithSidebarComponent,
SidebarDropdownComponent,
ThumbnailComponent,
+ ThemedThumbnailComponent,
+ MyDSpaceStatusBadgeComponent,
+ ThemedMyDSpaceStatusBadgeComponent,
ViewModeSwitchComponent,
TruncatableComponent,
TruncatablePartComponent,
@@ -353,6 +367,13 @@ const COMPONENTS = [
ComcolMetadataComponent,
TypeBadgeComponent,
AccessStatusBadgeComponent,
+ ThemedAccessStatusBadgeComponent,
+ ThemedTypeBadgeComponent,
+ StatusBadgeComponent,
+ ThemedStatusBadgeComponent,
+ BadgesComponent,
+ ThemedBadgesComponent,
+
ItemSelectComponent,
CollectionSelectComponent,
MetadataRepresentationLoaderComponent,
diff --git a/src/app/shared/starts-with/starts-with-abstract.component.ts b/src/app/shared/starts-with/starts-with-abstract.component.ts
index 3b35a11269..26140dcc6d 100644
--- a/src/app/shared/starts-with/starts-with-abstract.component.ts
+++ b/src/app/shared/starts-with/starts-with-abstract.component.ts
@@ -1,7 +1,7 @@
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
-import { FormControl, FormGroup } from '@angular/forms';
+import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { hasValue } from '../empty.util';
import { PaginationService } from '../../core/pagination/pagination.service';
@@ -21,7 +21,7 @@ export abstract class StartsWithAbstractComponent implements OnInit, OnDestroy {
/**
* The formdata controlling the StartsWith input
*/
- formData: FormGroup;
+ formData: UntypedFormGroup;
/**
* List of subscriptions
@@ -43,8 +43,8 @@ export abstract class StartsWithAbstractComponent implements OnInit, OnDestroy {
}
})
);
- this.formData = new FormGroup({
- startsWith: new FormControl()
+ this.formData = new UntypedFormGroup({
+ startsWith: new UntypedFormControl()
});
}
diff --git a/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html b/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html
index a71498f002..287175bfa1 100644
--- a/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html
+++ b/src/app/shared/subscriptions/subscription-modal/subscription-modal.component.html
@@ -6,8 +6,8 @@
- {{dso.name}}
-
+ {{ dsoNameService.getName(dso) }}
+
|