mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
117287: Removed method calls returning observables from the metadata schema registry
This commit is contained in:
@@ -9,14 +9,17 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { EnumKeysPipe } from '../../../../shared/utils/enum-keys-pipe';
|
||||
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { MetadataField } from '../../../../core/metadata/metadata-field.model';
|
||||
import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
|
||||
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
|
||||
import { RegistryServiceStub } from '../../../../shared/testing/registry.service.stub';
|
||||
|
||||
describe('MetadataFieldFormComponent', () => {
|
||||
let component: MetadataFieldFormComponent;
|
||||
let fixture: ComponentFixture<MetadataFieldFormComponent>;
|
||||
let registryService: RegistryService;
|
||||
|
||||
let registryService: RegistryServiceStub;
|
||||
|
||||
const metadataSchema = Object.assign(new MetadataSchema(), {
|
||||
id: 1,
|
||||
@@ -24,38 +27,17 @@ describe('MetadataFieldFormComponent', () => {
|
||||
prefix: 'fake'
|
||||
});
|
||||
|
||||
/* eslint-disable no-empty,@typescript-eslint/no-empty-function */
|
||||
const registryServiceStub = {
|
||||
getActiveMetadataField: () => observableOf(undefined),
|
||||
createMetadataField: (field: MetadataField) => observableOf(field),
|
||||
updateMetadataField: (field: MetadataField) => observableOf(field),
|
||||
cancelEditMetadataField: () => {
|
||||
},
|
||||
cancelEditMetadataSchema: () => {
|
||||
},
|
||||
clearMetadataFieldRequests: () => observableOf(undefined)
|
||||
};
|
||||
const formBuilderServiceStub = {
|
||||
createFormGroup: () => {
|
||||
return {
|
||||
patchValue: () => {
|
||||
},
|
||||
reset(_value?: any, _options?: { onlySelf?: boolean; emitEvent?: boolean; }): void {
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
/* eslint-enable no-empty, @typescript-eslint/no-empty-function */
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
registryService = new RegistryServiceStub();
|
||||
|
||||
return TestBed.configureTestingModule({
|
||||
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
|
||||
declarations: [MetadataFieldFormComponent, EnumKeysPipe],
|
||||
providers: [
|
||||
{ provide: RegistryService, useValue: registryServiceStub },
|
||||
{ provide: FormBuilderService, useValue: formBuilderServiceStub }
|
||||
{ provide: RegistryService, useValue: registryService },
|
||||
{ provide: FormBuilderService, useValue: getMockFormBuilderService() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
|
@@ -32,11 +32,11 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let field of fields?.page"
|
||||
[ngClass]="{'table-primary' : isActive(field) | async}">
|
||||
[ngClass]="{'table-primary' : (activeField$ | async)?.id === field.id}">
|
||||
<td>
|
||||
<label class="mb-0">
|
||||
<input type="checkbox"
|
||||
[checked]="isSelected(field) | async"
|
||||
[checked]="(selectedMetadataFieldIDs$ | async)?.includes(field.id)"
|
||||
(change)="selectMetadataField(field, $event)">
|
||||
</label>
|
||||
</td>
|
||||
|
@@ -4,7 +4,7 @@ import { of as observableOf } from 'rxjs';
|
||||
import { buildPaginatedList } from '../../../core/data/paginated-list.model';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RegistryService } from '../../../core/registry/registry.service';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
@@ -12,25 +12,28 @@ import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
|
||||
import { PaginationComponent } from '../../../shared/pagination/pagination.component';
|
||||
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
|
||||
import { HostWindowService } from '../../../shared/host-window.service';
|
||||
import { RouterStub } from '../../../shared/testing/router.stub';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
|
||||
import { RestResponse } from '../../../core/cache/response.models';
|
||||
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
|
||||
import { MetadataField } from '../../../core/metadata/metadata-field.model';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { VarDirective } from '../../../shared/utils/var.directive';
|
||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
||||
import { RegistryServiceStub } from '../../../shared/testing/registry.service.stub';
|
||||
|
||||
describe('MetadataSchemaComponent', () => {
|
||||
let comp: MetadataSchemaComponent;
|
||||
let fixture: ComponentFixture<MetadataSchemaComponent>;
|
||||
let registryService: RegistryService;
|
||||
const mockSchemasList = [
|
||||
|
||||
let registryService: RegistryServiceStub;
|
||||
let activatedRoute: ActivatedRouteStub;
|
||||
let paginationService: PaginationServiceStub;
|
||||
|
||||
const mockSchemasList: MetadataSchema[] = [
|
||||
{
|
||||
id: 1,
|
||||
_links: {
|
||||
@@ -51,8 +54,8 @@ describe('MetadataSchemaComponent', () => {
|
||||
prefix: 'mock',
|
||||
namespace: 'http://dspace.org/mockschema'
|
||||
}
|
||||
];
|
||||
const mockFieldsList = [
|
||||
] as MetadataSchema[];
|
||||
const mockFieldsList: MetadataField[] = [
|
||||
{
|
||||
id: 1,
|
||||
_links: {
|
||||
@@ -101,47 +104,29 @@ describe('MetadataSchemaComponent', () => {
|
||||
scopeNote: null,
|
||||
schema: createSuccessfulRemoteDataObject$(mockSchemasList[1])
|
||||
}
|
||||
];
|
||||
const mockSchemas = createSuccessfulRemoteDataObject$(buildPaginatedList(null, mockSchemasList));
|
||||
/* eslint-disable no-empty,@typescript-eslint/no-empty-function */
|
||||
const registryServiceStub = {
|
||||
getMetadataSchemas: () => mockSchemas,
|
||||
getMetadataFieldsBySchema: (schema: MetadataSchema) => createSuccessfulRemoteDataObject$(buildPaginatedList(null, mockFieldsList.filter((value) => value.id === 3 || value.id === 4))),
|
||||
getMetadataSchemaByPrefix: (schemaName: string) => createSuccessfulRemoteDataObject$(mockSchemasList.filter((value) => value.prefix === schemaName)[0]),
|
||||
getActiveMetadataField: () => observableOf(undefined),
|
||||
getSelectedMetadataFields: () => observableOf([]),
|
||||
editMetadataField: (schema) => {
|
||||
},
|
||||
cancelEditMetadataField: () => {
|
||||
},
|
||||
deleteMetadataField: () => observableOf(new RestResponse(true, 200, 'OK')),
|
||||
deselectAllMetadataField: () => {
|
||||
},
|
||||
clearMetadataFieldRequests: () => observableOf(undefined)
|
||||
};
|
||||
/* eslint-enable no-empty, @typescript-eslint/no-empty-function */
|
||||
] as MetadataField[];
|
||||
const schemaNameParam = 'mock';
|
||||
const activatedRouteStub = Object.assign(new ActivatedRouteStub(), {
|
||||
params: observableOf({
|
||||
schemaName: schemaNameParam
|
||||
})
|
||||
});
|
||||
|
||||
const paginationService = new PaginationServiceStub();
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
activatedRoute = new ActivatedRouteStub({
|
||||
schemaName: schemaNameParam,
|
||||
});
|
||||
paginationService = new PaginationServiceStub();
|
||||
registryService = new RegistryServiceStub();
|
||||
spyOn(registryService, 'getMetadataFieldsBySchema').and.returnValue(createSuccessfulRemoteDataObject$(buildPaginatedList(null, mockFieldsList.filter((value) => value.id === 3 || value.id === 4))));
|
||||
spyOn(registryService, 'getMetadataSchemaByPrefix').and.callFake((schemaName) => createSuccessfulRemoteDataObject$(mockSchemasList.filter((value) => value.prefix === schemaName)[0]));
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
|
||||
declarations: [MetadataSchemaComponent, PaginationComponent, EnumKeysPipe, VarDirective],
|
||||
providers: [
|
||||
{ provide: RegistryService, useValue: registryServiceStub },
|
||||
{ provide: ActivatedRoute, useValue: activatedRouteStub },
|
||||
{ provide: RegistryService, useValue: registryService },
|
||||
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
|
||||
{ provide: Router, useValue: new RouterStub() },
|
||||
{ provide: PaginationService, useValue: paginationService },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
@@ -190,7 +175,7 @@ describe('MetadataSchemaComponent', () => {
|
||||
}));
|
||||
|
||||
it('should cancel editing the selected field when clicked again', waitForAsync(() => {
|
||||
spyOn(registryService, 'getActiveMetadataField').and.returnValue(observableOf(mockFieldsList[2] as MetadataField));
|
||||
comp.activeField$ = observableOf(mockFieldsList[2] as MetadataField);
|
||||
spyOn(registryService, 'cancelEditMetadataField');
|
||||
row.click();
|
||||
fixture.detectChanges();
|
||||
@@ -205,7 +190,7 @@ describe('MetadataSchemaComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(registryService, 'deleteMetadataField').and.callThrough();
|
||||
spyOn(registryService, 'getSelectedMetadataFields').and.returnValue(observableOf(selectedFields as MetadataField[]));
|
||||
comp.selectedMetadataFieldIDs$ = observableOf(selectedFields.map((metadataField: MetadataField) => metadataField.id));
|
||||
comp.deleteFields();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,18 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { RegistryService } from '../../../core/registry/registry.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
combineLatest as observableCombineLatest,
|
||||
combineLatest,
|
||||
Observable,
|
||||
of as observableOf,
|
||||
zip
|
||||
zip,
|
||||
Subscription,
|
||||
} from 'rxjs';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||
import { map, switchMap, take } from 'rxjs/operators';
|
||||
import { hasValue } from '../../../shared/empty.util';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MetadataField } from '../../../core/metadata/metadata-field.model';
|
||||
@@ -32,7 +31,7 @@ import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||
* A component used for managing all existing metadata fields within the current metadata schema.
|
||||
* The admin can create, edit or delete metadata fields here.
|
||||
*/
|
||||
export class MetadataSchemaComponent implements OnInit {
|
||||
export class MetadataSchemaComponent implements OnDestroy, OnInit {
|
||||
/**
|
||||
* The metadata schema
|
||||
*/
|
||||
@@ -57,27 +56,33 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
*/
|
||||
needsUpdate$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
||||
constructor(private registryService: RegistryService,
|
||||
private route: ActivatedRoute,
|
||||
private notificationsService: NotificationsService,
|
||||
private router: Router,
|
||||
private paginationService: PaginationService,
|
||||
private translateService: TranslateService) {
|
||||
/**
|
||||
* The current {@link MetadataField} that is being edited
|
||||
*/
|
||||
activeField$: Observable<MetadataField>;
|
||||
|
||||
/**
|
||||
* The selected {@link MetadataField} IDs
|
||||
*/
|
||||
selectedMetadataFieldIDs$: Observable<number[]>;
|
||||
|
||||
subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(
|
||||
protected registryService: RegistryService,
|
||||
protected route: ActivatedRoute,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected paginationService: PaginationService,
|
||||
protected translateService: TranslateService,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.params.subscribe((params) => {
|
||||
this.initialize(params);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the component using the params within the url (schemaName)
|
||||
* @param params
|
||||
*/
|
||||
initialize(params) {
|
||||
this.metadataSchema$ = this.registryService.getMetadataSchemaByPrefix(params.schemaName).pipe(getFirstSucceededRemoteDataPayload());
|
||||
this.metadataSchema$ = this.registryService.getMetadataSchemaByPrefix(this.route.snapshot.params.schemaName).pipe(getFirstSucceededRemoteDataPayload());
|
||||
this.activeField$ = this.registryService.getActiveMetadataField();
|
||||
this.selectedMetadataFieldIDs$ = this.registryService.getSelectedMetadataFields().pipe(
|
||||
map((metadataFields: MetadataField[]) => metadataFields.map((metadataField: MetadataField) => metadataField.id)),
|
||||
);
|
||||
this.updateFields();
|
||||
}
|
||||
|
||||
@@ -86,7 +91,7 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
*/
|
||||
private updateFields() {
|
||||
this.metadataFields$ = this.paginationService.getCurrentPagination(this.config.id, this.config).pipe(
|
||||
switchMap((currentPagination) => combineLatest(this.metadataSchema$, this.needsUpdate$, observableOf(currentPagination))),
|
||||
switchMap((currentPagination) => combineLatest([this.metadataSchema$, this.needsUpdate$, observableOf(currentPagination)])),
|
||||
switchMap(([schema, update, currentPagination]: [MetadataSchema, boolean, PaginationComponentOptions]) => {
|
||||
if (update) {
|
||||
this.needsUpdate$.next(false);
|
||||
@@ -110,30 +115,13 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
* @param field
|
||||
*/
|
||||
editField(field: MetadataField) {
|
||||
this.getActiveField().pipe(take(1)).subscribe((activeField) => {
|
||||
this.subscriptions.push(this.activeField$.pipe(take(1)).subscribe((activeField) => {
|
||||
if (field === activeField) {
|
||||
this.registryService.cancelEditMetadataField();
|
||||
} else {
|
||||
this.registryService.editMetadataField(field);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given metadata field is active (being edited)
|
||||
* @param field
|
||||
*/
|
||||
isActive(field: MetadataField): Observable<boolean> {
|
||||
return this.getActiveField().pipe(
|
||||
map((activeField) => field === activeField)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the active metadata field (being edited)
|
||||
*/
|
||||
getActiveField(): Observable<MetadataField> {
|
||||
return this.registryService.getActiveMetadataField();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,42 +135,25 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
this.registryService.deselectMetadataField(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given metadata field is selected in the list (checkbox)
|
||||
* @param field
|
||||
*/
|
||||
isSelected(field: MetadataField): Observable<boolean> {
|
||||
return this.registryService.getSelectedMetadataFields().pipe(
|
||||
map((fields) => fields.find((selectedField) => selectedField === field) != null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the selected metadata fields
|
||||
*/
|
||||
deleteFields() {
|
||||
this.registryService.getSelectedMetadataFields().pipe(take(1)).subscribe(
|
||||
(fields) => {
|
||||
const tasks$ = [];
|
||||
for (const field of fields) {
|
||||
if (hasValue(field.id)) {
|
||||
tasks$.push(this.registryService.deleteMetadataField(field.id).pipe(getFirstCompletedRemoteData()));
|
||||
}
|
||||
}
|
||||
zip(...tasks$).subscribe((responses: RemoteData<NoContent>[]) => {
|
||||
const successResponses = responses.filter((response: RemoteData<NoContent>) => response.hasSucceeded);
|
||||
const failedResponses = responses.filter((response: RemoteData<NoContent>) => response.hasFailed);
|
||||
if (successResponses.length > 0) {
|
||||
this.showNotification(true, successResponses.length);
|
||||
}
|
||||
if (failedResponses.length > 0) {
|
||||
this.showNotification(false, failedResponses.length);
|
||||
}
|
||||
this.registryService.deselectAllMetadataField();
|
||||
this.registryService.cancelEditMetadataField();
|
||||
});
|
||||
this.subscriptions.push(this.selectedMetadataFieldIDs$.pipe(
|
||||
take(1),
|
||||
switchMap((fieldIDs) => zip(fieldIDs.map((fieldID) => this.registryService.deleteMetadataField(fieldID).pipe(getFirstCompletedRemoteData())))),
|
||||
).subscribe((responses: RemoteData<NoContent>[]) => {
|
||||
const successResponses = responses.filter((response: RemoteData<NoContent>) => response.hasSucceeded);
|
||||
const failedResponses = responses.filter((response: RemoteData<NoContent>) => response.hasFailed);
|
||||
if (successResponses.length > 0) {
|
||||
this.showNotification(true, successResponses.length);
|
||||
}
|
||||
);
|
||||
if (failedResponses.length > 0) {
|
||||
this.showNotification(false, failedResponses.length);
|
||||
}
|
||||
this.registryService.deselectAllMetadataField();
|
||||
this.registryService.cancelEditMetadataField();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,20 +164,18 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
showNotification(success: boolean, amount: number) {
|
||||
const prefix = 'admin.registries.schema.notification';
|
||||
const suffix = success ? 'success' : 'failure';
|
||||
const messages = observableCombineLatest(
|
||||
this.translateService.get(success ? `${prefix}.${suffix}` : `${prefix}.${suffix}`),
|
||||
this.translateService.get(`${prefix}.field.deleted.${suffix}`, { amount: amount })
|
||||
);
|
||||
messages.subscribe(([head, content]) => {
|
||||
if (success) {
|
||||
this.notificationsService.success(head, content);
|
||||
} else {
|
||||
this.notificationsService.error(head, content);
|
||||
}
|
||||
});
|
||||
const head = this.translateService.instant(success ? `${prefix}.${suffix}` : `${prefix}.${suffix}`);
|
||||
const content = this.translateService.instant(`${prefix}.field.deleted.${suffix}`, { amount: amount });
|
||||
if (success) {
|
||||
this.notificationsService.success(head, content);
|
||||
} else {
|
||||
this.notificationsService.error(head, content);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.paginationService.clearPagination(this.config.id);
|
||||
this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -85,12 +85,12 @@ export class RegistryServiceStub {
|
||||
return observableOf('');
|
||||
}
|
||||
|
||||
createMetadataField(_field: MetadataField, _schema: MetadataSchema): Observable<MetadataField> {
|
||||
return observableOf(undefined);
|
||||
createMetadataField(field: MetadataField, _schema: MetadataSchema): Observable<MetadataField> {
|
||||
return observableOf(field);
|
||||
}
|
||||
|
||||
updateMetadataField(_field: MetadataField): Observable<MetadataField> {
|
||||
return observableOf(undefined);
|
||||
updateMetadataField(field: MetadataField): Observable<MetadataField> {
|
||||
return observableOf(field);
|
||||
}
|
||||
|
||||
deleteMetadataField(_id: number): Observable<RemoteData<NoContent>> {
|
||||
|
Reference in New Issue
Block a user