{{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..fb045ebb88 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);
}
@@ -284,14 +287,17 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
/**
* This method will set everything to stale, which will cause the lists on this page to update.
*/
- reset() {
+ reset(): void {
this.epersonService.getBrowseEndpoint().pipe(
- take(1)
- ).subscribe((href: string) => {
- this.requestService.setStaleByHrefSubstring(href).pipe(take(1)).subscribe(() => {
- this.epersonService.cancelEditEPerson();
- this.isEPersonFormShown = false;
- });
+ take(1),
+ switchMap((href: string) => {
+ return this.requestService.setStaleByHrefSubstring(href).pipe(
+ take(1),
+ );
+ })
+ ).subscribe(()=>{
+ this.epersonService.cancelEditEPerson();
+ this.isEPersonFormShown = false;
});
}
}
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..d009d56058 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,
@@ -8,7 +8,7 @@ import {
} from '@ng-dynamic-forms/core';
import { TranslateService } from '@ngx-translate/core';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
-import { debounceTime, switchMap, take } from 'rxjs/operators';
+import { debounceTime, finalize, map, switchMap, take } from 'rxjs/operators';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
@@ -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();
}
});
@@ -461,31 +463,42 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
* Deletes the EPerson from the Repository. The EPerson will be the only that this form is showing.
* It'll either show a success or error message depending on whether the delete was successful or not.
*/
- delete() {
- this.epersonService.getActiveEPerson().pipe(take(1)).subscribe((eperson: EPerson) => {
- const modalRef = this.modalService.open(ConfirmationModalComponent);
- modalRef.componentInstance.dso = eperson;
- modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-eperson.header';
- modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-eperson.info';
- modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-eperson.cancel';
- modalRef.componentInstance.confirmLabel = 'confirmation-modal.delete-eperson.confirm';
- modalRef.componentInstance.brandColor = 'danger';
- modalRef.componentInstance.confirmIcon = 'fas fa-trash';
- modalRef.componentInstance.response.pipe(take(1)).subscribe((confirm: boolean) => {
- if (confirm) {
- 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.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);
- }
- this.cancelForm.emit();
- });
- }
- }
- });
+ delete(): void {
+ this.epersonService.getActiveEPerson().pipe(
+ take(1),
+ switchMap((eperson: EPerson) => {
+ const modalRef = this.modalService.open(ConfirmationModalComponent);
+ modalRef.componentInstance.dso = eperson;
+ modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-eperson.header';
+ modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-eperson.info';
+ modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-eperson.cancel';
+ modalRef.componentInstance.confirmLabel = 'confirmation-modal.delete-eperson.confirm';
+ modalRef.componentInstance.brandColor = 'danger';
+ modalRef.componentInstance.confirmIcon = 'fas fa-trash';
+
+ return modalRef.componentInstance.response.pipe(
+ take(1),
+ switchMap((confirm: boolean) => {
+ if (confirm && hasValue(eperson.id)) {
+ this.canDelete$ = observableOf(false);
+ return this.epersonService.deleteEPerson(eperson).pipe(
+ getFirstCompletedRemoteData(),
+ map((restResponse: RemoteData) => ({ restResponse, eperson }))
+ );
+ } else {
+ return observableOf(null);
+ }
+ }),
+ finalize(() => this.canDelete$ = observableOf(true))
+ );
+ })
+ ).subscribe(({ restResponse, eperson }: { restResponse: RemoteData | null, eperson: EPerson }) => {
+ if (restResponse?.hasSucceeded) {
+ this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: this.dsoNameService.getName(eperson) }));
+ } else {
+ this.notificationsService.error(`Error occurred when trying to delete EPerson with id: ${eperson?.id} with code: ${restResponse?.statusCode} and message: ${restResponse?.errorMessage}`);
+ }
+ this.cancelForm.emit();
});
}
@@ -521,7 +534,6 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
* Cancel the current edit when component is destroyed & unsub all subscriptions
*/
ngOnDestroy(): void {
- this.onCancel();
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
this.paginationService.clearPagination(this.config.id);
if (hasValue(this.emailValueChangeSubscribe)) {
@@ -554,7 +566,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-import-batch-page/batch-import-page.component.html b/src/app/admin/admin-import-batch-page/batch-import-page.component.html
index dbc8c74437..1092443436 100644
--- a/src/app/admin/admin-import-batch-page/batch-import-page.component.html
+++ b/src/app/admin/admin-import-batch-page/batch-import-page.component.html
@@ -20,12 +20,29 @@
+
+
+ {{'admin.batch-import.page.toggle.help' | translate}}
+
+
+
+
+
+
+
diff --git a/src/app/admin/admin-import-batch-page/batch-import-page.component.spec.ts b/src/app/admin/admin-import-batch-page/batch-import-page.component.spec.ts
index 36ba1137c9..341aefb704 100644
--- a/src/app/admin/admin-import-batch-page/batch-import-page.component.spec.ts
+++ b/src/app/admin/admin-import-batch-page/batch-import-page.component.spec.ts
@@ -86,10 +86,18 @@ describe('BatchImportPageComponent', () => {
let fileMock: File;
beforeEach(() => {
+ component.isUpload = true;
fileMock = new File([''], 'filename.zip', { type: 'application/zip' });
component.setFile(fileMock);
});
+ it('should show the file dropzone', () => {
+ const fileDropzone = fixture.debugElement.query(By.css('[data-test="file-dropzone"]'));
+ const fileUrlInput = fixture.debugElement.query(By.css('[data-test="file-url-input"]'));
+ expect(fileDropzone).toBeTruthy();
+ expect(fileUrlInput).toBeFalsy();
+ });
+
describe('if proceed button is pressed without validate only', () => {
beforeEach(fakeAsync(() => {
component.validateOnly = false;
@@ -99,9 +107,9 @@ describe('BatchImportPageComponent', () => {
}));
it('metadata-import script is invoked with --zip fileName and the mockFile', () => {
const parameterValues: ProcessParameter[] = [
- Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' }),
+ Object.assign(new ProcessParameter(), { name: '--add' }),
+ Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' })
];
- parameterValues.push(Object.assign(new ProcessParameter(), { name: '--add' }));
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [fileMock]);
});
it('success notification is shown', () => {
@@ -121,8 +129,8 @@ describe('BatchImportPageComponent', () => {
}));
it('metadata-import script is invoked with --zip fileName and the mockFile and -v validate-only', () => {
const parameterValues: ProcessParameter[] = [
- Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' }),
Object.assign(new ProcessParameter(), { name: '--add' }),
+ Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' }),
Object.assign(new ProcessParameter(), { name: '-v', value: true }),
];
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [fileMock]);
@@ -148,4 +156,77 @@ describe('BatchImportPageComponent', () => {
});
});
});
+
+ describe('if url is set', () => {
+ beforeEach(fakeAsync(() => {
+ component.isUpload = false;
+ component.fileURL = 'example.fileURL.com';
+ fixture.detectChanges();
+ }));
+
+ it('should show the file url input', () => {
+ const fileDropzone = fixture.debugElement.query(By.css('[data-test="file-dropzone"]'));
+ const fileUrlInput = fixture.debugElement.query(By.css('[data-test="file-url-input"]'));
+ expect(fileDropzone).toBeFalsy();
+ expect(fileUrlInput).toBeTruthy();
+ });
+
+ describe('if proceed button is pressed without validate only', () => {
+ beforeEach(fakeAsync(() => {
+ component.validateOnly = false;
+ const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
+ proceed.click();
+ fixture.detectChanges();
+ }));
+ it('metadata-import script is invoked with --url and the file url', () => {
+ const parameterValues: ProcessParameter[] = [
+ Object.assign(new ProcessParameter(), { name: '--add' }),
+ Object.assign(new ProcessParameter(), { name: '--url', value: 'example.fileURL.com' })
+ ];
+ expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [null]);
+ });
+ it('success notification is shown', () => {
+ expect(notificationService.success).toHaveBeenCalled();
+ });
+ it('redirected to process page', () => {
+ expect(router.navigateByUrl).toHaveBeenCalledWith('/processes/46');
+ });
+ });
+
+ describe('if proceed button is pressed with validate only', () => {
+ beforeEach(fakeAsync(() => {
+ component.validateOnly = true;
+ const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
+ proceed.click();
+ fixture.detectChanges();
+ }));
+ it('metadata-import script is invoked with --url and the file url and -v validate-only', () => {
+ const parameterValues: ProcessParameter[] = [
+ Object.assign(new ProcessParameter(), { name: '--add' }),
+ Object.assign(new ProcessParameter(), { name: '--url', value: 'example.fileURL.com' }),
+ Object.assign(new ProcessParameter(), { name: '-v', value: true }),
+ ];
+ expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [null]);
+ });
+ it('success notification is shown', () => {
+ expect(notificationService.success).toHaveBeenCalled();
+ });
+ it('redirected to process page', () => {
+ expect(router.navigateByUrl).toHaveBeenCalledWith('/processes/46');
+ });
+ });
+
+ describe('if proceed is pressed; but script invoke fails', () => {
+ beforeEach(fakeAsync(() => {
+ jasmine.getEnv().allowRespy(true);
+ spyOn(scriptService, 'invoke').and.returnValue(createFailedRemoteDataObject$('Error', 500));
+ const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
+ proceed.click();
+ fixture.detectChanges();
+ }));
+ it('error notification is shown', () => {
+ expect(notificationService.error).toHaveBeenCalled();
+ });
+ });
+ });
});
diff --git a/src/app/admin/admin-import-batch-page/batch-import-page.component.ts b/src/app/admin/admin-import-batch-page/batch-import-page.component.ts
index 95e69277a8..673e1f23f5 100644
--- a/src/app/admin/admin-import-batch-page/batch-import-page.component.ts
+++ b/src/app/admin/admin-import-batch-page/batch-import-page.component.ts
@@ -8,7 +8,7 @@ import { ProcessParameter } from '../../process-page/processes/process-parameter
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { RemoteData } from '../../core/data/remote-data';
import { Process } from '../../process-page/processes/process.model';
-import { isNotEmpty } from '../../shared/empty.util';
+import { isEmpty, isNotEmpty } from '../../shared/empty.util';
import { getProcessDetailRoute } from '../../process-page/process-page-routing.paths';
import {
ImportBatchSelectorComponent
@@ -32,11 +32,22 @@ export class BatchImportPageComponent {
* The validate only flag
*/
validateOnly = true;
+
/**
* dso object for community or collection
*/
dso: DSpaceObject = null;
+ /**
+ * The flag between upload and url
+ */
+ isUpload = true;
+
+ /**
+ * File URL when flag is for url
+ */
+ fileURL: string;
+
public constructor(private location: Location,
protected translate: TranslateService,
protected notificationsService: NotificationsService,
@@ -72,13 +83,22 @@ export class BatchImportPageComponent {
* Starts import-metadata script with --zip fileName (and the selected file)
*/
public importMetadata() {
- if (this.fileObject == null) {
- this.notificationsService.error(this.translate.get('admin.metadata-import.page.error.addFile'));
+ if (this.fileObject == null && isEmpty(this.fileURL)) {
+ if (this.isUpload) {
+ this.notificationsService.error(this.translate.get('admin.metadata-import.page.error.addFile'));
+ } else {
+ this.notificationsService.error(this.translate.get('admin.metadata-import.page.error.addFileUrl'));
+ }
} else {
const parameterValues: ProcessParameter[] = [
- Object.assign(new ProcessParameter(), { name: '--zip', value: this.fileObject.name }),
Object.assign(new ProcessParameter(), { name: '--add' })
];
+ if (this.isUpload) {
+ parameterValues.push(Object.assign(new ProcessParameter(), { name: '--zip', value: this.fileObject.name }));
+ } else {
+ this.fileObject = null;
+ parameterValues.push(Object.assign(new ProcessParameter(), { name: '--url', value: this.fileURL }));
+ }
if (this.dso) {
parameterValues.push(Object.assign(new ProcessParameter(), { name: '--collection', value: this.dso.uuid }));
}
@@ -127,4 +147,11 @@ export class BatchImportPageComponent {
removeDspaceObject(): void {
this.dso = null;
}
+
+ /**
+ * toggle the flag between upload and url
+ */
+ toggleUpload() {
+ this.isUpload = !this.isUpload;
+ }
}
diff --git a/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts
new file mode 100644
index 0000000000..870458fa9f
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts
@@ -0,0 +1,9 @@
+import { URLCombiner } from '../../core/url-combiner/url-combiner';
+import { getNotificationsModuleRoute } from '../admin-routing-paths';
+
+export const QUALITY_ASSURANCE_EDIT_PATH = 'quality-assurance';
+export const NOTIFICATIONS_RECITER_SUGGESTION_PATH = 'suggestion-targets';
+
+export function getQualityAssuranceRoute(id: string) {
+ return new URLCombiner(getNotificationsModuleRoute(), QUALITY_ASSURANCE_EDIT_PATH, id).toString();
+}
diff --git a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts
new file mode 100644
index 0000000000..60fa679777
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts
@@ -0,0 +1,100 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+
+import { AuthenticatedGuard } from '../../core/auth/authenticated.guard';
+import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
+import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service';
+import { NOTIFICATIONS_RECITER_SUGGESTION_PATH } from './admin-notifications-routing-paths';
+import { AdminNotificationsSuggestionTargetsPageComponent } from './admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component';
+import { AdminNotificationsSuggestionTargetsPageResolver } from './admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page-resolver.service';
+import { QUALITY_ASSURANCE_EDIT_PATH } from './admin-notifications-routing-paths';
+import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component';
+import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.component';
+import { AdminQualityAssuranceTopicsPageResolver } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service';
+import { AdminQualityAssuranceEventsPageResolver } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver';
+import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component';
+import { AdminQualityAssuranceSourcePageResolver } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service';
+import { SourceDataResolver } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover';
+
+@NgModule({
+ imports: [
+ RouterModule.forChild([
+ {
+ canActivate: [ AuthenticatedGuard ],
+ path: `${NOTIFICATIONS_RECITER_SUGGESTION_PATH}`,
+ component: AdminNotificationsSuggestionTargetsPageComponent,
+ pathMatch: 'full',
+ resolve: {
+ breadcrumb: I18nBreadcrumbResolver,
+ reciterSuggestionTargetParams: AdminNotificationsSuggestionTargetsPageResolver
+ },
+ data: {
+ title: 'admin.notifications.recitersuggestion.page.title',
+ breadcrumbKey: 'admin.notifications.recitersuggestion',
+ showBreadcrumbsFluid: false
+ }
+ },
+ {
+ canActivate: [ AuthenticatedGuard ],
+ path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId`,
+ component: AdminQualityAssuranceTopicsPageComponent,
+ pathMatch: 'full',
+ resolve: {
+ breadcrumb: I18nBreadcrumbResolver,
+ openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver
+ },
+ data: {
+ title: 'admin.quality-assurance.page.title',
+ breadcrumbKey: 'admin.quality-assurance',
+ showBreadcrumbsFluid: false
+ }
+ },
+ {
+ canActivate: [ AuthenticatedGuard ],
+ path: `${QUALITY_ASSURANCE_EDIT_PATH}`,
+ component: AdminQualityAssuranceSourcePageComponent,
+ pathMatch: 'full',
+ resolve: {
+ breadcrumb: I18nBreadcrumbResolver,
+ openaireQualityAssuranceSourceParams: AdminQualityAssuranceSourcePageResolver,
+ sourceData: SourceDataResolver
+ },
+ data: {
+ title: 'admin.notifications.source.breadcrumbs',
+ breadcrumbKey: 'admin.notifications.source',
+ showBreadcrumbsFluid: false
+ }
+ },
+ {
+ canActivate: [ AuthenticatedGuard ],
+ path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId/:topicId`,
+ component: AdminQualityAssuranceEventsPageComponent,
+ pathMatch: 'full',
+ resolve: {
+ breadcrumb: I18nBreadcrumbResolver,
+ openaireQualityAssuranceEventsParams: AdminQualityAssuranceEventsPageResolver
+ },
+ data: {
+ title: 'admin.notifications.event.page.title',
+ breadcrumbKey: 'admin.notifications.event',
+ showBreadcrumbsFluid: false
+ }
+ }
+ ])
+ ],
+ providers: [
+ I18nBreadcrumbResolver,
+ I18nBreadcrumbsService,
+ AdminNotificationsSuggestionTargetsPageResolver,
+ SourceDataResolver,
+ AdminQualityAssuranceSourcePageResolver,
+ AdminQualityAssuranceTopicsPageResolver,
+ AdminQualityAssuranceEventsPageResolver,
+ ]
+})
+/**
+ * Routing module for the Notifications section of the admin sidebar
+ */
+export class AdminNotificationsRoutingModule {
+
+}
diff --git a/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page-resolver.service.ts b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page-resolver.service.ts
new file mode 100644
index 0000000000..df1f4b81e6
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page-resolver.service.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+
+/**
+ * Interface for the route parameters.
+ */
+export interface AdminNotificationsSuggestionTargetsPageParams {
+ pageId?: string;
+ pageSize?: number;
+ currentPage?: number;
+}
+
+/**
+ * This class represents a resolver that retrieve the route data before the route is activated.
+ */
+@Injectable()
+export class AdminNotificationsSuggestionTargetsPageResolver implements Resolve {
+
+ /**
+ * Method for resolving the parameters in the current route.
+ * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+ * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+ * @returns AdminNotificationsSuggestionTargetsPageParams Emits the route parameters
+ */
+ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsSuggestionTargetsPageParams {
+ return {
+ pageId: route.queryParams.pageId,
+ pageSize: parseInt(route.queryParams.pageSize, 10),
+ currentPage: parseInt(route.queryParams.page, 10)
+ };
+ }
+}
diff --git a/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.html b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.html
new file mode 100644
index 0000000000..5d06a1a6bd
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.scss b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.spec.ts
new file mode 100644
index 0000000000..f9e407f402
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.spec.ts
@@ -0,0 +1,38 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AdminNotificationsSuggestionTargetsPageComponent } from './admin-notifications-suggestion-targets-page.component';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { TranslateModule } from '@ngx-translate/core';
+
+describe('AdminNotificationsSuggestionTargetsPageComponent', () => {
+ let component: AdminNotificationsSuggestionTargetsPageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ CommonModule,
+ TranslateModule.forRoot()
+ ],
+ declarations: [
+ AdminNotificationsSuggestionTargetsPageComponent
+ ],
+ providers: [
+ AdminNotificationsSuggestionTargetsPageComponent
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AdminNotificationsSuggestionTargetsPageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.ts
new file mode 100644
index 0000000000..a9a77f5089
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'ds-admin-notifications-reciter-page',
+ templateUrl: './admin-notifications-suggestion-targets-page.component.html',
+ styleUrls: ['./admin-notifications-suggestion-targets-page.component.scss']
+})
+export class AdminNotificationsSuggestionTargetsPageComponent {
+
+}
diff --git a/src/app/admin/admin-notifications/admin-notifications.module.ts b/src/app/admin/admin-notifications/admin-notifications.module.ts
new file mode 100644
index 0000000000..53b3aada6e
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-notifications.module.ts
@@ -0,0 +1,33 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { CoreModule } from '../../core/core.module';
+import { SharedModule } from '../../shared/shared.module';
+import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module';
+import { AdminNotificationsSuggestionTargetsPageComponent } from './admin-notifications-suggestion-targets-page/admin-notifications-suggestion-targets-page.component';
+import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component';
+import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.component';
+import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component';
+import {SuggestionNotificationsModule} from '../../suggestion-notifications/suggestion-notifications.module';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ SharedModule,
+ CoreModule.forRoot(),
+ AdminNotificationsRoutingModule,
+ SuggestionNotificationsModule
+ ],
+ declarations: [
+ AdminNotificationsSuggestionTargetsPageComponent,
+ AdminQualityAssuranceTopicsPageComponent,
+ AdminQualityAssuranceEventsPageComponent,
+ AdminQualityAssuranceSourcePageComponent
+ ],
+ entryComponents: []
+})
+/**
+ * This module handles all components related to the notifications pages
+ */
+export class AdminNotificationsModule {
+
+}
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.html b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.html
new file mode 100644
index 0000000000..315209d342
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.spec.ts b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.spec.ts
new file mode 100644
index 0000000000..b952078215
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.spec.ts
@@ -0,0 +1,26 @@
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page.component';
+
+describe('AdminQualityAssuranceEventsPageComponent', () => {
+ let component: AdminQualityAssuranceEventsPageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ AdminQualityAssuranceEventsPageComponent ],
+ schemas: [NO_ERRORS_SCHEMA]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AdminQualityAssuranceEventsPageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create AdminQualityAssuranceEventsPageComponent', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.ts
new file mode 100644
index 0000000000..bd3470f301
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.ts
@@ -0,0 +1,12 @@
+import { Component } from '@angular/core';
+
+/**
+ * Component for the page that show the QA events related to a specific topic.
+ */
+@Component({
+ selector: 'ds-quality-assurance-events-page',
+ templateUrl: './admin-quality-assurance-events-page.component.html'
+})
+export class AdminQualityAssuranceEventsPageComponent {
+
+}
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver.ts b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver.ts
new file mode 100644
index 0000000000..3139355629
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+
+/**
+ * Interface for the route parameters.
+ */
+export interface AdminQualityAssuranceEventsPageParams {
+ pageId?: string;
+ pageSize?: number;
+ currentPage?: number;
+}
+
+/**
+ * This class represents a resolver that retrieve the route data before the route is activated.
+ */
+@Injectable()
+export class AdminQualityAssuranceEventsPageResolver implements Resolve {
+
+ /**
+ * Method for resolving the parameters in the current route.
+ * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+ * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+ * @returns AdminQualityAssuranceEventsPageParams Emits the route parameters
+ */
+ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminQualityAssuranceEventsPageParams {
+ return {
+ pageId: route.queryParams.pageId,
+ pageSize: parseInt(route.queryParams.pageSize, 10),
+ currentPage: parseInt(route.queryParams.page, 10)
+ };
+ }
+}
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts
new file mode 100644
index 0000000000..8475732aed
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts
@@ -0,0 +1,45 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot, Router } from '@angular/router';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { PaginatedList } from '../../../core/data/paginated-list.model';
+import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model';
+import { QualityAssuranceSourceService } from '../../../suggestion-notifications/qa/source/quality-assurance-source.service';
+/**
+ * This class represents a resolver that retrieve the route data before the route is activated.
+ */
+@Injectable()
+export class SourceDataResolver implements Resolve> {
+ /**
+ * Initialize the effect class variables.
+ * @param {QualityAssuranceSourceService} qualityAssuranceSourceService
+ */
+ constructor(
+ private qualityAssuranceSourceService: QualityAssuranceSourceService,
+ private router: Router
+ ) { }
+ /**
+ * Method for resolving the parameters in the current route.
+ * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+ * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+ * @returns Observable
+ */
+ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
+ return this.qualityAssuranceSourceService.getSources(5,0).pipe(
+ map((sources: PaginatedList) => {
+ if (sources.page.length === 1) {
+ this.router.navigate([this.getResolvedUrl(route) + '/' + sources.page[0].id]);
+ }
+ return sources.page;
+ }));
+ }
+
+ /**
+ *
+ * @param route url path
+ * @returns url path
+ */
+ getResolvedUrl(route: ActivatedRouteSnapshot): string {
+ return route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/');
+ }
+}
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service.ts
new file mode 100644
index 0000000000..ac9bdb48d6
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+
+/**
+ * Interface for the route parameters.
+ */
+export interface AdminQualityAssuranceSourcePageParams {
+ pageId?: string;
+ pageSize?: number;
+ currentPage?: number;
+}
+
+/**
+ * This class represents a resolver that retrieve the route data before the route is activated.
+ */
+@Injectable()
+export class AdminQualityAssuranceSourcePageResolver implements Resolve {
+
+ /**
+ * Method for resolving the parameters in the current route.
+ * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+ * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+ * @returns AdminQualityAssuranceSourcePageParams Emits the route parameters
+ */
+ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminQualityAssuranceSourcePageParams {
+ return {
+ pageId: route.queryParams.pageId,
+ pageSize: parseInt(route.queryParams.pageSize, 10),
+ currentPage: parseInt(route.queryParams.page, 10)
+ };
+ }
+}
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.html b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.html
new file mode 100644
index 0000000000..709103cf3d
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.spec.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.spec.ts
new file mode 100644
index 0000000000..451c911c4c
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.spec.ts
@@ -0,0 +1,27 @@
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page.component';
+
+describe('AdminQualityAssuranceSourcePageComponent', () => {
+ let component: AdminQualityAssuranceSourcePageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ AdminQualityAssuranceSourcePageComponent ],
+ schemas: [NO_ERRORS_SCHEMA]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AdminQualityAssuranceSourcePageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create AdminQualityAssuranceSourcePageComponent', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts
new file mode 100644
index 0000000000..447e5a2e55
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+/**
+ * Component for the page that show the QA sources.
+ */
+@Component({
+ selector: 'ds-admin-quality-assurance-source-page-component',
+ templateUrl: './admin-quality-assurance-source-page.component.html',
+})
+export class AdminQualityAssuranceSourcePageComponent {}
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service.ts b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service.ts
new file mode 100644
index 0000000000..47500d1878
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+
+/**
+ * Interface for the route parameters.
+ */
+export interface AdminQualityAssuranceTopicsPageParams {
+ pageId?: string;
+ pageSize?: number;
+ currentPage?: number;
+}
+
+/**
+ * This class represents a resolver that retrieve the route data before the route is activated.
+ */
+@Injectable()
+export class AdminQualityAssuranceTopicsPageResolver implements Resolve {
+
+ /**
+ * Method for resolving the parameters in the current route.
+ * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+ * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+ * @returns AdminQualityAssuranceTopicsPageParams Emits the route parameters
+ */
+ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminQualityAssuranceTopicsPageParams {
+ return {
+ pageId: route.queryParams.pageId,
+ pageSize: parseInt(route.queryParams.pageSize, 10),
+ currentPage: parseInt(route.queryParams.page, 10)
+ };
+ }
+}
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.html b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.html
new file mode 100644
index 0000000000..fc905ad724
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.spec.ts b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.spec.ts
new file mode 100644
index 0000000000..a32f60f017
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.spec.ts
@@ -0,0 +1,26 @@
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page.component';
+
+describe('AdminQualityAssuranceTopicsPageComponent', () => {
+ let component: AdminQualityAssuranceTopicsPageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ AdminQualityAssuranceTopicsPageComponent ],
+ schemas: [NO_ERRORS_SCHEMA]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AdminQualityAssuranceTopicsPageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create AdminQualityAssuranceTopicsPageComponent', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts
new file mode 100644
index 0000000000..f17d3448d5
--- /dev/null
+++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts
@@ -0,0 +1,12 @@
+import { Component } from '@angular/core';
+
+/**
+ * Component for the page that show the QA topics related to a specific source.
+ */
+@Component({
+ selector: 'ds-notification-qa-page',
+ templateUrl: './admin-quality-assurance-topics-page.component.html'
+})
+export class AdminQualityAssuranceTopicsPageComponent {
+
+}
diff --git a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts
index 8d416c2df8..b758767ddb 100644
--- a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts
+++ b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts
@@ -1,5 +1,4 @@
import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
-
import { MetadataSchemaFormComponent } from './metadata-schema-form.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
@@ -29,14 +28,16 @@ describe('MetadataSchemaFormComponent', () => {
createFormGroup: () => {
return {
patchValue: () => {
- }
+ },
+ reset(_value?: any, _options?: { onlySelf?: boolean; emitEvent?: boolean; }): void {
+ },
};
}
};
/* eslint-enable no-empty, @typescript-eslint/no-empty-function */
beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
+ return TestBed.configureTestingModule({
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
declarations: [MetadataSchemaFormComponent, EnumKeysPipe],
providers: [
@@ -64,7 +65,7 @@ describe('MetadataSchemaFormComponent', () => {
const expected = Object.assign(new MetadataSchema(), {
namespace: namespace,
prefix: prefix
- });
+ } as MetadataSchema);
beforeEach(() => {
spyOn(component.submitForm, 'emit');
@@ -79,11 +80,10 @@ describe('MetadataSchemaFormComponent', () => {
fixture.detectChanges();
});
- it('should emit a new schema using the correct values', waitForAsync(() => {
- fixture.whenStable().then(() => {
- expect(component.submitForm.emit).toHaveBeenCalledWith(expected);
- });
- }));
+ it('should emit a new schema using the correct values', async () => {
+ await fixture.whenStable();
+ expect(component.submitForm.emit).toHaveBeenCalledWith(expected);
+ });
});
describe('with an active schema', () => {
@@ -91,7 +91,7 @@ describe('MetadataSchemaFormComponent', () => {
id: 1,
namespace: namespace,
prefix: prefix
- });
+ } as MetadataSchema);
beforeEach(() => {
spyOn(registryService, 'getActiveMetadataSchema').and.returnValue(observableOf(expectedWithId));
@@ -99,11 +99,10 @@ describe('MetadataSchemaFormComponent', () => {
fixture.detectChanges();
});
- it('should edit the existing schema using the correct values', waitForAsync(() => {
- fixture.whenStable().then(() => {
- expect(component.submitForm.emit).toHaveBeenCalledWith(expectedWithId);
- });
- }));
+ it('should edit the existing schema using the correct values', async () => {
+ await fixture.whenStable();
+ expect(component.submitForm.emit).toHaveBeenCalledWith(expectedWithId);
+ });
});
});
});
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..1992289ff7 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
@@ -77,19 +77,24 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
}
ngOnInit() {
- combineLatest(
+ combineLatest([
this.translateService.get(`${this.messagePrefix}.name`),
this.translateService.get(`${this.messagePrefix}.namespace`)
- ).subscribe(([name, namespace]) => {
+ ]).subscribe(([name, namespace]) => {
this.name = new DynamicInputModel({
id: 'name',
label: name,
name: 'name',
validators: {
required: null,
- pattern: '^[^ ,_]{1,32}$'
+ pattern: '^[^. ,]*$',
+ maxLength: 32,
},
required: true,
+ errorMessages: {
+ pattern: 'error.validation.metadata.name.invalid-pattern',
+ maxLength: 'error.validation.metadata.name.max-length',
+ },
});
this.namespace = new DynamicInputModel({
id: 'namespace',
@@ -97,8 +102,12 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
name: 'namespace',
validators: {
required: null,
+ maxLength: 256,
},
required: true,
+ errorMessages: {
+ maxLength: 'error.validation.metadata.namespace.max-length',
+ },
});
this.formModel = [
new DynamicFormGroupModel(
@@ -108,13 +117,18 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
})
];
this.formGroup = this.formBuilderService.createFormGroup(this.formModel);
- this.registryService.getActiveMetadataSchema().subscribe((schema) => {
- this.formGroup.patchValue({
- metadatadataschemagroup:{
- name: schema != null ? schema.prefix : '',
- namespace: schema != null ? schema.namespace : ''
- }
- });
+ this.registryService.getActiveMetadataSchema().subscribe((schema: MetadataSchema) => {
+ if (schema == null) {
+ this.clearFields();
+ } else {
+ this.formGroup.patchValue({
+ metadatadataschemagroup: {
+ name: schema.prefix,
+ namespace: schema.namespace,
+ },
+ });
+ this.name.disabled = true;
+ }
});
});
}
@@ -132,10 +146,10 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
* When the schema has no id attached -> Create new schema
* Emit the updated/created schema using the EventEmitter submitForm
*/
- onSubmit() {
+ onSubmit(): void {
this.registryService.clearMetadataSchemaRequests().subscribe();
this.registryService.getActiveMetadataSchema().pipe(take(1)).subscribe(
- (schema) => {
+ (schema: MetadataSchema) => {
const values = {
prefix: this.name.value,
namespace: this.namespace.value
@@ -147,9 +161,9 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
} else {
this.registryService.createOrUpdateMetadataSchema(Object.assign(new MetadataSchema(), schema, {
id: schema.id,
- prefix: (values.prefix ? values.prefix : schema.prefix),
- namespace: (values.namespace ? values.namespace : schema.namespace)
- })).subscribe((updatedSchema) => {
+ prefix: schema.prefix,
+ namespace: values.namespace,
+ })).subscribe((updatedSchema: MetadataSchema) => {
this.submitForm.emit(updatedSchema);
});
}
@@ -162,13 +176,9 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy {
/**
* Reset all input-fields to be empty
*/
- clearFields() {
- this.formGroup.patchValue({
- metadatadataschemagroup:{
- prefix: '',
- namespace: ''
- }
- });
+ clearFields(): void {
+ this.formGroup.reset('metadatadataschemagroup');
+ this.name.disabled = false;
}
/**
diff --git a/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts b/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts
index e13180d633..ad7b54945d 100644
--- a/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts
+++ b/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts
@@ -39,14 +39,16 @@ describe('MetadataFieldFormComponent', () => {
createFormGroup: () => {
return {
patchValue: () => {
- }
+ },
+ reset(_value?: any, _options?: { onlySelf?: boolean; emitEvent?: boolean; }): void {
+ },
};
}
};
/* eslint-enable no-empty, @typescript-eslint/no-empty-function */
beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
+ return TestBed.configureTestingModule({
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
declarations: [MetadataFieldFormComponent, EnumKeysPipe],
providers: [
@@ -98,11 +100,10 @@ describe('MetadataFieldFormComponent', () => {
fixture.detectChanges();
});
- it('should emit a new field using the correct values', waitForAsync(() => {
- fixture.whenStable().then(() => {
- expect(component.submitForm.emit).toHaveBeenCalledWith(expected);
- });
- }));
+ it('should emit a new field using the correct values', async () => {
+ await fixture.whenStable();
+ expect(component.submitForm.emit).toHaveBeenCalledWith(expected);
+ });
});
describe('with an active field', () => {
@@ -120,11 +121,10 @@ describe('MetadataFieldFormComponent', () => {
fixture.detectChanges();
});
- it('should edit the existing field using the correct values', waitForAsync(() => {
- fixture.whenStable().then(() => {
- expect(component.submitForm.emit).toHaveBeenCalledWith(expectedWithId);
- });
- }));
+ it('should edit the existing field using the correct values', async () => {
+ await fixture.whenStable();
+ expect(component.submitForm.emit).toHaveBeenCalledWith(expectedWithId);
+ });
});
});
});
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..773e0600fb 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
@@ -98,25 +98,39 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
* Initialize the component, setting up the necessary Models for the dynamic form
*/
ngOnInit() {
- combineLatest(
+ combineLatest([
this.translateService.get(`${this.messagePrefix}.element`),
this.translateService.get(`${this.messagePrefix}.qualifier`),
this.translateService.get(`${this.messagePrefix}.scopenote`)
- ).subscribe(([element, qualifier, scopenote]) => {
+ ]).subscribe(([element, qualifier, scopenote]) => {
this.element = new DynamicInputModel({
id: 'element',
label: element,
name: 'element',
validators: {
required: null,
+ pattern: '^[^. ,]*$',
+ maxLength: 64,
},
required: true,
+ errorMessages: {
+ pattern: 'error.validation.metadata.element.invalid-pattern',
+ maxLength: 'error.validation.metadata.element.max-length',
+ },
});
this.qualifier = new DynamicInputModel({
id: 'qualifier',
label: qualifier,
name: 'qualifier',
+ validators: {
+ pattern: '^[^. ,]*$',
+ maxLength: 64,
+ },
required: false,
+ errorMessages: {
+ pattern: 'error.validation.metadata.qualifier.invalid-pattern',
+ maxLength: 'error.validation.metadata.qualifier.max-length',
+ },
});
this.scopeNote = new DynamicInputModel({
id: 'scopeNote',
@@ -132,14 +146,20 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
})
];
this.formGroup = this.formBuilderService.createFormGroup(this.formModel);
- this.registryService.getActiveMetadataField().subscribe((field) => {
- this.formGroup.patchValue({
- metadatadatafieldgroup: {
- element: field != null ? field.element : '',
- qualifier: field != null ? field.qualifier : '',
- scopeNote: field != null ? field.scopeNote : ''
- }
- });
+ this.registryService.getActiveMetadataField().subscribe((field: MetadataField): void => {
+ if (field == null) {
+ this.clearFields();
+ } else {
+ this.formGroup.patchValue({
+ metadatadatafieldgroup: {
+ element: field.element,
+ qualifier: field.qualifier,
+ scopeNote: field.scopeNote,
+ },
+ });
+ this.element.disabled = true;
+ this.qualifier.disabled = true;
+ }
});
});
}
@@ -157,25 +177,24 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
* When the field has no id attached -> Create new field
* Emit the updated/created field using the EventEmitter submitForm
*/
- onSubmit() {
+ onSubmit(): void {
this.registryService.getActiveMetadataField().pipe(take(1)).subscribe(
- (field) => {
- const values = {
- element: this.element.value,
- qualifier: this.qualifier.value,
- scopeNote: this.scopeNote.value
- };
+ (field: MetadataField) => {
if (field == null) {
- this.registryService.createMetadataField(Object.assign(new MetadataField(), values), this.metadataSchema).subscribe((newField) => {
+ this.registryService.createMetadataField(Object.assign(new MetadataField(), {
+ element: this.element.value,
+ qualifier: this.qualifier.value,
+ scopeNote: this.scopeNote.value,
+ }), this.metadataSchema).subscribe((newField: MetadataField) => {
this.submitForm.emit(newField);
});
} else {
this.registryService.updateMetadataField(Object.assign(new MetadataField(), field, {
id: field.id,
- element: (values.element ? values.element : field.element),
- qualifier: (values.qualifier ? values.qualifier : field.qualifier),
- scopeNote: (values.scopeNote ? values.scopeNote : field.scopeNote)
- })).subscribe((updatedField) => {
+ element: field.element,
+ qualifier: field.qualifier,
+ scopeNote: this.scopeNote.value,
+ })).subscribe((updatedField: MetadataField) => {
this.submitForm.emit(updatedField);
});
}
@@ -188,14 +207,10 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
/**
* Reset all input-fields to be empty
*/
- clearFields() {
- this.formGroup.patchValue({
- metadatadatafieldgroup: {
- element: '',
- qualifier: '',
- scopeNote: ''
- }
- });
+ clearFields(): void {
+ this.formGroup.reset('metadatadatafieldgroup');
+ this.element.disabled = false;
+ this.qualifier.disabled = false;
}
/**
diff --git a/src/app/admin/admin-routing-paths.ts b/src/app/admin/admin-routing-paths.ts
index 3168ea93c9..30f801cecb 100644
--- a/src/app/admin/admin-routing-paths.ts
+++ b/src/app/admin/admin-routing-paths.ts
@@ -2,7 +2,12 @@ import { URLCombiner } from '../core/url-combiner/url-combiner';
import { getAdminModuleRoute } from '../app-routing-paths';
export const REGISTRIES_MODULE_PATH = 'registries';
+export const NOTIFICATIONS_MODULE_PATH = 'notifications';
export function getRegistriesModuleRoute() {
return new URLCombiner(getAdminModuleRoute(), REGISTRIES_MODULE_PATH).toString();
}
+
+export function getNotificationsModuleRoute() {
+ return new URLCombiner(getAdminModuleRoute(), NOTIFICATIONS_MODULE_PATH).toString();
+}
diff --git a/src/app/admin/admin-routing.module.ts b/src/app/admin/admin-routing.module.ts
index 8e4f13b164..a7d19a6935 100644
--- a/src/app/admin/admin-routing.module.ts
+++ b/src/app/admin/admin-routing.module.ts
@@ -6,12 +6,17 @@ import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.reso
import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component';
import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service';
import { AdminCurationTasksComponent } from './admin-curation-tasks/admin-curation-tasks.component';
-import { REGISTRIES_MODULE_PATH } from './admin-routing-paths';
+import { REGISTRIES_MODULE_PATH, NOTIFICATIONS_MODULE_PATH } from './admin-routing-paths';
import { BatchImportPageComponent } from './admin-import-batch-page/batch-import-page.component';
@NgModule({
imports: [
RouterModule.forChild([
+ {
+ path: NOTIFICATIONS_MODULE_PATH,
+ loadChildren: () => import('./admin-notifications/admin-notifications.module')
+ .then((m) => m.AdminNotificationsModule),
+ },
{
path: REGISTRIES_MODULE_PATH,
loadChildren: () => import('./admin-registries/admin-registries.module')
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/admin/admin.module.ts b/src/app/admin/admin.module.ts
index dff2e506c3..3dc0036854 100644
--- a/src/app/admin/admin.module.ts
+++ b/src/app/admin/admin.module.ts
@@ -10,6 +10,7 @@ import { AdminSearchModule } from './admin-search-page/admin-search.module';
import { AdminSidebarSectionComponent } from './admin-sidebar/admin-sidebar-section/admin-sidebar-section.component';
import { ExpandableAdminSidebarSectionComponent } from './admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component';
import { BatchImportPageComponent } from './admin-import-batch-page/batch-import-page.component';
+import { UiSwitchModule } from 'ngx-ui-switch';
import { UploadModule } from '../shared/upload/upload.module';
const ENTRY_COMPONENTS = [
@@ -27,6 +28,7 @@ const ENTRY_COMPONENTS = [
AdminSearchModule.withEntryComponents(),
AdminWorkflowModuleModule.withEntryComponents(),
SharedModule,
+ UiSwitchModule,
UploadModule,
],
declarations: [
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index b69e47c82c..9cbd246f0b 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -38,6 +38,7 @@ import {
ThemedPageInternalServerErrorComponent
} from './page-internal-server-error/themed-page-internal-server-error.component';
import { ServerCheckGuard } from './core/server-check/server-check.guard';
+import { SUGGESTION_MODULE_PATH } from './suggestions-page/suggestions-page-routing-paths';
import { MenuResolver } from './menu.resolver';
import { ThemedPageErrorComponent } from './page-error/themed-page-error.component';
@@ -202,6 +203,11 @@ import { ThemedPageErrorComponent } from './page-error/themed-page-error.compone
.then((m) => m.ProcessPageModule),
canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard]
},
+ { path: SUGGESTION_MODULE_PATH,
+ loadChildren: () => import('./suggestions-page/suggestions-page.module')
+ .then((m) => m.SuggestionsPageModule),
+ canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard]
+ },
{
path: INFO_MODULE_PATH,
loadChildren: () => import('./info/info.module').then((m) => m.InfoModule)
@@ -209,7 +215,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)) } }}
| |