mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 10:34:15 +00:00
Fixed conflicts with new metadata map
This commit is contained in:
@@ -8,7 +8,6 @@ import { RemoteData } from '../../../../core/data/remote-data';
|
|||||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||||
import { MetadataField } from '../../../../core/metadata/metadatafield.model';
|
import { MetadataField } from '../../../../core/metadata/metadatafield.model';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { Metadatum } from '../../../../core/shared/metadatum.model';
|
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { SharedModule } from '../../../../shared/shared.module';
|
import { SharedModule } from '../../../../shared/shared.module';
|
||||||
import { getTestScheduler } from 'jasmine-marbles';
|
import { getTestScheduler } from 'jasmine-marbles';
|
||||||
@@ -17,6 +16,7 @@ import { TestScheduler } from 'rxjs/testing';
|
|||||||
import { MetadataSchema } from '../../../../core/metadata/metadataschema.model';
|
import { MetadataSchema } from '../../../../core/metadata/metadataschema.model';
|
||||||
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { MetadatumViewModel } from '../../../../core/shared/metadata.models';
|
||||||
|
|
||||||
let comp: EditInPlaceFieldComponent;
|
let comp: EditInPlaceFieldComponent;
|
||||||
let fixture: ComponentFixture<EditInPlaceFieldComponent>;
|
let fixture: ComponentFixture<EditInPlaceFieldComponent>;
|
||||||
@@ -38,7 +38,7 @@ const mdField3 = Object.assign(new MetadataField(), {
|
|||||||
qualifier: 'abstract'
|
qualifier: 'abstract'
|
||||||
});
|
});
|
||||||
|
|
||||||
const metadatum = Object.assign(new Metadatum(), {
|
const metadatum = Object.assign(new MetadatumViewModel(), {
|
||||||
key: 'dc.description.abstract',
|
key: 'dc.description.abstract',
|
||||||
value: 'Example abstract',
|
value: 'Example abstract',
|
||||||
language: 'en'
|
language: 'en'
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||||
import { hasValue, isNotEmpty } from '../../../../shared/empty.util';
|
import { hasValue, isNotEmpty } from '../../../../shared/empty.util';
|
||||||
import { Metadatum } from '../../../../core/shared/metadatum.model';
|
|
||||||
import { RegistryService } from '../../../../core/registry/registry.service';
|
import { RegistryService } from '../../../../core/registry/registry.service';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||||
@@ -10,8 +9,8 @@ import { InputSuggestion } from '../../../../shared/input-suggestions/input-sugg
|
|||||||
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
||||||
import { FieldUpdate } from '../../../../core/data/object-updates/object-updates.reducer';
|
import { FieldUpdate } from '../../../../core/data/object-updates/object-updates.reducer';
|
||||||
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
||||||
import { getSucceededRemoteData } from '../../../../core/shared/operators';
|
|
||||||
import { NgModel } from '@angular/forms';
|
import { NgModel } from '@angular/forms';
|
||||||
|
import { MetadatumViewModel } from '../../../../core/shared/metadata.models';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
// tslint:disable-next-line:component-selector
|
// tslint:disable-next-line:component-selector
|
||||||
@@ -41,7 +40,7 @@ export class EditInPlaceFieldComponent implements OnInit, OnChanges {
|
|||||||
/**
|
/**
|
||||||
* The metadatum of this field
|
* The metadatum of this field
|
||||||
*/
|
*/
|
||||||
metadata: Metadatum;
|
metadata: MetadatumViewModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits whether or not this field is currently editable
|
* Emits whether or not this field is currently editable
|
||||||
@@ -118,7 +117,7 @@ export class EditInPlaceFieldComponent implements OnInit, OnChanges {
|
|||||||
* Sets the current metadatafield based on the fieldUpdate input field
|
* Sets the current metadatafield based on the fieldUpdate input field
|
||||||
*/
|
*/
|
||||||
ngOnChanges(): void {
|
ngOnChanges(): void {
|
||||||
this.metadata = cloneDeep(this.fieldUpdate.field) as Metadatum;
|
this.metadata = cloneDeep(this.fieldUpdate.field) as MetadatumViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -3,7 +3,6 @@ import { CUSTOM_ELEMENTS_SCHEMA, DebugElement, NO_ERRORS_SCHEMA } from '@angular
|
|||||||
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';
|
||||||
import { Metadatum } from '../../../core/shared/metadatum.model';
|
|
||||||
import { TestScheduler } from 'rxjs/testing';
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
import { SharedModule } from '../../../shared/shared.module';
|
import { SharedModule } from '../../../shared/shared.module';
|
||||||
import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
|
import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
|
||||||
@@ -22,6 +21,7 @@ import { GLOBAL_CONFIG } from '../../../../config';
|
|||||||
import { Item } from '../../../core/shared/item.model';
|
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';
|
||||||
|
|
||||||
let comp: ItemMetadataComponent;
|
let comp: ItemMetadataComponent;
|
||||||
let fixture: ComponentFixture<ItemMetadataComponent>;
|
let fixture: ComponentFixture<ItemMetadataComponent>;
|
||||||
@@ -43,19 +43,19 @@ const notificationsService = jasmine.createSpyObj('notificationsService',
|
|||||||
success: successNotification
|
success: successNotification
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const metadatum1 = Object.assign(new Metadatum(), {
|
const metadatum1 = Object.assign(new MetadatumViewModel(), {
|
||||||
key: 'dc.description.abstract',
|
key: 'dc.description.abstract',
|
||||||
value: 'Example abstract',
|
value: 'Example abstract',
|
||||||
language: 'en'
|
language: 'en'
|
||||||
});
|
});
|
||||||
|
|
||||||
const metadatum2 = Object.assign(new Metadatum(), {
|
const metadatum2 = Object.assign(new MetadatumViewModel(), {
|
||||||
key: 'dc.title',
|
key: 'dc.title',
|
||||||
value: 'Title test',
|
value: 'Title test',
|
||||||
language: 'de'
|
language: 'de'
|
||||||
});
|
});
|
||||||
|
|
||||||
const metadatum3 = Object.assign(new Metadatum(), {
|
const metadatum3 = Object.assign(new MetadatumViewModel(), {
|
||||||
key: 'dc.contributor.author',
|
key: 'dc.contributor.author',
|
||||||
value: 'Shakespeare, William',
|
value: 'Shakespeare, William',
|
||||||
});
|
});
|
||||||
@@ -140,7 +140,7 @@ describe('ItemMetadataComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('add', () => {
|
describe('add', () => {
|
||||||
const md = new Metadatum();
|
const md = new MetadatumViewModel();
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
comp.add(md);
|
comp.add(md);
|
||||||
});
|
});
|
||||||
|
@@ -10,7 +10,6 @@ import {
|
|||||||
FieldUpdates,
|
FieldUpdates,
|
||||||
Identifiable
|
Identifiable
|
||||||
} from '../../../core/data/object-updates/object-updates.reducer';
|
} from '../../../core/data/object-updates/object-updates.reducer';
|
||||||
import { Metadatum } from '../../../core/shared/metadatum.model';
|
|
||||||
import { first, map, switchMap, take, tap } from 'rxjs/operators';
|
import { first, map, switchMap, take, tap } from 'rxjs/operators';
|
||||||
import { getSucceededRemoteData } from '../../../core/shared/operators';
|
import { getSucceededRemoteData } from '../../../core/shared/operators';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
@@ -19,6 +18,8 @@ import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config';
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { RegistryService } from '../../../core/registry/registry.service';
|
import { RegistryService } from '../../../core/registry/registry.service';
|
||||||
import { MetadataField } from '../../../core/metadata/metadatafield.model';
|
import { MetadataField } from '../../../core/metadata/metadatafield.model';
|
||||||
|
import { MetadatumViewModel } from '../../../core/shared/metadata.models';
|
||||||
|
import { Metadata } from '../../../core/shared/metadata.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-item-metadata',
|
selector: 'ds-item-metadata',
|
||||||
@@ -92,14 +93,14 @@ export class ItemMetadataComponent implements OnInit {
|
|||||||
this.checkLastModified();
|
this.checkLastModified();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.updates$ = this.objectUpdatesService.getFieldUpdates(this.url, this.item.metadata);
|
this.updates$ = this.objectUpdatesService.getFieldUpdates(this.url, this.item.metadataAsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a new add update for a field to the object updates service
|
* Sends a new add update for a field to the object updates service
|
||||||
* @param metadata The metadata to add, if no parameter is supplied, create a new Metadatum
|
* @param metadata The metadata to add, if no parameter is supplied, create a new Metadatum
|
||||||
*/
|
*/
|
||||||
add(metadata: Metadatum = new Metadatum()) {
|
add(metadata: MetadatumViewModel = new MetadatumViewModel()) {
|
||||||
this.objectUpdatesService.saveAddFieldUpdate(this.url, metadata);
|
this.objectUpdatesService.saveAddFieldUpdate(this.url, metadata);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -124,7 +125,7 @@ export class ItemMetadataComponent implements OnInit {
|
|||||||
* Sends all initial values of this item to the object updates service
|
* Sends all initial values of this item to the object updates service
|
||||||
*/
|
*/
|
||||||
private initializeOriginalFields() {
|
private initializeOriginalFields() {
|
||||||
this.objectUpdatesService.initialize(this.url, this.item.metadata, this.item.lastModified);
|
this.objectUpdatesService.initialize(this.url, this.item.metadataAsList, this.item.lastModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,11 +142,11 @@ export class ItemMetadataComponent implements OnInit {
|
|||||||
submit() {
|
submit() {
|
||||||
this.isValid().pipe(first()).subscribe((isValid) => {
|
this.isValid().pipe(first()).subscribe((isValid) => {
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
const metadata$: Observable<Identifiable[]> = this.objectUpdatesService.getUpdatedFields(this.url, this.item.metadata) as Observable<Metadatum[]>;
|
const metadata$: Observable<Identifiable[]> = this.objectUpdatesService.getUpdatedFields(this.url, this.item.metadataAsList) as Observable<MetadatumViewModel[]>;
|
||||||
metadata$.pipe(
|
metadata$.pipe(
|
||||||
first(),
|
first(),
|
||||||
switchMap((metadata: Metadatum[]) => {
|
switchMap((metadata: MetadatumViewModel[]) => {
|
||||||
const updatedItem: Item = Object.assign(cloneDeep(this.item), { metadata });
|
const updatedItem: Item = Object.assign(cloneDeep(this.item), { metadata: Metadata.toMetadataMap(metadata) });
|
||||||
return this.itemService.update(updatedItem);
|
return this.itemService.update(updatedItem);
|
||||||
}),
|
}),
|
||||||
tap(() => this.itemService.commitUpdates()),
|
tap(() => this.itemService.commitUpdates()),
|
||||||
@@ -154,7 +155,7 @@ export class ItemMetadataComponent implements OnInit {
|
|||||||
(rd: RemoteData<Item>) => {
|
(rd: RemoteData<Item>) => {
|
||||||
this.item = rd.payload;
|
this.item = rd.payload;
|
||||||
this.initializeOriginalFields();
|
this.initializeOriginalFields();
|
||||||
this.updates$ = this.objectUpdatesService.getFieldUpdates(this.url, this.item.metadata);
|
this.updates$ = this.objectUpdatesService.getFieldUpdates(this.url, this.item.metadataAsList);
|
||||||
this.notificationsService.success(this.getNotificationTitle('saved'), this.getNotificationContent('saved'));
|
this.notificationsService.success(this.getNotificationTitle('saved'), this.getNotificationContent('saved'));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import {Component, Input, OnInit} from '@angular/core';
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
import {Item} from '../../../core/shared/item.model';
|
import {Item} from '../../../core/shared/item.model';
|
||||||
import {MetadataMap} from '../../../core/shared/metadata.interfaces';
|
import {MetadataMap} from '../../../core/shared/metadata.models';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-modify-item-overview',
|
selector: 'ds-modify-item-overview',
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
import { MetadataValuesComponent } from '../metadata-values/metadata-values.component';
|
import { MetadataValuesComponent } from '../metadata-values/metadata-values.component';
|
||||||
import { MetadataValue } from '../../../core/shared/metadata.interfaces';
|
import { MetadataValue } from '../../../core/shared/metadata.models';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders the configured 'values' into the ds-metadata-field-wrapper component as a link.
|
* This component renders the configured 'values' into the ds-metadata-field-wrapper component as a link.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { MetadataValue } from '../../../core/shared/metadata.interfaces';
|
import { MetadataValue } from '../../../core/shared/metadata.models';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders the configured 'values' into the ds-metadata-field-wrapper component.
|
* This component renders the configured 'values' into the ds-metadata-field-wrapper component.
|
||||||
|
@@ -6,7 +6,7 @@ import { ActivatedRoute } from '@angular/router';
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { ItemPageComponent } from '../simple/item-page.component';
|
import { ItemPageComponent } from '../simple/item-page.component';
|
||||||
import { MetadataMap } from '../../core/shared/metadata.interfaces';
|
import { MetadataMap } from '../../core/shared/metadata.models';
|
||||||
import { ItemDataService } from '../../core/data/item-data.service';
|
import { ItemDataService } from '../../core/data/item-data.service';
|
||||||
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { autoserialize } from 'cerialize';
|
import { autoserialize } from 'cerialize';
|
||||||
import { MetadataMap } from '../core/shared/metadata.interfaces';
|
import { MetadataMap } from '../core/shared/metadata.models';
|
||||||
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
|
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||||
import { MetadataMap } from '../core/shared/metadata.interfaces';
|
import { MetadataMap } from '../core/shared/metadata.models';
|
||||||
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
|
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { autoserialize, autoserializeAs, deserialize, serialize } from 'cerialize';
|
import { autoserializeAs, deserializeAs } from 'cerialize';
|
||||||
import { DSpaceObject } from '../../shared/dspace-object.model';
|
import { DSpaceObject } from '../../shared/dspace-object.model';
|
||||||
import { MetadataMap } from '../../shared/metadata.interfaces';
|
import { MetadataMap, MetadataMapSerializer } from '../../shared/metadata.models';
|
||||||
import { ResourceType } from '../../shared/resource-type';
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
import { mapsTo } from '../builders/build-decorators';
|
import { mapsTo } from '../builders/build-decorators';
|
||||||
import { NormalizedObject } from './normalized-object.model';
|
import { NormalizedObject } from './normalized-object.model';
|
||||||
@@ -17,7 +17,7 @@ export class NormalizedDSpaceObject<T extends DSpaceObject> extends NormalizedOb
|
|||||||
* Repeated here to make the serialization work,
|
* Repeated here to make the serialization work,
|
||||||
* inheritSerialization doesn't seem to work for more than one level
|
* inheritSerialization doesn't seem to work for more than one level
|
||||||
*/
|
*/
|
||||||
@deserialize
|
@deserializeAs(String)
|
||||||
self: string;
|
self: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,31 +35,31 @@ export class NormalizedDSpaceObject<T extends DSpaceObject> extends NormalizedOb
|
|||||||
* Repeated here to make the serialization work,
|
* Repeated here to make the serialization work,
|
||||||
* inheritSerialization doesn't seem to work for more than one level
|
* inheritSerialization doesn't seem to work for more than one level
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserializeAs(String)
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserializeAs(String)
|
||||||
type: ResourceType;
|
type: ResourceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All metadata of this DSpaceObject
|
* All metadata of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserializeAs(MetadataMapSerializer)
|
||||||
metadata: MetadataMap;
|
metadata: MetadataMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@deserialize
|
@deserializeAs(String)
|
||||||
parents: string[];
|
parents: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The DSpaceObject that owns this DSpaceObject
|
* The DSpaceObject that owns this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@deserialize
|
@deserializeAs(String)
|
||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,7 +68,7 @@ export class NormalizedDSpaceObject<T extends DSpaceObject> extends NormalizedOb
|
|||||||
* Repeated here to make the serialization work,
|
* Repeated here to make the serialization work,
|
||||||
* inheritSerialization doesn't seem to work for more than one level
|
* inheritSerialization doesn't seem to work for more than one level
|
||||||
*/
|
*/
|
||||||
@deserialize
|
@deserializeAs(Object)
|
||||||
_links: {
|
_links: {
|
||||||
[name: string]: string
|
[name: string]: string
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.
|
|||||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../shared/empty.util';
|
||||||
import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model';
|
import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model';
|
||||||
import { MetadataMap, MetadataValue } from '../shared/metadata.interfaces';
|
import { MetadataMap, MetadataValue } from '../shared/metadata.models';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SearchResponseParsingService implements ResponseParsingService {
|
export class SearchResponseParsingService implements ResponseParsingService {
|
||||||
@@ -22,7 +22,7 @@ export class SearchResponseParsingService implements ResponseParsingService {
|
|||||||
const mdMap: MetadataMap = {};
|
const mdMap: MetadataMap = {};
|
||||||
if (hhObject) {
|
if (hhObject) {
|
||||||
for (const key of Object.keys(hhObject)) {
|
for (const key of Object.keys(hhObject)) {
|
||||||
const value: MetadataValue = { value: hhObject[key].join('...'), language: null };
|
const value: MetadataValue = Object.assign(new MetadataValue(), { value: hhObject[key].join('...'), language: null });
|
||||||
mdMap[key] = [ value ];
|
mdMap[key] = [ value ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,6 @@ export class EPerson extends DSpaceObject {
|
|||||||
public selfRegistered: boolean;
|
public selfRegistered: boolean;
|
||||||
|
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return this.findMetadata('eperson.firstname') + ' ' + this.findMetadata('eperson.lastname');
|
return this.firstMetadataValue('eperson.firstname') + ' ' + this.firstMetadataValue('eperson.lastname');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,7 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { EmptyError } from 'rxjs/internal-compatibility';
|
import { EmptyError } from 'rxjs/internal-compatibility';
|
||||||
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||||
import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
|
import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
|
||||||
import { MetadataValue } from '../shared/metadata.interfaces';
|
import { MetadataValue } from '../shared/metadata.models';
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
@Component({
|
@Component({
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
import { MetadataMap, MetadataValue, MetadataValueFilter } from './metadata.interfaces';
|
import { MetadataMap, MetadataValue, MetadataValueFilter } from './metadata.models';
|
||||||
import { Metadata } from './metadata.model';
|
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';
|
||||||
import { ResourceType } from './resource-type';
|
import { ResourceType } from './resource-type';
|
||||||
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { autoserialize } from 'cerialize';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* An abstract model class for a DSpaceObject.
|
||||||
@@ -17,13 +16,11 @@ export class DSpaceObject implements CacheableObject, ListableObject {
|
|||||||
/**
|
/**
|
||||||
* The human-readable identifier of this DSpaceObject
|
* The human-readable identifier of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The universally unique identifier of this DSpaceObject
|
* The universally unique identifier of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,9 +38,12 @@ export class DSpaceObject implements CacheableObject, ListableObject {
|
|||||||
/**
|
/**
|
||||||
* All metadata of this DSpaceObject
|
* All metadata of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
|
||||||
metadata: MetadataMap;
|
metadata: MetadataMap;
|
||||||
|
|
||||||
|
get metadataAsList() {
|
||||||
|
return Metadata.toViewModelList(this.metadata);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
|
@@ -1,30 +0,0 @@
|
|||||||
/** A map of metadata keys to an ordered list of MetadataValue objects. */
|
|
||||||
export interface MetadataMap {
|
|
||||||
[ key: string ]: MetadataValue[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A single metadata value and its properties. */
|
|
||||||
export interface MetadataValue {
|
|
||||||
|
|
||||||
/** The language. */
|
|
||||||
language: string;
|
|
||||||
|
|
||||||
/** The string value. */
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Constraints for matching metadata values. */
|
|
||||||
export interface MetadataValueFilter {
|
|
||||||
|
|
||||||
/** The language constraint. */
|
|
||||||
language?: string;
|
|
||||||
|
|
||||||
/** The value constraint. */
|
|
||||||
value?: string;
|
|
||||||
|
|
||||||
/** Whether the value constraint should match without regard to case. */
|
|
||||||
ignoreCase?: boolean;
|
|
||||||
|
|
||||||
/** Whether the value constraint should match as a substring. */
|
|
||||||
substring?: boolean;
|
|
||||||
}
|
|
@@ -1,10 +1,16 @@
|
|||||||
import { isUndefined } from '../../shared/empty.util';
|
import { isUndefined } from '../../shared/empty.util';
|
||||||
import { MetadataValue, MetadataValueFilter } from './metadata.interfaces';
|
import * as uuidv4 from 'uuid/v4';
|
||||||
import { Metadata } from './metadata.model';
|
import {
|
||||||
|
MetadataMap,
|
||||||
|
MetadataValue,
|
||||||
|
MetadataValueFilter,
|
||||||
|
MetadatumViewModel
|
||||||
|
} from './metadata.models';
|
||||||
|
import { Metadata } from './metadata.utils';
|
||||||
|
|
||||||
const mdValue = (value: string, language?: string): MetadataValue => {
|
const mdValue = (value: string, language?: string): MetadataValue => {
|
||||||
return { value: value, language: isUndefined(language) ? null : language };
|
return { uuid: uuidv4(), value: value, language: isUndefined(language) ? null : language };
|
||||||
}
|
};
|
||||||
|
|
||||||
const dcDescription = mdValue('Some description');
|
const dcDescription = mdValue('Some description');
|
||||||
const dcAbstract = mdValue('Some abstract');
|
const dcAbstract = mdValue('Some abstract');
|
||||||
@@ -13,19 +19,27 @@ const dcTitle1 = mdValue('Title 1');
|
|||||||
const dcTitle2 = mdValue('Title 2', 'en_US');
|
const dcTitle2 = mdValue('Title 2', 'en_US');
|
||||||
const bar = mdValue('Bar');
|
const bar = mdValue('Bar');
|
||||||
|
|
||||||
const singleMap = { 'dc.title': [ dcTitle0 ] };
|
const singleMap = { 'dc.title': [dcTitle0] };
|
||||||
|
|
||||||
const multiMap = {
|
const multiMap = {
|
||||||
'dc.description': [ dcDescription ],
|
'dc.description': [dcDescription],
|
||||||
'dc.description.abstract': [ dcAbstract ],
|
'dc.description.abstract': [dcAbstract],
|
||||||
'dc.title': [ dcTitle1, dcTitle2 ],
|
'dc.title': [dcTitle1, dcTitle2],
|
||||||
'foo': [ bar ]
|
'foo': [bar]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const multiViewModelList = [
|
||||||
|
{ key: 'dc.description', ...dcDescription, order: 0 },
|
||||||
|
{ key: 'dc.description.abstract', ...dcAbstract, order: 0 },
|
||||||
|
{ key: 'dc.title', ...dcTitle1, order: 0 },
|
||||||
|
{ key: 'dc.title', ...dcTitle2, order: 1 },
|
||||||
|
{ key: 'foo', ...bar, order: 0 }
|
||||||
|
];
|
||||||
|
|
||||||
const testMethod = (fn, resultKind, mapOrMaps, keyOrKeys, expected, filter?) => {
|
const testMethod = (fn, resultKind, mapOrMaps, keyOrKeys, expected, filter?) => {
|
||||||
const keys = keyOrKeys instanceof Array ? keyOrKeys : [ keyOrKeys ];
|
const keys = keyOrKeys instanceof Array ? keyOrKeys : [keyOrKeys];
|
||||||
describe('and key' + (keys.length === 1 ? (' ' + keys[0]) : ('s ' + JSON.stringify(keys)))
|
describe('and key' + (keys.length === 1 ? (' ' + keys[0]) : ('s ' + JSON.stringify(keys)))
|
||||||
+ ' with ' + (isUndefined(filter) ? 'no filter' : 'filter ' + JSON.stringify(filter)), () => {
|
+ ' with ' + (isUndefined(filter) ? 'no filter' : 'filter ' + JSON.stringify(filter)), () => {
|
||||||
const result = fn(mapOrMaps, keys, filter);
|
const result = fn(mapOrMaps, keys, filter);
|
||||||
let shouldReturn;
|
let shouldReturn;
|
||||||
if (resultKind === 'boolean') {
|
if (resultKind === 'boolean') {
|
||||||
@@ -34,7 +48,7 @@ const testMethod = (fn, resultKind, mapOrMaps, keyOrKeys, expected, filter?) =>
|
|||||||
shouldReturn = 'undefined';
|
shouldReturn = 'undefined';
|
||||||
} else if (expected instanceof Array) {
|
} else if (expected instanceof Array) {
|
||||||
shouldReturn = 'an array with ' + expected.length + ' ' + (expected.length > 1 ? 'ordered ' : '')
|
shouldReturn = 'an array with ' + expected.length + ' ' + (expected.length > 1 ? 'ordered ' : '')
|
||||||
+ resultKind + (expected.length !== 1 ? 's' : '');
|
+ resultKind + (expected.length !== 1 ? 's' : '');
|
||||||
} else {
|
} else {
|
||||||
shouldReturn = 'a ' + resultKind;
|
shouldReturn = 'a ' + resultKind;
|
||||||
}
|
}
|
||||||
@@ -57,30 +71,30 @@ describe('Metadata', () => {
|
|||||||
});
|
});
|
||||||
describe('with singleMap', () => {
|
describe('with singleMap', () => {
|
||||||
testAll(singleMap, 'foo', []);
|
testAll(singleMap, 'foo', []);
|
||||||
testAll(singleMap, '*', [ dcTitle0 ]);
|
testAll(singleMap, '*', [dcTitle0]);
|
||||||
testAll(singleMap, '*', [], { value: 'baz' });
|
testAll(singleMap, '*', [], { value: 'baz' });
|
||||||
testAll(singleMap, 'dc.title', [ dcTitle0 ]);
|
testAll(singleMap, 'dc.title', [dcTitle0]);
|
||||||
testAll(singleMap, 'dc.*', [ dcTitle0 ]);
|
testAll(singleMap, 'dc.*', [dcTitle0]);
|
||||||
});
|
});
|
||||||
describe('with multiMap', () => {
|
describe('with multiMap', () => {
|
||||||
testAll(multiMap, 'foo', [ bar ]);
|
testAll(multiMap, 'foo', [bar]);
|
||||||
testAll(multiMap, '*', [ dcDescription, dcAbstract, dcTitle1, dcTitle2, bar ]);
|
testAll(multiMap, '*', [dcDescription, dcAbstract, dcTitle1, dcTitle2, bar]);
|
||||||
testAll(multiMap, 'dc.title', [ dcTitle1, dcTitle2 ]);
|
testAll(multiMap, 'dc.title', [dcTitle1, dcTitle2]);
|
||||||
testAll(multiMap, 'dc.*', [ dcDescription, dcAbstract, dcTitle1, dcTitle2 ]);
|
testAll(multiMap, 'dc.*', [dcDescription, dcAbstract, dcTitle1, dcTitle2]);
|
||||||
testAll(multiMap, [ 'dc.title', 'dc.*' ], [ dcTitle1, dcTitle2, dcDescription, dcAbstract ]);
|
testAll(multiMap, ['dc.title', 'dc.*'], [dcTitle1, dcTitle2, dcDescription, dcAbstract]);
|
||||||
});
|
});
|
||||||
describe('with [ singleMap, multiMap ]', () => {
|
describe('with [ singleMap, multiMap ]', () => {
|
||||||
testAll([ singleMap, multiMap ], 'foo', [ bar ]);
|
testAll([singleMap, multiMap], 'foo', [bar]);
|
||||||
testAll([ singleMap, multiMap ], '*', [ dcTitle0 ]);
|
testAll([singleMap, multiMap], '*', [dcTitle0]);
|
||||||
testAll([ singleMap, multiMap ], 'dc.title', [ dcTitle0 ]);
|
testAll([singleMap, multiMap], 'dc.title', [dcTitle0]);
|
||||||
testAll([ singleMap, multiMap ], 'dc.*', [ dcTitle0 ]);
|
testAll([singleMap, multiMap], 'dc.*', [dcTitle0]);
|
||||||
});
|
});
|
||||||
describe('with [ multiMap, singleMap ]', () => {
|
describe('with [ multiMap, singleMap ]', () => {
|
||||||
testAll([ multiMap, singleMap ], 'foo', [ bar ]);
|
testAll([multiMap, singleMap], 'foo', [bar]);
|
||||||
testAll([ multiMap, singleMap ], '*', [ dcDescription, dcAbstract, dcTitle1, dcTitle2, bar ]);
|
testAll([multiMap, singleMap], '*', [dcDescription, dcAbstract, dcTitle1, dcTitle2, bar]);
|
||||||
testAll([ multiMap, singleMap ], 'dc.title', [ dcTitle1, dcTitle2 ]);
|
testAll([multiMap, singleMap], 'dc.title', [dcTitle1, dcTitle2]);
|
||||||
testAll([ multiMap, singleMap ], 'dc.*', [ dcDescription, dcAbstract, dcTitle1, dcTitle2 ]);
|
testAll([multiMap, singleMap], 'dc.*', [dcDescription, dcAbstract, dcTitle1, dcTitle2]);
|
||||||
testAll([ multiMap, singleMap ], [ 'dc.title', 'dc.*' ], [ dcTitle1, dcTitle2, dcDescription, dcAbstract ]);
|
testAll([multiMap, singleMap], ['dc.title', 'dc.*'], [dcTitle1, dcTitle2, dcDescription, dcAbstract]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -93,10 +107,10 @@ describe('Metadata', () => {
|
|||||||
testAllValues({}, '*', []);
|
testAllValues({}, '*', []);
|
||||||
});
|
});
|
||||||
describe('with singleMap', () => {
|
describe('with singleMap', () => {
|
||||||
testAllValues([ singleMap, multiMap ], '*', [ dcTitle0.value ]);
|
testAllValues([singleMap, multiMap], '*', [dcTitle0.value]);
|
||||||
});
|
});
|
||||||
describe('with [ multiMap, singleMap ]', () => {
|
describe('with [ multiMap, singleMap ]', () => {
|
||||||
testAllValues([ multiMap, singleMap ], '*', [ dcDescription.value, dcAbstract.value, dcTitle1.value, dcTitle2.value, bar.value ]);
|
testAllValues([multiMap, singleMap], '*', [dcDescription.value, dcAbstract.value, dcTitle1.value, dcTitle2.value, bar.value]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -112,7 +126,7 @@ describe('Metadata', () => {
|
|||||||
testFirst(singleMap, '*', dcTitle0);
|
testFirst(singleMap, '*', dcTitle0);
|
||||||
});
|
});
|
||||||
describe('with [ multiMap, singleMap ]', () => {
|
describe('with [ multiMap, singleMap ]', () => {
|
||||||
testFirst([ multiMap, singleMap ], '*', dcDescription);
|
testFirst([multiMap, singleMap], '*', dcDescription);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -128,7 +142,7 @@ describe('Metadata', () => {
|
|||||||
testFirstValue(singleMap, '*', dcTitle0.value);
|
testFirstValue(singleMap, '*', dcTitle0.value);
|
||||||
});
|
});
|
||||||
describe('with [ multiMap, singleMap ]', () => {
|
describe('with [ multiMap, singleMap ]', () => {
|
||||||
testFirstValue([ multiMap, singleMap ], '*', dcDescription.value);
|
testFirstValue([multiMap, singleMap], '*', dcDescription.value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -145,7 +159,7 @@ describe('Metadata', () => {
|
|||||||
testHas(singleMap, '*', false, { value: 'baz' });
|
testHas(singleMap, '*', false, { value: 'baz' });
|
||||||
});
|
});
|
||||||
describe('with [ multiMap, singleMap ]', () => {
|
describe('with [ multiMap, singleMap ]', () => {
|
||||||
testHas([ multiMap, singleMap ], '*', true);
|
testHas([multiMap, singleMap], '*', true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -153,7 +167,7 @@ describe('Metadata', () => {
|
|||||||
|
|
||||||
const testValueMatches = (value: MetadataValue, expected: boolean, filter?: MetadataValueFilter) => {
|
const testValueMatches = (value: MetadataValue, expected: boolean, filter?: MetadataValueFilter) => {
|
||||||
describe('with value ' + JSON.stringify(value) + ' and filter '
|
describe('with value ' + JSON.stringify(value) + ' and filter '
|
||||||
+ (isUndefined(filter) ? 'undefined' : JSON.stringify(filter)), () => {
|
+ (isUndefined(filter) ? 'undefined' : JSON.stringify(filter)), () => {
|
||||||
const result = Metadata.valueMatches(value, filter);
|
const result = Metadata.valueMatches(value, filter);
|
||||||
it('should return ' + expected, () => {
|
it('should return ' + expected, () => {
|
||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
@@ -172,4 +186,32 @@ describe('Metadata', () => {
|
|||||||
testValueMatches(mdValue('a', 'en_US'), true, { language: 'en_US' });
|
testValueMatches(mdValue('a', 'en_US'), true, { language: 'en_US' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('toViewModelList method', () => {
|
||||||
|
|
||||||
|
const testToViewModelList = (map: MetadataMap, expected: MetadatumViewModel[]) => {
|
||||||
|
describe('with map ' + JSON.stringify(map), () => {
|
||||||
|
const result = Metadata.toViewModelList(map);
|
||||||
|
it('should return ' + JSON.stringify(expected), () => {
|
||||||
|
expect(result).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
testToViewModelList(multiMap, multiViewModelList);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toMetadataMap method', () => {
|
||||||
|
|
||||||
|
const testToMetadataMap = (metadatumList: MetadatumViewModel[], expected: MetadataMap) => {
|
||||||
|
describe('with metadatum list ' + JSON.stringify(metadatumList), () => {
|
||||||
|
const result = Metadata.toMetadataMap(metadatumList);
|
||||||
|
it('should return ' + JSON.stringify(expected), () => {
|
||||||
|
expect(result).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
testToMetadataMap(multiViewModelList, multiMap);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
75
src/app/core/shared/metadata.models.ts
Normal file
75
src/app/core/shared/metadata.models.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import * as uuidv4 from 'uuid/v4';
|
||||||
|
import { autoserialize, Serialize, Deserialize } from 'cerialize';
|
||||||
|
|
||||||
|
/** A map of metadata keys to an ordered list of MetadataValue objects. */
|
||||||
|
export class MetadataMap {
|
||||||
|
[key: string]: MetadataValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A single metadata value and its properties. */
|
||||||
|
|
||||||
|
export class MetadataValue {
|
||||||
|
|
||||||
|
/** The uuid. */
|
||||||
|
uuid: string = uuidv4();
|
||||||
|
|
||||||
|
/** The language. */
|
||||||
|
@autoserialize
|
||||||
|
language: string;
|
||||||
|
|
||||||
|
/** The string value. */
|
||||||
|
@autoserialize
|
||||||
|
value: string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constraints for matching metadata values. */
|
||||||
|
export interface MetadataValueFilter {
|
||||||
|
/** The language constraint. */
|
||||||
|
language?: string;
|
||||||
|
|
||||||
|
/** The value constraint. */
|
||||||
|
value?: string;
|
||||||
|
|
||||||
|
/** Whether the value constraint should match without regard to case. */
|
||||||
|
ignoreCase?: boolean;
|
||||||
|
|
||||||
|
/** Whether the value constraint should match as a substring. */
|
||||||
|
substring?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MetadatumViewModel {
|
||||||
|
/** The uuid. */
|
||||||
|
uuid: string = uuidv4();
|
||||||
|
|
||||||
|
/** The metadatafield key. */
|
||||||
|
key: string;
|
||||||
|
|
||||||
|
/** The language. */
|
||||||
|
language: string;
|
||||||
|
|
||||||
|
/** The string value. */
|
||||||
|
value: string;
|
||||||
|
|
||||||
|
/** The order. */
|
||||||
|
order: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const MetadataMapSerializer = {
|
||||||
|
Serialize(map: MetadataMap): any {
|
||||||
|
const json = {};
|
||||||
|
Object.keys(map).forEach((key: string) => {
|
||||||
|
json[key] = Serialize(map[key], MetadataValue);
|
||||||
|
});
|
||||||
|
return json;
|
||||||
|
},
|
||||||
|
|
||||||
|
Deserialize(json: any): MetadataMap {
|
||||||
|
const metadataMap: MetadataMap = {};
|
||||||
|
Object.keys(json).forEach((key: string) => {
|
||||||
|
metadataMap[key] = Deserialize(json[key], MetadataValue);
|
||||||
|
});
|
||||||
|
return metadataMap;
|
||||||
|
}
|
||||||
|
};
|
@@ -1,5 +1,11 @@
|
|||||||
import { isEmpty, isNotUndefined, isUndefined } from '../../shared/empty.util';
|
import { isEmpty, isNotUndefined, isUndefined } from '../../shared/empty.util';
|
||||||
import { MetadataMap, MetadataValue, MetadataValueFilter } from './metadata.interfaces';
|
import {
|
||||||
|
MetadataMap,
|
||||||
|
MetadataValue,
|
||||||
|
MetadataValueFilter,
|
||||||
|
MetadatumViewModel
|
||||||
|
} from './metadata.models';
|
||||||
|
import { groupBy, sortBy } from 'lodash';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for working with DSpace object metadata.
|
* Utility class for working with DSpace object metadata.
|
||||||
@@ -27,7 +33,7 @@ export class Metadata {
|
|||||||
*/
|
*/
|
||||||
public static all(mapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
public static all(mapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
||||||
filter?: MetadataValueFilter): MetadataValue[] {
|
filter?: MetadataValueFilter): MetadataValue[] {
|
||||||
const mdMaps: MetadataMap[] = mapOrMaps instanceof Array ? mapOrMaps : [ mapOrMaps ];
|
const mdMaps: MetadataMap[] = mapOrMaps instanceof Array ? mapOrMaps : [mapOrMaps];
|
||||||
const matches: MetadataValue[] = [];
|
const matches: MetadataValue[] = [];
|
||||||
for (const mdMap of mdMaps) {
|
for (const mdMap of mdMaps) {
|
||||||
for (const mdKey of Metadata.resolveKeys(mdMap, keyOrKeys)) {
|
for (const mdKey of Metadata.resolveKeys(mdMap, keyOrKeys)) {
|
||||||
@@ -71,7 +77,7 @@ export class Metadata {
|
|||||||
*/
|
*/
|
||||||
public static first(mdMapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
public static first(mdMapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
||||||
filter?: MetadataValueFilter): MetadataValue {
|
filter?: MetadataValueFilter): MetadataValue {
|
||||||
const mdMaps: MetadataMap[] = mdMapOrMaps instanceof Array ? mdMapOrMaps : [ mdMapOrMaps ];
|
const mdMaps: MetadataMap[] = mdMapOrMaps instanceof Array ? mdMapOrMaps : [mdMapOrMaps];
|
||||||
for (const mdMap of mdMaps) {
|
for (const mdMap of mdMaps) {
|
||||||
for (const key of Metadata.resolveKeys(mdMap, keyOrKeys)) {
|
for (const key of Metadata.resolveKeys(mdMap, keyOrKeys)) {
|
||||||
const values: MetadataValue[] = mdMap[key];
|
const values: MetadataValue[] = mdMap[key];
|
||||||
@@ -144,7 +150,7 @@ export class Metadata {
|
|||||||
* @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) {
|
||||||
if (inputKey.includes('*')) {
|
if (inputKey.includes('*')) {
|
||||||
@@ -160,4 +166,31 @@ export class Metadata {
|
|||||||
}
|
}
|
||||||
return outputKeys;
|
return outputKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static toViewModelList(mdMap: MetadataMap) {
|
||||||
|
let metadatumList: MetadatumViewModel[] = [];
|
||||||
|
Object.keys(mdMap).forEach((key: string) => {
|
||||||
|
const fields = mdMap[key].map(
|
||||||
|
(metadataValue: MetadataValue, index: number) =>
|
||||||
|
Object.assign(
|
||||||
|
{},
|
||||||
|
metadataValue,
|
||||||
|
{
|
||||||
|
order: index,
|
||||||
|
key
|
||||||
|
}));
|
||||||
|
metadatumList = [...metadatumList, ...fields];
|
||||||
|
});
|
||||||
|
return metadatumList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static toMetadataMap(viewModelList: MetadatumViewModel[]) {
|
||||||
|
const metadataMap: MetadataMap = {};
|
||||||
|
const groupedList = groupBy(viewModelList, (viewModel) => viewModel.key);
|
||||||
|
Object.keys(groupedList).forEach((key: string) => {
|
||||||
|
const orderedValues = sortBy(groupedList[key], ['order']);
|
||||||
|
metadataMap[key] = orderedValues.map((value: MetadataValue, index: number) => Object.assign({}, value, { order: index }))
|
||||||
|
});
|
||||||
|
return metadataMap;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -8,7 +8,7 @@ import { FormGroup } from '@angular/forms';
|
|||||||
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.interfaces';
|
import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models';
|
||||||
import { isNotEmpty } from '../../empty.util';
|
import { isNotEmpty } from '../../empty.util';
|
||||||
import { ResourceType } from '../../../core/shared/resource-type';
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
|
|
||||||
@@ -83,11 +83,14 @@ 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 = { value: fieldModel.value as string, language: null };
|
const value: MetadataValue = Object.assign(new MetadataValue(), {
|
||||||
|
value: fieldModel.value as string,
|
||||||
|
language: null
|
||||||
|
});
|
||||||
if (formMetadata.hasOwnProperty(fieldModel.name)) {
|
if (formMetadata.hasOwnProperty(fieldModel.name)) {
|
||||||
formMetadata[fieldModel.name].push(value);
|
formMetadata[fieldModel.name].push(value);
|
||||||
} else {
|
} else {
|
||||||
formMetadata[fieldModel.name] = [ value ];
|
formMetadata[fieldModel.name] = [value];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ import {
|
|||||||
ViewChildren
|
ViewChildren
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
import { hasValue, isNotEmpty } from '../empty.util';
|
import { hasValue, isNotEmpty, isNotUndefined } from '../empty.util';
|
||||||
import { InputSuggestion } from './input-suggestions.model';
|
import { InputSuggestion } from './input-suggestions.model';
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ export class InputSuggestionsComponent implements ControlValueAccessor, OnChange
|
|||||||
*/
|
*/
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (hasValue(changes.suggestions)) {
|
if (hasValue(changes.suggestions)) {
|
||||||
this.show.next(isNotEmpty(changes.suggestions.currentValue));
|
this.show.next(isNotEmpty(changes.suggestions.currentValue) && !changes.suggestions.firstChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ import { AbstractListableElementComponent } from '../../object-collection/shared
|
|||||||
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
||||||
import { TruncatableService } from '../../truncatable/truncatable.service';
|
import { TruncatableService } from '../../truncatable/truncatable.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Metadata } from '../../../core/shared/metadata.model';
|
import { Metadata } from '../../../core/shared/metadata.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-result-grid-element',
|
selector: 'ds-search-result-grid-element',
|
||||||
|
@@ -6,7 +6,7 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
|||||||
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
||||||
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
|
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
|
||||||
import { TruncatableService } from '../../truncatable/truncatable.service';
|
import { TruncatableService } from '../../truncatable/truncatable.service';
|
||||||
import { Metadata } from '../../../core/shared/metadata.model';
|
import { Metadata } from '../../../core/shared/metadata.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-result-list-element',
|
selector: 'ds-search-result-list-element',
|
||||||
|
Reference in New Issue
Block a user