mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
PR 545 Create relationships as an admin in edit item
This commit is contained in:
@@ -1,15 +1,26 @@
|
|||||||
<h5>{{getRelationshipMessageKey() | async | translate}}</h5>
|
<h5>
|
||||||
|
{{getRelationshipMessageKey() | async | translate}}
|
||||||
|
<button class="ml-2 btn btn-success" (click)="openLookup()">
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
<span class="d-none d-sm-inline"> {{"item.edit.relationships.edit.buttons.add" | translate}}</span>
|
||||||
|
</button>
|
||||||
|
</h5>
|
||||||
<ng-container *ngVar="updates$ | async as updates">
|
<ng-container *ngVar="updates$ | async as updates">
|
||||||
<ng-container *ngIf="updates">
|
<ng-container *ngIf="updates">
|
||||||
<ng-container *ngVar="updates | dsObjectValues as updateValues">
|
<ng-container *ngVar="updates | dsObjectValues as updateValues">
|
||||||
<ds-edit-relationship *ngFor="let updateValue of updateValues; trackBy: trackUpdate"
|
<ds-edit-relationship *ngFor="let updateValue of updateValues; trackBy: trackUpdate"
|
||||||
class="relationship-row d-block"
|
class="relationship-row d-block alert"
|
||||||
[fieldUpdate]="updateValue"
|
[fieldUpdate]="updateValue || {}"
|
||||||
[url]="url"
|
[url]="url"
|
||||||
[editItem]="item"
|
[editItem]="item"
|
||||||
[ngClass]="{'alert alert-danger': updateValue?.changeType === 2}">
|
[ngClass]="{
|
||||||
|
'alert-success': updateValue.changeType === 1,
|
||||||
|
'alert-warning': updateValue.changeType === 0,
|
||||||
|
'alert-danger': updateValue.changeType === 2
|
||||||
|
}">
|
||||||
</ds-edit-relationship>
|
</ds-edit-relationship>
|
||||||
|
<div *ngIf="updateValues.length === 0">{{"item.edit.relationships.no-relationships" | translate}}</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<div *ngIf="!updates">no relationships</div>
|
<ds-loading *ngIf="!updates"></ds-loading>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
.relationship-row:not(.alert-danger) {
|
.relationship-row:not(.alert) {
|
||||||
padding: $alert-padding-y 0;
|
padding: $alert-padding-y 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.relationship-row.alert-danger {
|
.relationship-row.alert {
|
||||||
margin-left: -$alert-padding-x;
|
margin-left: -$alert-padding-x;
|
||||||
margin-right: -$alert-padding-x;
|
margin-right: -$alert-padding-x;
|
||||||
margin-top: -1px;
|
margin-top: -1px;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||||
@@ -8,6 +8,7 @@ import { FieldChangeType } from '../../../../core/data/object-updates/object-upd
|
|||||||
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
||||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||||
import { RelationshipTypeService } from '../../../../core/data/relationship-type.service';
|
import { RelationshipTypeService } from '../../../../core/data/relationship-type.service';
|
||||||
|
import { RelationshipService } from '../../../../core/data/relationship.service';
|
||||||
import { RemoteData } from '../../../../core/data/remote-data';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
import { ItemType } from '../../../../core/shared/item-relationships/item-type.model';
|
import { ItemType } from '../../../../core/shared/item-relationships/item-type.model';
|
||||||
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
|
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
|
||||||
@@ -15,6 +16,7 @@ import { Relationship } from '../../../../core/shared/item-relationships/relatio
|
|||||||
import { Item } from '../../../../core/shared/item.model';
|
import { Item } from '../../../../core/shared/item.model';
|
||||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||||
import { getMockLinkService } from '../../../../shared/mocks/link-service.mock';
|
import { getMockLinkService } from '../../../../shared/mocks/link-service.mock';
|
||||||
|
import { SelectableListService } from '../../../../shared/object-list/selectable-list/selectable-list.service';
|
||||||
import { SharedModule } from '../../../../shared/shared.module';
|
import { SharedModule } from '../../../../shared/shared.module';
|
||||||
import { EditRelationshipListComponent } from './edit-relationship-list.component';
|
import { EditRelationshipListComponent } from './edit-relationship-list.component';
|
||||||
|
|
||||||
@@ -22,72 +24,123 @@ let comp: EditRelationshipListComponent;
|
|||||||
let fixture: ComponentFixture<EditRelationshipListComponent>;
|
let fixture: ComponentFixture<EditRelationshipListComponent>;
|
||||||
let de: DebugElement;
|
let de: DebugElement;
|
||||||
|
|
||||||
|
let linkService;
|
||||||
let objectUpdatesService;
|
let objectUpdatesService;
|
||||||
let entityTypeService;
|
let relationshipService;
|
||||||
|
let selectableListService;
|
||||||
|
|
||||||
const url = 'http://test-url.com/test-url';
|
const url = 'http://test-url.com/test-url';
|
||||||
|
|
||||||
let item;
|
let item;
|
||||||
|
let entityType;
|
||||||
|
let relatedEntityType;
|
||||||
let author1;
|
let author1;
|
||||||
let author2;
|
let author2;
|
||||||
let fieldUpdate1;
|
let fieldUpdate1;
|
||||||
let fieldUpdate2;
|
let fieldUpdate2;
|
||||||
let relationship1;
|
let relationships;
|
||||||
let relationship2;
|
|
||||||
let relationshipType;
|
let relationshipType;
|
||||||
let entityType;
|
|
||||||
let relatedEntityType;
|
|
||||||
|
|
||||||
describe('EditRelationshipListComponent', () => {
|
describe('EditRelationshipListComponent', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async(() => {
|
||||||
|
|
||||||
entityType = Object.assign(new ItemType(), {
|
entityType = Object.assign(new ItemType(), {
|
||||||
id: 'entityType',
|
id: 'Publication',
|
||||||
|
uuid: 'Publication',
|
||||||
|
label: 'Publication',
|
||||||
});
|
});
|
||||||
|
|
||||||
relatedEntityType = Object.assign(new ItemType(), {
|
relatedEntityType = Object.assign(new ItemType(), {
|
||||||
id: 'relatedEntityType',
|
id: 'Author',
|
||||||
|
uuid: 'Author',
|
||||||
|
label: 'Author',
|
||||||
});
|
});
|
||||||
|
|
||||||
relationshipType = Object.assign(new RelationshipType(), {
|
relationshipType = Object.assign(new RelationshipType(), {
|
||||||
id: '1',
|
id: '1',
|
||||||
uuid: '1',
|
uuid: '1',
|
||||||
|
leftType: observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
entityType,
|
||||||
|
)),
|
||||||
|
rightType: observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
relatedEntityType,
|
||||||
|
)),
|
||||||
leftwardType: 'isAuthorOfPublication',
|
leftwardType: 'isAuthorOfPublication',
|
||||||
rightwardType: 'isPublicationOfAuthor',
|
rightwardType: 'isPublicationOfAuthor',
|
||||||
leftType: observableOf(new RemoteData(false, false, true, undefined, entityType)),
|
|
||||||
rightType: observableOf(new RemoteData(false, false, true, undefined, relatedEntityType)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
relationship1 = Object.assign(new Relationship(), {
|
author1 = Object.assign(new Item(), {
|
||||||
_links: {
|
id: 'author1',
|
||||||
self: {
|
uuid: 'author1'
|
||||||
href: url + '/2'
|
});
|
||||||
}
|
author2 = Object.assign(new Item(), {
|
||||||
},
|
id: 'author2',
|
||||||
|
uuid: 'author2'
|
||||||
|
});
|
||||||
|
|
||||||
|
relationships = [
|
||||||
|
Object.assign(new Relationship(), {
|
||||||
|
self: url + '/2',
|
||||||
id: '2',
|
id: '2',
|
||||||
uuid: '2',
|
uuid: '2',
|
||||||
leftId: 'author1',
|
relationshipType: observableOf(new RemoteData(
|
||||||
rightId: 'publication',
|
false,
|
||||||
leftItem: observableOf(new RemoteData(false, false, true, undefined, item)),
|
false,
|
||||||
rightItem: observableOf(new RemoteData(false, false, true, undefined, author1)),
|
true,
|
||||||
relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType))
|
undefined,
|
||||||
});
|
relationshipType
|
||||||
|
)),
|
||||||
relationship2 = Object.assign(new Relationship(), {
|
leftItem: observableOf(new RemoteData(
|
||||||
_links: {
|
false,
|
||||||
self: {
|
false,
|
||||||
href: url + '/3'
|
true,
|
||||||
}
|
undefined,
|
||||||
},
|
item,
|
||||||
|
)),
|
||||||
|
rightItem: observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
author1,
|
||||||
|
)),
|
||||||
|
}),
|
||||||
|
Object.assign(new Relationship(), {
|
||||||
|
self: url + '/3',
|
||||||
id: '3',
|
id: '3',
|
||||||
uuid: '3',
|
uuid: '3',
|
||||||
leftId: 'author2',
|
relationshipType: observableOf(new RemoteData(
|
||||||
rightId: 'publication',
|
false,
|
||||||
leftItem: observableOf(new RemoteData(false, false, true, undefined, item)),
|
false,
|
||||||
rightItem: observableOf(new RemoteData(false, false, true, undefined, author2)),
|
true,
|
||||||
relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType))
|
undefined,
|
||||||
});
|
relationshipType
|
||||||
|
)),
|
||||||
|
leftItem: observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
item,
|
||||||
|
)),
|
||||||
|
rightItem: observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
author2,
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
item = Object.assign(new Item(), {
|
item = Object.assign(new Item(), {
|
||||||
_links: {
|
_links: {
|
||||||
@@ -100,84 +153,82 @@ describe('EditRelationshipListComponent', () => {
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
undefined,
|
undefined,
|
||||||
new PaginatedList(new PageInfo(), [relationship1, relationship2])
|
new PaginatedList(new PageInfo(), relationships),
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
author1 = Object.assign(new Item(), {
|
|
||||||
id: 'author1',
|
|
||||||
uuid: 'author1'
|
|
||||||
});
|
|
||||||
author2 = Object.assign(new Item(), {
|
|
||||||
id: 'author2',
|
|
||||||
uuid: 'author2'
|
|
||||||
});
|
|
||||||
|
|
||||||
fieldUpdate1 = {
|
fieldUpdate1 = {
|
||||||
field: author1,
|
field: {
|
||||||
|
uuid: relationships[0].uuid,
|
||||||
|
relationship: relationships[0],
|
||||||
|
type: relationshipType,
|
||||||
|
},
|
||||||
changeType: undefined
|
changeType: undefined
|
||||||
};
|
};
|
||||||
fieldUpdate2 = {
|
fieldUpdate2 = {
|
||||||
field: author2,
|
field: {
|
||||||
|
uuid: relationships[1].uuid,
|
||||||
|
relationship: relationships[1],
|
||||||
|
type: relationshipType,
|
||||||
|
},
|
||||||
changeType: FieldChangeType.REMOVE
|
changeType: FieldChangeType.REMOVE
|
||||||
};
|
};
|
||||||
|
|
||||||
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',
|
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',
|
||||||
{
|
{
|
||||||
getFieldUpdates: observableOf({
|
getFieldUpdates: observableOf({
|
||||||
[author1.uuid]: fieldUpdate1,
|
[relationships[0].uuid]: fieldUpdate1,
|
||||||
[author2.uuid]: fieldUpdate2
|
[relationships[1].uuid]: fieldUpdate2
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
entityTypeService = jasmine.createSpyObj('entityTypeService',
|
relationshipService = jasmine.createSpyObj('relationshipService',
|
||||||
{
|
{
|
||||||
getEntityTypeByLabel: observableOf(new RemoteData(
|
getRelatedItemsByLabel: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [author1, author2]))),
|
||||||
false,
|
getItemRelationshipsByLabel: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), relationships))),
|
||||||
false,
|
isLeftItem: observableOf(true),
|
||||||
true,
|
|
||||||
null,
|
|
||||||
entityType,
|
|
||||||
)),
|
|
||||||
getEntityTypeRelationships: observableOf(new RemoteData(
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
null,
|
|
||||||
new PaginatedList(new PageInfo(), [relationshipType]),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
selectableListService = {};
|
||||||
|
|
||||||
|
linkService = {
|
||||||
|
resolveLink: () => null,
|
||||||
|
resolveLinks: () => null,
|
||||||
|
};
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [SharedModule, TranslateModule.forRoot()],
|
imports: [SharedModule, TranslateModule.forRoot()],
|
||||||
declarations: [EditRelationshipListComponent],
|
declarations: [EditRelationshipListComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ObjectUpdatesService, useValue: objectUpdatesService },
|
{ provide: ObjectUpdatesService, useValue: objectUpdatesService },
|
||||||
{ provide: RelationshipTypeService, useValue: {} },
|
{ provide: RelationshipService, useValue: relationshipService },
|
||||||
{ provide: LinkService, useValue: getMockLinkService() },
|
{ provide: SelectableListService, useValue: selectableListService },
|
||||||
|
{ provide: LinkService, useValue: linkService },
|
||||||
], schemas: [
|
], schemas: [
|
||||||
NO_ERRORS_SCHEMA
|
NO_ERRORS_SCHEMA
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(EditRelationshipListComponent);
|
fixture = TestBed.createComponent(EditRelationshipListComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
de = fixture.debugElement;
|
de = fixture.debugElement;
|
||||||
|
|
||||||
comp.item = item;
|
comp.item = item;
|
||||||
comp.itemType = entityType;
|
comp.itemType = entityType;
|
||||||
comp.url = url;
|
comp.url = url;
|
||||||
comp.relationshipType = relationshipType;
|
comp.relationshipType = relationshipType;
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('changeType is REMOVE', () => {
|
describe('changeType is REMOVE', () => {
|
||||||
it('the div should have class alert-danger', () => {
|
beforeEach(() => {
|
||||||
|
|
||||||
fieldUpdate1.changeType = FieldChangeType.REMOVE;
|
fieldUpdate1.changeType = FieldChangeType.REMOVE;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
it('the div should have class alert-danger', () => {
|
||||||
const element = de.queryAll(By.css('.relationship-row'))[1].nativeElement;
|
const element = de.queryAll(By.css('.relationship-row'))[1].nativeElement;
|
||||||
expect(element.classList).toContain('alert-danger');
|
expect(element.classList).toContain('alert-danger');
|
||||||
});
|
});
|
||||||
|
@@ -1,11 +1,23 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { LinkService } from '../../../../core/cache/builders/link.service';
|
import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||||
|
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
||||||
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import {FieldUpdate, FieldUpdates} from '../../../../core/data/object-updates/object-updates.reducer';
|
import {
|
||||||
|
FieldUpdate,
|
||||||
|
FieldUpdates,
|
||||||
|
RelationshipIdentifiable
|
||||||
|
} from '../../../../core/data/object-updates/object-updates.reducer';
|
||||||
|
import { RelationshipService } from '../../../../core/data/relationship.service';
|
||||||
import {Item} from '../../../../core/shared/item.model';
|
import {Item} from '../../../../core/shared/item.model';
|
||||||
import { map, switchMap, tap } from 'rxjs/operators';
|
import {
|
||||||
import {hasValue} from '../../../../shared/empty.util';
|
defaultIfEmpty, filter, flatMap,
|
||||||
|
map, startWith,
|
||||||
|
switchMap,
|
||||||
|
take, tap,
|
||||||
|
} from 'rxjs/operators';
|
||||||
|
import { hasValue, isNotEmptyOperator } from '../../../../shared/empty.util';
|
||||||
import {Relationship} from '../../../../core/shared/item-relationships/relationship.model';
|
import {Relationship} from '../../../../core/shared/item-relationships/relationship.model';
|
||||||
import {RelationshipType} from '../../../../core/shared/item-relationships/relationship-type.model';
|
import {RelationshipType} from '../../../../core/shared/item-relationships/relationship-type.model';
|
||||||
import {
|
import {
|
||||||
@@ -13,8 +25,13 @@ import {
|
|||||||
getRemoteDataPayload,
|
getRemoteDataPayload,
|
||||||
getSucceededRemoteData
|
getSucceededRemoteData
|
||||||
} from '../../../../core/shared/operators';
|
} from '../../../../core/shared/operators';
|
||||||
import { combineLatest as observableCombineLatest } from 'rxjs';
|
import { combineLatest as observableCombineLatest, of } from 'rxjs';
|
||||||
import { ItemType } from '../../../../core/shared/item-relationships/item-type.model';
|
import { ItemType } from '../../../../core/shared/item-relationships/item-type.model';
|
||||||
|
import { DsDynamicLookupRelationModalComponent } from '../../../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component';
|
||||||
|
import { RelationshipOptions } from '../../../../shared/form/builder/models/relationship-options.model';
|
||||||
|
import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model';
|
||||||
|
import { SelectableListService } from '../../../../shared/object-list/selectable-list/selectable-list.service';
|
||||||
|
import { SearchResult } from '../../../../shared/search/search-result.model';
|
||||||
import { followLink } from '../../../../shared/utils/follow-link-config.model';
|
import { followLink } from '../../../../shared/utils/follow-link-config.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -46,14 +63,29 @@ export class EditRelationshipListComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input() relationshipType: RelationshipType;
|
@Input() relationshipType: RelationshipType;
|
||||||
|
|
||||||
|
private relatedEntityType$: Observable<ItemType>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list ID to save selected entities under
|
||||||
|
*/
|
||||||
|
listId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The FieldUpdates for the relationships in question
|
* The FieldUpdates for the relationships in question
|
||||||
*/
|
*/
|
||||||
updates$: Observable<FieldUpdates>;
|
updates$: Observable<FieldUpdates>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the lookup window
|
||||||
|
*/
|
||||||
|
modalRef: NgbModalRef;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected objectUpdatesService: ObjectUpdatesService,
|
protected objectUpdatesService: ObjectUpdatesService,
|
||||||
protected linkService: LinkService
|
protected linkService: LinkService,
|
||||||
|
protected relationshipService: RelationshipService,
|
||||||
|
protected modalService: NgbModal,
|
||||||
|
protected selectableListService: SelectableListService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +109,6 @@ export class EditRelationshipListComponent implements OnInit {
|
|||||||
* Get the relevant label for this relationship type
|
* Get the relevant label for this relationship type
|
||||||
*/
|
*/
|
||||||
private getLabel(): Observable<string> {
|
private getLabel(): Observable<string> {
|
||||||
|
|
||||||
return observableCombineLatest([
|
return observableCombineLatest([
|
||||||
this.relationshipType.leftType,
|
this.relationshipType.leftType,
|
||||||
this.relationshipType.rightType,
|
this.relationshipType.rightType,
|
||||||
@@ -99,19 +130,189 @@ export class EditRelationshipListComponent implements OnInit {
|
|||||||
return update && update.field ? update.field.uuid : undefined;
|
return update && update.field ? update.field.uuid : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the dynamic lookup modal to search for items to add as relationships
|
||||||
|
*/
|
||||||
|
openLookup() {
|
||||||
|
|
||||||
|
this.modalRef = this.modalService.open(DsDynamicLookupRelationModalComponent, {
|
||||||
|
size: 'lg'
|
||||||
|
});
|
||||||
|
const modalComp: DsDynamicLookupRelationModalComponent = this.modalRef.componentInstance;
|
||||||
|
modalComp.repeatable = true;
|
||||||
|
modalComp.listId = this.listId;
|
||||||
|
modalComp.item = this.item;
|
||||||
|
modalComp.select = (...selectableObjects: Array<SearchResult<Item>>) => {
|
||||||
|
selectableObjects.forEach((searchResult) => {
|
||||||
|
const relatedItem: Item = searchResult.indexableObject;
|
||||||
|
this.getFieldUpdatesForRelatedItem(relatedItem)
|
||||||
|
.subscribe((identifiables) => {
|
||||||
|
identifiables.forEach((identifiable) =>
|
||||||
|
this.objectUpdatesService.removeSingleFieldUpdate(this.url, identifiable.uuid)
|
||||||
|
);
|
||||||
|
if (identifiables.length === 0) {
|
||||||
|
this.relationshipService.getNameVariant(this.listId, relatedItem.uuid)
|
||||||
|
.subscribe((nameVariant) => {
|
||||||
|
const update = {
|
||||||
|
uuid: this.relationshipType.id + '-' + relatedItem.uuid,
|
||||||
|
nameVariant,
|
||||||
|
type: this.relationshipType,
|
||||||
|
relatedItem,
|
||||||
|
} as RelationshipIdentifiable;
|
||||||
|
this.objectUpdatesService.saveAddFieldUpdate(this.url, update);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
};
|
||||||
|
modalComp.deselect = (...selectableObjects: Array<SearchResult<Item>>) => {
|
||||||
|
selectableObjects.forEach((searchResult) => {
|
||||||
|
const relatedItem: Item = searchResult.indexableObject;
|
||||||
|
this.objectUpdatesService.removeSingleFieldUpdate(this.url, this.relationshipType.id + '-' + relatedItem.uuid);
|
||||||
|
this.getFieldUpdatesForRelatedItem(relatedItem)
|
||||||
|
.subscribe((identifiables) =>
|
||||||
|
identifiables.forEach((identifiable) =>
|
||||||
|
this.objectUpdatesService.saveRemoveFieldUpdate(this.url, identifiable)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
this.relatedEntityType$
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe((relatedEntityType) => {
|
||||||
|
modalComp.relationshipOptions = Object.assign(
|
||||||
|
new RelationshipOptions(), {
|
||||||
|
relationshipType: relatedEntityType.label,
|
||||||
|
// filter: this.getRelationshipMessageKey(),
|
||||||
|
searchConfiguration: relatedEntityType.label.toLowerCase(),
|
||||||
|
nameVariants: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.selectableListService.deselectAll(this.listId);
|
||||||
|
this.updates$.pipe(
|
||||||
|
switchMap((updates) => observableCombineLatest(
|
||||||
|
Object.values(updates)
|
||||||
|
.filter((update) => update.changeType !== FieldChangeType.REMOVE)
|
||||||
|
.map((update) => {
|
||||||
|
const field = update.field as RelationshipIdentifiable;
|
||||||
|
if (field.relationship) {
|
||||||
|
return this.getRelatedItem(field.relationship);
|
||||||
|
} else {
|
||||||
|
return of(field.relatedItem);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)),
|
||||||
|
take(1),
|
||||||
|
map((items) => items.map((item) => {
|
||||||
|
const searchResult = new ItemSearchResult();
|
||||||
|
searchResult.indexableObject = item;
|
||||||
|
searchResult.hitHighlights = {};
|
||||||
|
return searchResult;
|
||||||
|
})),
|
||||||
|
).subscribe((items) => {
|
||||||
|
this.selectableListService.select(this.listId, items);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the existing field updates regarding a relationship with a given item
|
||||||
|
* @param relatedItem The item for which to get the existing field updates
|
||||||
|
*/
|
||||||
|
private getFieldUpdatesForRelatedItem(relatedItem: Item): Observable<RelationshipIdentifiable[]> {
|
||||||
|
|
||||||
|
return this.updates$.pipe(
|
||||||
|
take(1),
|
||||||
|
map((updates) => Object.values(updates)
|
||||||
|
.map((update) => update.field as RelationshipIdentifiable)
|
||||||
|
.filter((field) => field.relationship)
|
||||||
|
),
|
||||||
|
flatMap((identifiables) =>
|
||||||
|
observableCombineLatest(
|
||||||
|
identifiables.map((identifiable) => this.getRelatedItem(identifiable.relationship))
|
||||||
|
).pipe(
|
||||||
|
defaultIfEmpty([]),
|
||||||
|
map((relatedItems) =>
|
||||||
|
identifiables.filter((identifiable, index) => relatedItems[index].uuid === relatedItem.uuid)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the related item for a given relationship
|
||||||
|
* @param relationship The relationship for which to get the related item
|
||||||
|
*/
|
||||||
|
private getRelatedItem(relationship: Relationship): Observable<Item> {
|
||||||
|
return this.relationshipService.isLeftItem(relationship, this.item).pipe(
|
||||||
|
switchMap((isLeftItem) => isLeftItem ? relationship.rightItem : relationship.leftItem),
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.updates$ = this.item.relationships.pipe(
|
this.listId = 'edit-relationship-' + this.itemType.id;
|
||||||
|
|
||||||
|
this.relatedEntityType$ =
|
||||||
|
observableCombineLatest([
|
||||||
|
this.relationshipType.leftType,
|
||||||
|
this.relationshipType.rightType,
|
||||||
|
].map((type) => type.pipe(
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
))).pipe(
|
||||||
|
map((relatedTypes) => relatedTypes.find((relatedType) => relatedType.uuid !== this.itemType.uuid)),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.updates$ = this.getItemRelationships().pipe(
|
||||||
|
switchMap((relationships) =>
|
||||||
|
observableCombineLatest(
|
||||||
|
relationships.map((relationship) => this.relationshipService.isLeftItem(relationship, this.item))
|
||||||
|
).pipe(
|
||||||
|
defaultIfEmpty([]),
|
||||||
|
map((isLeftItemArray) => isLeftItemArray.map((isLeftItem, index) => {
|
||||||
|
const relationship = relationships[index];
|
||||||
|
const nameVariant = isLeftItem ? relationship.rightwardValue : relationship.leftwardValue;
|
||||||
|
return {
|
||||||
|
uuid: relationship.id,
|
||||||
|
type: this.relationshipType,
|
||||||
|
relationship,
|
||||||
|
nameVariant,
|
||||||
|
} as RelationshipIdentifiable
|
||||||
|
})),
|
||||||
|
)),
|
||||||
|
switchMap((initialFields) => this.objectUpdatesService.getFieldUpdates(this.url, initialFields).pipe(
|
||||||
|
map((fieldUpdates) => {
|
||||||
|
const fieldUpdatesFiltered: FieldUpdates = {};
|
||||||
|
Object.keys(fieldUpdates).forEach((uuid) => {
|
||||||
|
const field = fieldUpdates[uuid].field;
|
||||||
|
if ((field as RelationshipIdentifiable).type.id === this.relationshipType.id) {
|
||||||
|
fieldUpdatesFiltered[uuid] = fieldUpdates[uuid];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return fieldUpdatesFiltered;
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getItemRelationships() {
|
||||||
|
this.linkService.resolveLink(this.item, followLink('relationships'));
|
||||||
|
return this.item.relationships.pipe(
|
||||||
getAllSucceededRemoteData(),
|
getAllSucceededRemoteData(),
|
||||||
map((relationships) => relationships.payload.page.filter((relationship) => relationship)),
|
map((relationships) => relationships.payload.page.filter((relationship) => relationship)),
|
||||||
map((relationships: Relationship[]) =>
|
filter((relationships) => relationships.every((relationship) => !!relationship)),
|
||||||
relationships.map((relationship: Relationship) => {
|
tap((relationships: Relationship[]) =>
|
||||||
|
relationships.forEach((relationship: Relationship) => {
|
||||||
this.linkService.resolveLinks(
|
this.linkService.resolveLinks(
|
||||||
relationship,
|
relationship,
|
||||||
followLink('relationshipType'),
|
followLink('relationshipType'),
|
||||||
followLink('leftItem'),
|
followLink('leftItem'),
|
||||||
followLink('rightItem'),
|
followLink('rightItem'),
|
||||||
);
|
);
|
||||||
return relationship;
|
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
switchMap((itemRelationships: Relationship[]) =>
|
switchMap((itemRelationships: Relationship[]) =>
|
||||||
@@ -122,15 +323,12 @@ export class EditRelationshipListComponent implements OnInit {
|
|||||||
getRemoteDataPayload(),
|
getRemoteDataPayload(),
|
||||||
))
|
))
|
||||||
).pipe(
|
).pipe(
|
||||||
|
defaultIfEmpty([]),
|
||||||
map((relationshipTypes) => itemRelationships.filter(
|
map((relationshipTypes) => itemRelationships.filter(
|
||||||
(relationship, index) => relationshipTypes[index].id === this.relationshipType.id)
|
(relationship, index) => relationshipTypes[index].id === this.relationshipType.id)
|
||||||
),
|
),
|
||||||
map((relationships) => relationships.map((relationship) =>
|
|
||||||
Object.assign(new Relationship(), relationship, {uuid: relationship.id})
|
|
||||||
)),
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
switchMap((initialFields) => this.objectUpdatesService.getFieldUpdates(this.url, initialFields)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
<div class="row" *ngIf="relatedItem$ | async">
|
<div class="row" *ngIf="relatedItem$ | async">
|
||||||
<div class="col-10 relationship">
|
<div class="col-10 relationship">
|
||||||
<ds-listable-object-component-loader [object]="relatedItem$ | async" [viewMode]="viewMode"></ds-listable-object-component-loader>
|
<ds-listable-object-component-loader
|
||||||
|
[object]="relatedItem$ | async"
|
||||||
|
[viewMode]="viewMode"
|
||||||
|
[value]="nameVariant"
|
||||||
|
>
|
||||||
|
</ds-listable-object-component-loader>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<div class="btn-group relationship-action-buttons">
|
<div class="btn-group relationship-action-buttons">
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||||
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
||||||
@@ -25,7 +25,7 @@ let fieldUpdate2;
|
|||||||
let relationships;
|
let relationships;
|
||||||
let relationshipType;
|
let relationshipType;
|
||||||
|
|
||||||
let fixture;
|
let fixture: ComponentFixture<EditRelationshipComponent>;
|
||||||
let comp: EditRelationshipComponent;
|
let comp: EditRelationshipComponent;
|
||||||
let de;
|
let de;
|
||||||
let el;
|
let el;
|
||||||
@@ -91,11 +91,17 @@ describe('EditRelationshipComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
fieldUpdate1 = {
|
fieldUpdate1 = {
|
||||||
field: relationships[0],
|
field: {
|
||||||
|
uuid: relationships[0].uuid,
|
||||||
|
relationship: relationships[0],
|
||||||
|
},
|
||||||
changeType: undefined
|
changeType: undefined
|
||||||
};
|
};
|
||||||
fieldUpdate2 = {
|
fieldUpdate2 = {
|
||||||
field: relationships[1],
|
field: {
|
||||||
|
uuid: relationships[1].uuid,
|
||||||
|
relationship: relationships[1],
|
||||||
|
},
|
||||||
changeType: FieldChangeType.REMOVE
|
changeType: FieldChangeType.REMOVE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
import { combineLatest as observableCombineLatest, Observable, of } from 'rxjs';
|
||||||
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
|
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
|
||||||
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
||||||
import { DeleteRelationship, FieldUpdate } from '../../../../core/data/object-updates/object-updates.reducer';
|
import {
|
||||||
|
DeleteRelationship,
|
||||||
|
FieldUpdate,
|
||||||
|
RelationshipIdentifiable
|
||||||
|
} 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 { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
|
|
||||||
import { Item } from '../../../../core/shared/item.model';
|
import { Item } from '../../../../core/shared/item.model';
|
||||||
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
|
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
|
||||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||||
@@ -36,8 +39,16 @@ export class EditRelationshipComponent implements OnChanges {
|
|||||||
/**
|
/**
|
||||||
* The relationship being edited
|
* The relationship being edited
|
||||||
*/
|
*/
|
||||||
get relationship(): Relationship {
|
get relationship() {
|
||||||
return this.fieldUpdate.field as Relationship;
|
return this.update.relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
get update() {
|
||||||
|
return this.fieldUpdate.field as RelationshipIdentifiable;
|
||||||
|
}
|
||||||
|
|
||||||
|
get nameVariant() {
|
||||||
|
return this.update.nameVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
public leftItem$: Observable<Item>;
|
public leftItem$: Observable<Item>;
|
||||||
@@ -68,6 +79,7 @@ export class EditRelationshipComponent implements OnChanges {
|
|||||||
* Sets the current relationship based on the fieldUpdate input field
|
* Sets the current relationship based on the fieldUpdate input field
|
||||||
*/
|
*/
|
||||||
ngOnChanges(): void {
|
ngOnChanges(): void {
|
||||||
|
if (this.relationship) {
|
||||||
this.leftItem$ = this.relationship.leftItem.pipe(
|
this.leftItem$ = this.relationship.leftItem.pipe(
|
||||||
getSucceededRemoteData(),
|
getSucceededRemoteData(),
|
||||||
getRemoteDataPayload(),
|
getRemoteDataPayload(),
|
||||||
@@ -86,6 +98,9 @@ export class EditRelationshipComponent implements OnChanges {
|
|||||||
items.find((item) => item.uuid !== this.editItem.uuid)
|
items.find((item) => item.uuid !== this.editItem.uuid)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
this.relatedItem$ = of(this.update.relatedItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,7 +151,8 @@ export class EditRelationshipComponent implements OnChanges {
|
|||||||
* Check if a user should be allowed to remove this field
|
* Check if a user should be allowed to remove this field
|
||||||
*/
|
*/
|
||||||
canRemove(): boolean {
|
canRemove(): boolean {
|
||||||
return this.fieldUpdate.changeType !== FieldChangeType.REMOVE;
|
return this.fieldUpdate.changeType !== FieldChangeType.REMOVE
|
||||||
|
&& this.fieldUpdate.changeType !== FieldChangeType.ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -19,14 +19,19 @@
|
|||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngFor="let relationshipType of relationshipTypes$ | async" class="mb-4">
|
<ng-container *ngVar="relationshipTypes$ | async as relationshipTypes">
|
||||||
|
<ng-container *ngIf="relationshipTypes">
|
||||||
|
<div *ngFor="let relationshipType of relationshipTypes" class="mb-4">
|
||||||
<ds-edit-relationship-list
|
<ds-edit-relationship-list
|
||||||
[url]="url"
|
[url]="url"
|
||||||
[item]="item"
|
[item]="item"
|
||||||
[itemType]="entityType"
|
[itemType]="entityType$ | async"
|
||||||
[relationshipType]="relationshipType"
|
[relationshipType]="relationshipType"
|
||||||
></ds-edit-relationship-list>
|
></ds-edit-relationship-list>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ds-loading *ngIf="!relationshipTypes"></ds-loading>
|
||||||
|
</ng-container>
|
||||||
<div class="button-row bottom">
|
<div class="button-row bottom">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
<button class="btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||||
|
@@ -1,9 +1,14 @@
|
|||||||
import { ChangeDetectorRef, Component, Inject, OnDestroy } from '@angular/core';
|
import { ChangeDetectorRef, Component, Inject, OnDestroy } from '@angular/core';
|
||||||
import { Item } from '../../../core/shared/item.model';
|
import { Item } from '../../../core/shared/item.model';
|
||||||
import { DeleteRelationship, FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
import {
|
||||||
|
DeleteRelationship,
|
||||||
|
FieldUpdate,
|
||||||
|
FieldUpdates,
|
||||||
|
RelationshipIdentifiable,
|
||||||
|
} from '../../../core/data/object-updates/object-updates.reducer';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { filter, map, switchMap, take } from 'rxjs/operators';
|
import { filter, map, startWith, switchMap, take} from 'rxjs/operators';
|
||||||
import { of as observableOf, zip as observableZip} from 'rxjs';
|
import { combineLatest as observableCombineLatest, of as observableOf, zip as observableZip} from 'rxjs';
|
||||||
import { followLink } from '../../../shared/utils/follow-link-config.model';
|
import { followLink } from '../../../shared/utils/follow-link-config.model';
|
||||||
import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component';
|
import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component';
|
||||||
import { ItemDataService } from '../../../core/data/item-data.service';
|
import { ItemDataService } from '../../../core/data/item-data.service';
|
||||||
@@ -33,18 +38,18 @@ import { Relationship } from '../../../core/shared/item-relationships/relationsh
|
|||||||
/**
|
/**
|
||||||
* Component for displaying an item's relationships edit page
|
* Component for displaying an item's relationships edit page
|
||||||
*/
|
*/
|
||||||
export class ItemRelationshipsComponent extends AbstractItemUpdateComponent implements OnDestroy {
|
export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
|
||||||
|
|
||||||
|
itemRD$: Observable<RemoteData<Item>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The labels of all different relations within this item
|
* The allowed relationship types for this type of item as an observable list
|
||||||
*/
|
*/
|
||||||
relationshipTypes$: Observable<RelationshipType[]>;
|
relationshipTypes$: Observable<RelationshipType[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subscription that checks when the item is deleted in cache and reloads the item by sending a new request
|
* The item's entity type as an observable
|
||||||
* This is used to update the item in cache after relationships are deleted
|
|
||||||
*/
|
*/
|
||||||
itemUpdateSubscription: Subscription;
|
|
||||||
entityType$: Observable<ItemType>;
|
entityType$: Observable<ItemType>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -68,15 +73,29 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent impl
|
|||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
this.itemUpdateSubscription = this.requestService.hasByHrefObservable(this.item.self).pipe(
|
this.initializeItemUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the item (and view) when it's removed in the request cache
|
||||||
|
*/
|
||||||
|
public initializeItemUpdate(): void {
|
||||||
|
this.itemRD$ = this.requestService.hasByHrefObservable(this.item.self).pipe(
|
||||||
filter((exists: boolean) => !exists),
|
filter((exists: boolean) => !exists),
|
||||||
switchMap(() => this.itemService.findById(this.item.uuid,
|
switchMap(() => this.itemService.findById(
|
||||||
|
this.item.uuid,
|
||||||
followLink('owningCollection'),
|
followLink('owningCollection'),
|
||||||
followLink('bundles'),
|
followLink('bundles'),
|
||||||
followLink('relationships'))),
|
followLink('relationships')),
|
||||||
|
),
|
||||||
|
filter((itemRD) => !!itemRD.statusCode),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.itemRD$.pipe(
|
||||||
getSucceededRemoteData(),
|
getSucceededRemoteData(),
|
||||||
).subscribe((itemRD: RemoteData<Item>) => {
|
getRemoteDataPayload(),
|
||||||
this.item = itemRD.payload;
|
).subscribe((item) => {
|
||||||
|
this.item = item;
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
this.initializeUpdates();
|
this.initializeUpdates();
|
||||||
});
|
});
|
||||||
@@ -125,10 +144,12 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent impl
|
|||||||
* Make sure the lists are refreshed afterwards and notifications are sent for success and errors
|
* Make sure the lists are refreshed afterwards and notifications are sent for success and errors
|
||||||
*/
|
*/
|
||||||
public submit(): void {
|
public submit(): void {
|
||||||
|
|
||||||
// Get all the relationships that should be removed
|
// Get all the relationships that should be removed
|
||||||
this.relationshipService.getItemRelationshipsArray(this.item).pipe(
|
const removedRelationshipIDs$: Observable<DeleteRelationship[]> = this.relationshipService.getItemRelationshipsArray(this.item).pipe(
|
||||||
|
startWith([]),
|
||||||
map((relationships: Relationship[]) => relationships.map((relationship) =>
|
map((relationships: Relationship[]) => relationships.map((relationship) =>
|
||||||
Object.assign(new Relationship(), relationship, {uuid: relationship.id})
|
Object.assign(new Relationship(), relationship, { uuid: relationship.id })
|
||||||
)),
|
)),
|
||||||
switchMap((relationships: Relationship[]) => {
|
switchMap((relationships: Relationship[]) => {
|
||||||
return this.objectUpdatesService.getFieldUpdatesExclusive(this.url, relationships) as Observable<FieldUpdates>
|
return this.objectUpdatesService.getFieldUpdatesExclusive(this.url, relationships) as Observable<FieldUpdates>
|
||||||
@@ -138,10 +159,42 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent impl
|
|||||||
.filter((fieldUpdate: FieldUpdate) => fieldUpdate.changeType === FieldChangeType.REMOVE)
|
.filter((fieldUpdate: FieldUpdate) => fieldUpdate.changeType === FieldChangeType.REMOVE)
|
||||||
.map((fieldUpdate: FieldUpdate) => fieldUpdate.field as DeleteRelationship)
|
.map((fieldUpdate: FieldUpdate) => fieldUpdate.field as DeleteRelationship)
|
||||||
),
|
),
|
||||||
isNotEmptyOperator(),
|
);
|
||||||
|
|
||||||
|
const addRelatedItems$: Observable<RelationshipIdentifiable[]> = this.objectUpdatesService.getFieldUpdates(this.url, []).pipe(
|
||||||
|
map((fieldUpdates: FieldUpdates) =>
|
||||||
|
Object.values(fieldUpdates)
|
||||||
|
.filter((fieldUpdate: FieldUpdate) => fieldUpdate.changeType === FieldChangeType.ADD)
|
||||||
|
.map((fieldUpdate: FieldUpdate) => fieldUpdate.field as RelationshipIdentifiable)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
observableCombineLatest(
|
||||||
|
removedRelationshipIDs$,
|
||||||
|
addRelatedItems$,
|
||||||
|
).pipe(
|
||||||
take(1),
|
take(1),
|
||||||
switchMap((deleteRelationships: DeleteRelationship[]) =>
|
).subscribe(([removeRelationshipIDs, addRelatedItems]) => {
|
||||||
observableZip(...deleteRelationships.map((deleteRelationship) => {
|
const actions = [
|
||||||
|
this.deleteRelationships(removeRelationshipIDs),
|
||||||
|
this.addRelationships(addRelatedItems),
|
||||||
|
];
|
||||||
|
actions.forEach((action) =>
|
||||||
|
action.subscribe((response) => {
|
||||||
|
if (response.length > 0) {
|
||||||
|
this.itemRD$.subscribe(() => {
|
||||||
|
this.initializeOriginalFields();
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
this.displayNotifications(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRelationships(deleteRelationshipIDs: DeleteRelationship[]): Observable<RestResponse[]> {
|
||||||
|
return observableZip(...deleteRelationshipIDs.map((deleteRelationship) => {
|
||||||
let copyVirtualMetadata: string;
|
let copyVirtualMetadata: string;
|
||||||
if (deleteRelationship.keepLeftVirtualMetadata && deleteRelationship.keepRightVirtualMetadata) {
|
if (deleteRelationship.keepLeftVirtualMetadata && deleteRelationship.keepRightVirtualMetadata) {
|
||||||
copyVirtualMetadata = 'all';
|
copyVirtualMetadata = 'all';
|
||||||
@@ -154,13 +207,33 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent impl
|
|||||||
}
|
}
|
||||||
return this.relationshipService.deleteRelationship(deleteRelationship.uuid, copyVirtualMetadata);
|
return this.relationshipService.deleteRelationship(deleteRelationship.uuid, copyVirtualMetadata);
|
||||||
}
|
}
|
||||||
))
|
));
|
||||||
),
|
}
|
||||||
).subscribe((responses: RestResponse[]) => {
|
|
||||||
this.itemUpdateSubscription.add(() => {
|
addRelationships(addRelatedItems: RelationshipIdentifiable[]): Observable<RestResponse[]> {
|
||||||
this.displayNotifications(responses);
|
return observableZip(...addRelatedItems.map((addRelationship) =>
|
||||||
});
|
this.entityType$.pipe(
|
||||||
});
|
switchMap((entityType) => this.entityTypeService.isLeftType(addRelationship.type, entityType)),
|
||||||
|
switchMap((isLeftType) => {
|
||||||
|
let leftItem: Item;
|
||||||
|
let rightItem: Item;
|
||||||
|
let leftwardValue: string;
|
||||||
|
let rightwardValue: string;
|
||||||
|
if (isLeftType) {
|
||||||
|
leftItem = this.item;
|
||||||
|
rightItem = addRelationship.relatedItem;
|
||||||
|
leftwardValue = null;
|
||||||
|
rightwardValue = addRelationship.nameVariant;
|
||||||
|
} else {
|
||||||
|
leftItem = addRelationship.relatedItem;
|
||||||
|
rightItem = this.item;
|
||||||
|
leftwardValue = addRelationship.nameVariant;
|
||||||
|
rightwardValue = null;
|
||||||
|
}
|
||||||
|
return this.relationshipService.addRelationship(addRelationship.type.id, leftItem, rightItem, leftwardValue, rightwardValue);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,19 +253,14 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent impl
|
|||||||
this.notificationsService.success(this.getNotificationTitle('saved'), this.getNotificationContent('saved'));
|
this.notificationsService.success(this.getNotificationTitle('saved'), this.getNotificationContent('saved'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends all initial values of this item to the object updates service
|
* Sends all initial values of this item to the object updates service
|
||||||
*/
|
*/
|
||||||
public initializeOriginalFields() {
|
public initializeOriginalFields() {
|
||||||
const initialFields = [];
|
return this.relationshipService.getRelatedItems(this.item).pipe(
|
||||||
this.objectUpdatesService.initialize(this.url, initialFields, this.item.lastModified);
|
take(1),
|
||||||
}
|
).subscribe((items: Item[]) => {
|
||||||
|
this.objectUpdatesService.initialize(this.url, items, this.item.lastModified);
|
||||||
/**
|
});
|
||||||
* Unsubscribe from the item update when the component is destroyed
|
|
||||||
*/
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.itemUpdateSubscription.unsubscribe();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,11 +12,12 @@ import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { GetRequest } from './request.models';
|
import { GetRequest } from './request.models';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import {switchMap, take, tap} from 'rxjs/operators';
|
import {switchMap, take, map} from 'rxjs/operators';
|
||||||
import { RemoteData } from './remote-data';
|
import { RemoteData } from './remote-data';
|
||||||
import {RelationshipType} from '../shared/item-relationships/relationship-type.model';
|
import {RelationshipType} from '../shared/item-relationships/relationship-type.model';
|
||||||
import {PaginatedList} from './paginated-list';
|
import {PaginatedList} from './paginated-list';
|
||||||
import {ItemType} from '../shared/item-relationships/item-type.model';
|
import {ItemType} from '../shared/item-relationships/item-type.model';
|
||||||
|
import {getRemoteDataPayload, getSucceededRemoteData} from '../shared/operators';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service handling all ItemType requests
|
* Service handling all ItemType requests
|
||||||
@@ -51,6 +52,20 @@ export class EntityTypeService extends DataService<ItemType> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given entity type is the left type of a given relationship type, as an observable boolean
|
||||||
|
* @param relationshipType the relationship type for which to check whether the given entity type is the left type
|
||||||
|
* @param entityType the entity type for which to check whether it is the left type of the given relationship type
|
||||||
|
*/
|
||||||
|
isLeftType(relationshipType: RelationshipType, itemType: ItemType): Observable<boolean> {
|
||||||
|
|
||||||
|
return relationshipType.leftType.pipe(
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
map((leftType) => leftType.uuid === itemType.uuid),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the allowed relationship types for an entity type
|
* Get the allowed relationship types for an entity type
|
||||||
* @param entityTypeId
|
* @param entityTypeId
|
||||||
|
@@ -13,9 +13,11 @@ import {
|
|||||||
SelectVirtualMetadataAction,
|
SelectVirtualMetadataAction,
|
||||||
} from './object-updates.actions';
|
} from './object-updates.actions';
|
||||||
import { hasNoValue, hasValue } from '../../../shared/empty.util';
|
import { hasNoValue, hasValue } from '../../../shared/empty.util';
|
||||||
import {Relationship} from '../../shared/item-relationships/relationship.model';
|
import { Relationship} from '../../shared/item-relationships/relationship.model';
|
||||||
import { InjectionToken } from '@angular/core';
|
import { InjectionToken } from '@angular/core';
|
||||||
import { PatchOperationService } from './patch-operation-service/patch-operation.service';
|
import { PatchOperationService } from './patch-operation-service/patch-operation.service';
|
||||||
|
import { Item} from '../../shared/item.model';
|
||||||
|
import { RelationshipType} from '../../shared/item-relationships/relationship-type.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path where discarded objects are saved
|
* Path where discarded objects are saved
|
||||||
@@ -74,11 +76,18 @@ export interface VirtualMetadataSource {
|
|||||||
[uuid: string]: boolean,
|
[uuid: string]: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RelationshipIdentifiable extends Identifiable {
|
||||||
|
nameVariant?: string,
|
||||||
|
relatedItem: Item;
|
||||||
|
relationship: Relationship;
|
||||||
|
type: RelationshipType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fieldupdate interface which represents a relationship selected to be deleted,
|
* A fieldupdate interface which represents a relationship selected to be deleted,
|
||||||
* along with a selection of the virtual metadata to keep
|
* along with a selection of the virtual metadata to keep
|
||||||
*/
|
*/
|
||||||
export interface DeleteRelationship extends Relationship {
|
export interface DeleteRelationship extends RelationshipIdentifiable {
|
||||||
keepLeftVirtualMetadata: boolean,
|
keepLeftVirtualMetadata: boolean,
|
||||||
keepRightVirtualMetadata: boolean,
|
keepRightVirtualMetadata: boolean,
|
||||||
}
|
}
|
||||||
@@ -189,7 +198,7 @@ function addFieldUpdate(state: any, action: AddFieldUpdateAction) {
|
|||||||
const url: string = action.payload.url;
|
const url: string = action.payload.url;
|
||||||
const field: Identifiable = action.payload.field;
|
const field: Identifiable = action.payload.field;
|
||||||
const changeType: FieldChangeType = action.payload.changeType;
|
const changeType: FieldChangeType = action.payload.changeType;
|
||||||
const pageState: ObjectUpdatesEntry = state[url] || {};
|
const pageState: ObjectUpdatesEntry = state[url] || {fieldUpdates: {}};
|
||||||
|
|
||||||
let states = pageState.fieldStates;
|
let states = pageState.fieldStates;
|
||||||
if (changeType === FieldChangeType.ADD) {
|
if (changeType === FieldChangeType.ADD) {
|
||||||
|
@@ -102,8 +102,8 @@ export class RelationshipService extends DataService<Relationship> {
|
|||||||
),
|
),
|
||||||
configureRequest(this.requestService),
|
configureRequest(this.requestService),
|
||||||
switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)),
|
switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)),
|
||||||
getResponseFromEntry(),
|
|
||||||
tap(() => this.refreshRelationshipItemsInCacheByRelationship(id)),
|
tap(() => this.refreshRelationshipItemsInCacheByRelationship(id)),
|
||||||
|
getResponseFromEntry(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +129,9 @@ export class RelationshipService extends DataService<Relationship> {
|
|||||||
map((endpointURL: string) => new PostRequest(this.requestService.generateRequestId(), endpointURL, `${item1.self} \n ${item2.self}`, options)),
|
map((endpointURL: string) => new PostRequest(this.requestService.generateRequestId(), endpointURL, `${item1.self} \n ${item2.self}`, options)),
|
||||||
configureRequest(this.requestService),
|
configureRequest(this.requestService),
|
||||||
switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)),
|
switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)),
|
||||||
getResponseFromEntry(),
|
|
||||||
tap(() => this.refreshRelationshipItemsInCache(item1)),
|
tap(() => this.refreshRelationshipItemsInCache(item1)),
|
||||||
tap(() => this.refreshRelationshipItemsInCache(item2))
|
tap(() => this.refreshRelationshipItemsInCache(item2)),
|
||||||
|
getResponseFromEntry(),
|
||||||
) as Observable<RestResponse>;
|
) as Observable<RestResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,6 +400,20 @@ export class RelationshipService extends DataService<Relationship> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given item is the left item of a given relationship, as an observable boolean
|
||||||
|
* @param relationship the relationship for which to check whether the given item is the left item
|
||||||
|
* @param item the item for which to check whether it is the left item of the given relationship
|
||||||
|
*/
|
||||||
|
public isLeftItem(relationship: Relationship, item: Item): Observable<boolean> {
|
||||||
|
return relationship.leftItem.pipe(
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
filter((leftItem: Item) => hasValue(leftItem) && isNotEmpty(leftItem.uuid)),
|
||||||
|
map((leftItem) => leftItem.uuid === item.uuid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to update the the right or left place of a relationship
|
* Method to update the the right or left place of a relationship
|
||||||
* The useLeftItem field in the reorderable relationship determines which place should be updated
|
* The useLeftItem field in the reorderable relationship determines which place should be updated
|
||||||
|
@@ -1 +1,6 @@
|
|||||||
<ds-person-search-result-list-element [showLabel]="showLabel" [object]="{ indexableObject: object, hitHighlights: {} }" [linkType]="linkType"></ds-person-search-result-list-element>
|
<ds-person-search-result-list-element [object]="{ indexableObject: object, hitHighlights: {} }"
|
||||||
|
[linkType]="linkType"
|
||||||
|
[showLabel]="showLabel"
|
||||||
|
[value]="value"
|
||||||
|
>
|
||||||
|
</ds-person-search-result-list-element>
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<ds-truncatable [id]="dso.id">
|
<ds-truncatable [id]="dso.id">
|
||||||
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
|
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
|
||||||
[routerLink]="['/items/' + dso.id]" class="lead"
|
[routerLink]="['/items/' + dso.id]" class="lead"
|
||||||
[innerHTML]="firstMetadataValue('person.familyName') + ', ' + firstMetadataValue('person.givenName')"></a>
|
[innerHTML]="name"></a>
|
||||||
<span *ngIf="linkType == linkTypes.None"
|
<span *ngIf="linkType == linkTypes.None"
|
||||||
class="lead"
|
class="lead"
|
||||||
[innerHTML]="firstMetadataValue('person.familyName') + ', ' + firstMetadataValue('person.givenName')"></span>
|
[innerHTML]="firstMetadataValue('person.familyName') + ', ' + firstMetadataValue('person.givenName')"></span>
|
||||||
|
@@ -15,4 +15,10 @@ import { Item } from '../../../../../core/shared/item.model';
|
|||||||
* The component for displaying a list element for an item search result of the type Person
|
* The component for displaying a list element for an item search result of the type Person
|
||||||
*/
|
*/
|
||||||
export class PersonSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {
|
export class PersonSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.value ?
|
||||||
|
this.value :
|
||||||
|
this.firstMetadataValue('person.familyName') + ', ' + this.firstMetadataValue('person.givenName');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -61,6 +61,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
|
|||||||
}
|
}
|
||||||
|
|
||||||
select(value) {
|
select(value) {
|
||||||
|
this.relationshipService.setNameVariant(this.listID, this.dso.uuid, value);
|
||||||
this.selectableListService.isObjectSelected(this.listID, this.object)
|
this.selectableListService.isObjectSelected(this.listID, this.object)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((selected) => {
|
.subscribe((selected) => {
|
||||||
@@ -68,7 +69,6 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
|
|||||||
this.selectableListService.selectSingle(this.listID, this.object);
|
this.selectableListService.selectSingle(this.listID, this.object);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.relationshipService.setNameVariant(this.listID, this.dso.uuid, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectCustom(value) {
|
selectCustom(value) {
|
||||||
|
@@ -54,7 +54,7 @@ describe('ExistingMetadataListElementComponent', () => {
|
|||||||
|
|
||||||
relationship = Object.assign(new Relationship(), { leftItem: leftItemRD$, rightItem: rightItemRD$ });
|
relationship = Object.assign(new Relationship(), { leftItem: leftItemRD$, rightItem: rightItemRD$ });
|
||||||
submissionId = '1234';
|
submissionId = '1234';
|
||||||
reoRel = new ReorderableRelationship(relationship, true, relationshipService, {} as any, submissionId);
|
reoRel = new ReorderableRelationship(relationship, true, {} as any, {} as any, submissionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
|
@@ -51,6 +51,8 @@ export class ListableObjectComponentLoaderComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input() showLabel = true;
|
@Input() showLabel = true;
|
||||||
|
|
||||||
|
@Input() value: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directive hook used to place the dynamic child component
|
* Directive hook used to place the dynamic child component
|
||||||
*/
|
*/
|
||||||
@@ -76,6 +78,7 @@ export class ListableObjectComponentLoaderComponent implements OnInit {
|
|||||||
(componentRef.instance as any).showLabel = this.showLabel;
|
(componentRef.instance as any).showLabel = this.showLabel;
|
||||||
(componentRef.instance as any).context = this.context;
|
(componentRef.instance as any).context = this.context;
|
||||||
(componentRef.instance as any).viewMode = this.viewMode;
|
(componentRef.instance as any).viewMode = this.viewMode;
|
||||||
|
(componentRef.instance as any).value = this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -24,6 +24,8 @@ export class AbstractListableElementComponent<T extends ListableObject> {
|
|||||||
*/
|
*/
|
||||||
@Input() listID: string;
|
@Input() listID: string;
|
||||||
|
|
||||||
|
@Input() value: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The index of this element
|
* The index of this element
|
||||||
*/
|
*/
|
||||||
|
@@ -1548,15 +1548,19 @@
|
|||||||
|
|
||||||
"item.edit.relationships.discard-button": "Discard",
|
"item.edit.relationships.discard-button": "Discard",
|
||||||
|
|
||||||
|
"item.edit.relationships.edit.buttons.add": "Add",
|
||||||
|
|
||||||
"item.edit.relationships.edit.buttons.remove": "Remove",
|
"item.edit.relationships.edit.buttons.remove": "Remove",
|
||||||
|
|
||||||
"item.edit.relationships.edit.buttons.undo": "Undo changes",
|
"item.edit.relationships.edit.buttons.undo": "Undo changes",
|
||||||
|
|
||||||
|
"item.edit.relationships.no-relationships": "No relationships",
|
||||||
|
|
||||||
"item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
|
"item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
|
||||||
|
|
||||||
"item.edit.relationships.notifications.discarded.title": "Changes discarded",
|
"item.edit.relationships.notifications.discarded.title": "Changes discarded",
|
||||||
|
|
||||||
"item.edit.relationships.notifications.failed.title": "Error deleting relationship",
|
"item.edit.relationships.notifications.failed.title": "Error editing relationships",
|
||||||
|
|
||||||
"item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts",
|
"item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts",
|
||||||
|
|
||||||
@@ -3027,10 +3031,25 @@
|
|||||||
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Local Authors ({{ count }})",
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Local Authors ({{ count }})",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Local Journals ({{ count }})",
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Local Journals ({{ count }})",
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Local Projects ({{ count }})",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication": "Local Publications ({{ count }})",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Person": "Local Authors ({{ count }})",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit": "Local Organizational Units ({{ count }})",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage": "Local Data Packages ({{ count }})",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile": "Local Data Files ({{ count }})",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Local Journals ({{ count }})",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Local Journal Issues ({{ count }})",
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Local Journal Issues ({{ count }})",
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Local Journal Issues ({{ count }})",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Local Journal Volumes ({{ count }})",
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Local Journal Volumes ({{ count }})",
|
||||||
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Local Journal Volumes ({{ count }})",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa Journals ({{ count }})",
|
"submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa Journals ({{ count }})",
|
||||||
|
|
||||||
@@ -3049,14 +3068,29 @@
|
|||||||
"submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Current Selection ({{ count }})",
|
"submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Current Selection ({{ count }})",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Journal Issues",
|
"submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Journal Issues",
|
||||||
|
"submission.sections.describe.relationship-lookup.title.JournalIssue": "Journal Issues",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Journal Volumes",
|
"submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Journal Volumes",
|
||||||
|
"submission.sections.describe.relationship-lookup.title.JournalVolume": "Journal Volumes",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Journals",
|
"submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Journals",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Authors",
|
"submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Authors",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Funding Agency",
|
"submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Funding Agency",
|
||||||
|
"submission.sections.describe.relationship-lookup.title.Project": "Projects",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.title.Publication": "Publications",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.title.Person": "Authors",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.title.OrgUnit": "Organizational Units",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.title.DataPackage": "Data Packages",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.title.DataFile": "Data Files",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.title.Funding Agency": "Funding Agency",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Funding",
|
"submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Funding",
|
||||||
|
|
||||||
@@ -3073,12 +3107,27 @@
|
|||||||
"submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Selected Journals",
|
"submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Selected Journals",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Selected Journal Volume",
|
"submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Selected Journal Volume",
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Selected Projects",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.Publication": "Selected Publications",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.Person": "Selected Authors",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit": "Selected Organizational Units",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage": "Selected Data Packages",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.DataFile": "Selected Data Files",
|
||||||
|
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Selected Journals",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Selected Issue",
|
"submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Selected Issue",
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Selected Journal Volume",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Selected Funding Agency",
|
"submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Selected Funding Agency",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Selected Funding",
|
"submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Selected Funding",
|
||||||
|
"submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Selected Issue",
|
||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Selected Organizational Unit",
|
"submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Selected Organizational Unit",
|
||||||
|
|
||||||
@@ -3305,7 +3354,7 @@
|
|||||||
|
|
||||||
"uploader.drag-message": "Drag & Drop your files here",
|
"uploader.drag-message": "Drag & Drop your files here",
|
||||||
|
|
||||||
"uploader.or": ", or",
|
"uploader.or": ", or ",
|
||||||
|
|
||||||
"uploader.processing": "Processing",
|
"uploader.processing": "Processing",
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user