finished docs and tests

This commit is contained in:
lotte
2019-02-27 13:18:35 +01:00
parent 664d58f40e
commit 8125f56009
9 changed files with 98 additions and 32 deletions

View File

@@ -60,7 +60,6 @@ describe('EditInPlaceFieldComponent', () => {
metadataFieldService = jasmine.createSpyObj({ metadataFieldService = jasmine.createSpyObj({
queryMetadataFields: observableOf(new RemoteData(false, false, true, undefined, paginatedMetadataFields)), queryMetadataFields: observableOf(new RemoteData(false, false, true, undefined, paginatedMetadataFields)),
getAllMetadataFields: observableOf(new RemoteData(false, false, true, undefined, paginatedMetadataFields))
}); });
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService', objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',
{ {

View File

@@ -1,5 +1,5 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { getTestScheduler } from 'jasmine-marbles'; import { getTestScheduler } from 'jasmine-marbles';
import { ItemMetadataComponent } from './item-metadata.component'; import { ItemMetadataComponent } from './item-metadata.component';
@@ -22,6 +22,11 @@ import { Item } from '../../../core/shared/item.model';
import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions'; import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { MetadatumViewModel } from '../../../core/shared/metadata.models'; import { MetadatumViewModel } from '../../../core/shared/metadata.models';
import { RegistryService } from '../../../core/registry/registry.service';
import { PaginatedList } from '../../../core/data/paginated-list';
import { MetadataSchema } from '../../../core/metadata/metadataschema.model';
import { MetadataField } from '../../../core/metadata/metadatafield.model';
import { Metadata } from '../../../core/shared/metadata.utils';
let comp: ItemMetadataComponent; let comp: ItemMetadataComponent;
let fixture: ComponentFixture<ItemMetadataComponent>; let fixture: ComponentFixture<ItemMetadataComponent>;
@@ -33,8 +38,23 @@ const warningNotification: INotification = new Notification('id', NotificationTy
const successNotification: INotification = new Notification('id', NotificationType.Success, 'success'); const successNotification: INotification = new Notification('id', NotificationType.Success, 'success');
const date = new Date(); const date = new Date();
const router = new RouterStub(); const router = new RouterStub();
let metadataFieldService;
let paginatedMetadataFields;
let routeStub; let routeStub;
const mdSchema = Object.assign(new MetadataSchema(), { prefix: 'dc' });
const mdField1 = Object.assign(new MetadataField(), {
schema: mdSchema,
element: 'contributor',
qualifier: 'author'
});
const mdField2 = Object.assign(new MetadataField(), { schema: mdSchema, element: 'title' });
const mdField3 = Object.assign(new MetadataField(), {
schema: mdSchema,
element: 'description',
qualifier: 'abstract'
});
let itemService; let itemService;
const notificationsService = jasmine.createSpyObj('notificationsService', const notificationsService = jasmine.createSpyObj('notificationsService',
{ {
@@ -83,7 +103,18 @@ let scheduler: TestScheduler;
let item; let item;
describe('ItemMetadataComponent', () => { describe('ItemMetadataComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
item = Object.assign(new Item(), { metadata: [metadatum1, metadatum2, metadatum3] }, { lastModified: date }); item = Object.assign(new Item(), {
metadata: {
[metadatum1.key]: [metadatum1],
[metadatum2.key]: [metadatum2],
[metadatum3.key]: [metadatum3]
}
},
{
lastModified: date
}
)
;
itemService = jasmine.createSpyObj('itemService', { itemService = jasmine.createSpyObj('itemService', {
update: observableOf(new RemoteData(false, false, true, undefined, item)), update: observableOf(new RemoteData(false, false, true, undefined, item)),
commitUpdates: {} commitUpdates: {}
@@ -93,6 +124,11 @@ describe('ItemMetadataComponent', () => {
data: observableOf({ item: new RemoteData(false, false, true, null, item) }) data: observableOf({ item: new RemoteData(false, false, true, null, item) })
} }
}; };
paginatedMetadataFields = new PaginatedList(undefined, [mdField1, mdField2, mdField3]);
metadataFieldService = jasmine.createSpyObj({
getAllMetadataFields: observableOf(new RemoteData(false, false, true, undefined, paginatedMetadataFields))
});
scheduler = getTestScheduler(); scheduler = getTestScheduler();
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService', objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',
{ {
@@ -122,7 +158,8 @@ describe('ItemMetadataComponent', () => {
{ provide: Router, useValue: router }, { provide: Router, useValue: router },
{ provide: ActivatedRoute, useValue: routeStub }, { provide: ActivatedRoute, useValue: routeStub },
{ provide: NotificationsService, useValue: notificationsService }, { provide: NotificationsService, useValue: notificationsService },
{ provide: GLOBAL_CONFIG, useValue: { notifications: { timeOut: 10 } } as any } { provide: GLOBAL_CONFIG, useValue: { notifications: { timeOut: 10 } } as any },
{ provide: RegistryService, useValue: metadataFieldService },
], schemas: [ ], schemas: [
NO_ERRORS_SCHEMA NO_ERRORS_SCHEMA
] ]
@@ -176,9 +213,9 @@ describe('ItemMetadataComponent', () => {
}); });
it('it should call reinstateFieldUpdates on the objectUpdatesService with the correct url and metadata', () => { it('it should call reinstateFieldUpdates on the objectUpdatesService with the correct url and metadata', () => {
expect(objectUpdatesService.getUpdatedFields).toHaveBeenCalledWith(url, comp.item.metadata); expect(objectUpdatesService.getUpdatedFields).toHaveBeenCalledWith(url, comp.item.metadataAsList);
expect(itemService.update).toHaveBeenCalledWith(comp.item); expect(itemService.update).toHaveBeenCalledWith(Object.assign(comp.item, { metadata: Metadata.toMetadataMap(comp.item.metadataAsList) }));
expect(objectUpdatesService.getFieldUpdates).toHaveBeenCalledWith(url, comp.item.metadata); expect(objectUpdatesService.getFieldUpdates).toHaveBeenCalledWith(url, comp.item.metadataAsList);
}); });
}); });

View File

@@ -72,7 +72,7 @@ export class ItemMetadataComponent implements OnInit {
* Set up and initialize all fields * Set up and initialize all fields
*/ */
ngOnInit(): void { ngOnInit(): void {
this.metadataFields$ = this.findMetadataFields() this.metadataFields$ = this.findMetadataFields();
this.route.parent.data.pipe(map((data) => data.item)) this.route.parent.data.pipe(map((data) => data.item))
.pipe( .pipe(
first(), first(),

View File

@@ -19,6 +19,7 @@ export class EPerson extends DSpaceObject {
public selfRegistered: boolean; public selfRegistered: boolean;
/** Getter to retrieve the EPerson's full name as a string */
get name(): string { get name(): string {
return this.firstMetadataValue('eperson.firstname') + ' ' + this.firstMetadataValue('eperson.lastname'); return this.firstMetadataValue('eperson.firstname') + ' ' + this.firstMetadataValue('eperson.lastname');
} }

View File

@@ -1,4 +1,9 @@
import { MetadataMap, MetadataValue, MetadataValueFilter } from './metadata.models'; import {
MetadataMap,
MetadataValue,
MetadataValueFilter,
MetadatumViewModel
} from './metadata.models';
import { Metadata } from './metadata.utils'; import { Metadata } from './metadata.utils';
import { CacheableObject } from '../cache/object-cache.reducer'; import { CacheableObject } from '../cache/object-cache.reducer';
import { RemoteData } from '../data/remote-data'; import { RemoteData } from '../data/remote-data';
@@ -40,7 +45,10 @@ export class DSpaceObject implements CacheableObject, ListableObject {
*/ */
metadata: MetadataMap; metadata: MetadataMap;
get metadataAsList() { /**
* Retrieve the current metadata as a list of MetadatumViewModels
*/
get metadataAsList(): MetadatumViewModel[] {
return Metadata.toViewModelList(this.metadata); return Metadata.toViewModelList(this.metadata);
} }

View File

@@ -1,5 +1,6 @@
import * as uuidv4 from 'uuid/v4'; import * as uuidv4 from 'uuid/v4';
import { autoserialize, Serialize, Deserialize } from 'cerialize'; import { autoserialize, Serialize, Deserialize } from 'cerialize';
/* tslint:disable:max-classes-per-file */
/** A map of metadata keys to an ordered list of MetadataValue objects. */ /** A map of metadata keys to an ordered list of MetadataValue objects. */
export class MetadataMap { export class MetadataMap {
@@ -9,7 +10,6 @@ export class MetadataMap {
/** A single metadata value and its properties. */ /** A single metadata value and its properties. */
export class MetadataValue { export class MetadataValue {
/** The uuid. */ /** The uuid. */
uuid: string = uuidv4(); uuid: string = uuidv4();
@@ -20,7 +20,6 @@ export class MetadataValue {
/** The string value. */ /** The string value. */
@autoserialize @autoserialize
value: string; value: string;
} }
/** Constraints for matching metadata values. */ /** Constraints for matching metadata values. */
@@ -55,7 +54,10 @@ export class MetadatumViewModel {
order: number; order: number;
} }
/** Serializer used for MetadataMaps.
* This is necessary because Cerialize has trouble instantiating the MetadataValues using their constructor
* when they are inside arrays which also represent the values in a map.
*/
export const MetadataMapSerializer = { export const MetadataMapSerializer = {
Serialize(map: MetadataMap): any { Serialize(map: MetadataMap): any {
const json = {}; const json = {};
@@ -73,3 +75,4 @@ export const MetadataMapSerializer = {
return metadataMap; return metadataMap;
} }
}; };
/* tslint:enable:max-classes-per-file */

View File

@@ -149,7 +149,7 @@ export class Metadata {
* @param {MetadataMap} mdMap The source map. * @param {MetadataMap} mdMap The source map.
* @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see above. * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see above.
*/ */
private static resolveKeys(mdMap: MetadataMap, keyOrKeys: string | string[]): string[] { private static resolveKeys(mdMap: MetadataMap = {}, keyOrKeys: string | string[]): string[] {
const inputKeys: string[] = keyOrKeys instanceof Array ? keyOrKeys : [keyOrKeys]; const inputKeys: string[] = keyOrKeys instanceof Array ? keyOrKeys : [keyOrKeys];
const outputKeys: string[] = []; const outputKeys: string[] = [];
for (const inputKey of inputKeys) { for (const inputKey of inputKeys) {
@@ -167,33 +167,51 @@ export class Metadata {
return outputKeys; return outputKeys;
} }
public static toViewModelList(mdMap: MetadataMap) { /**
* Creates an array of MetadatumViewModels from an existing MetadataMap.
*
* @param {MetadataMap} mdMap The source map.
* @returns {MetadatumViewModel[]} List of metadata view models based on the source map.
*/
public static toViewModelList(mdMap: MetadataMap): MetadatumViewModel[] {
let metadatumList: MetadatumViewModel[] = []; let metadatumList: MetadatumViewModel[] = [];
Object.keys(mdMap) Object.keys(mdMap)
.sort() .sort()
.forEach((key: string) => { .forEach((key: string) => {
const fields = mdMap[key].map( const fields = mdMap[key].map(
(metadataValue: MetadataValue, index: number) => (metadataValue: MetadataValue, index: number) =>
Object.assign( Object.assign(
{}, {},
metadataValue, metadataValue,
{ {
order: index, order: index,
key key
})); }));
metadatumList = [...metadatumList, ...fields]; metadatumList = [...metadatumList, ...fields];
}); });
return metadatumList; return metadatumList;
} }
public static toMetadataMap(viewModelList: MetadatumViewModel[]) { /**
* Creates an MetadataMap from an existing array of MetadatumViewModels.
*
* @param {MetadatumViewModel[]} viewModelList The source list.
* @returns {MetadataMap} Map with metadata values based on the source list.
*/
public static toMetadataMap(viewModelList: MetadatumViewModel[]): MetadataMap {
const metadataMap: MetadataMap = {}; const metadataMap: MetadataMap = {};
const groupedList = groupBy(viewModelList, (viewModel) => viewModel.key); const groupedList = groupBy(viewModelList, (viewModel) => viewModel.key);
Object.keys(groupedList) Object.keys(groupedList)
.sort() .sort()
.forEach((key: string) => { .forEach((key: string) => {
const orderedValues = sortBy(groupedList[key], ['order']); const orderedValues = sortBy(groupedList[key], ['order']);
metadataMap[key] = orderedValues.map((value: MetadataValue, index: number) => Object.assign({}, value, { order: index })) metadataMap[key] = orderedValues.map((value: MetadataValue) => {
const val = Object.assign({}, value);
delete (val as any).order;
delete (val as any).key;
return val;
}
)
}); });
return metadataMap; return metadataMap;
} }

View File

@@ -83,10 +83,10 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
onSubmit() { onSubmit() {
const formMetadata = new Object() as MetadataMap; const formMetadata = new Object() as MetadataMap;
this.formModel.forEach((fieldModel: DynamicInputModel) => { this.formModel.forEach((fieldModel: DynamicInputModel) => {
const value: MetadataValue = Object.assign(new MetadataValue(), { const value: MetadataValue = {
value: fieldModel.value as string, value: fieldModel.value as string,
language: null language: null
}); } as any;
if (formMetadata.hasOwnProperty(fieldModel.name)) { if (formMetadata.hasOwnProperty(fieldModel.name)) {
formMetadata[fieldModel.name].push(value); formMetadata[fieldModel.name].push(value);
} else { } else {