mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
62849: moving relation lookup from separate component to option for all input components
This commit is contained in:
@@ -6,20 +6,17 @@
|
|||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"input": {
|
"input": {
|
||||||
"type": "lookup-relation"
|
|
||||||
},
|
},
|
||||||
"label": "Author",
|
"label": "Author",
|
||||||
"mandatory": true,
|
"mandatory": true,
|
||||||
"repeatable": true,
|
"repeatable": true,
|
||||||
"mandatoryMessage": "At least one author (plain text or relationship) is required",
|
"mandatoryMessage": "At least one author (plain text or relationship) is required",
|
||||||
"hints": "Add an author",
|
"hints": "Add an author",
|
||||||
"selectableRelationships": [
|
"selectableRelationship": {
|
||||||
{
|
|
||||||
"relationshipType": "isAuthorOfPublication",
|
"relationshipType": "isAuthorOfPublication",
|
||||||
"filter": null,
|
"filter": null,
|
||||||
"searchConfiguration": "personConfiguration"
|
"searchConfiguration": "personConfiguration"
|
||||||
}
|
},
|
||||||
],
|
|
||||||
"selectableMetadata": [
|
"selectableMetadata": [
|
||||||
{
|
{
|
||||||
"metadata": "dc.contributor.author",
|
"metadata": "dc.contributor.author",
|
||||||
|
@@ -41,4 +41,13 @@
|
|||||||
|
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
|
|
||||||
|
<div *ngIf="hasRelationLookup" class="col-auto text-center">
|
||||||
|
<button class="btn btn-secondary"
|
||||||
|
type="submit"
|
||||||
|
ngbTooltip="{{'form.lookup-help' | translate}}"
|
||||||
|
placement="top"
|
||||||
|
(click)="openLookup(); $event.stopPropagation();">{{'form.lookup' | translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@@ -6,6 +6,7 @@ import {
|
|||||||
EventEmitter,
|
EventEmitter,
|
||||||
Input,
|
Input,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
|
OnInit,
|
||||||
Output,
|
Output,
|
||||||
QueryList,
|
QueryList,
|
||||||
SimpleChanges,
|
SimpleChanges,
|
||||||
@@ -55,7 +56,7 @@ import { DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER } from './models/date-picker/dat
|
|||||||
import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP } from './models/lookup/dynamic-lookup.model';
|
import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP } from './models/lookup/dynamic-lookup.model';
|
||||||
import { DynamicListCheckboxGroupModel } from './models/list/dynamic-list-checkbox-group.model';
|
import { DynamicListCheckboxGroupModel } from './models/list/dynamic-list-checkbox-group.model';
|
||||||
import { DynamicListRadioGroupModel } from './models/list/dynamic-list-radio-group.model';
|
import { DynamicListRadioGroupModel } from './models/list/dynamic-list-radio-group.model';
|
||||||
import { isNotEmpty, isNotUndefined } from '../../../empty.util';
|
import { hasValue, isNotEmpty, isNotUndefined } from '../../../empty.util';
|
||||||
import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME } from './models/lookup/dynamic-lookup-name.model';
|
import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME } from './models/lookup/dynamic-lookup-name.model';
|
||||||
import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component';
|
import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component';
|
||||||
import { DsDatePickerComponent } from './models/date-picker/date-picker.component';
|
import { DsDatePickerComponent } from './models/date-picker/date-picker.component';
|
||||||
@@ -68,8 +69,17 @@ import { DsDynamicFormArrayComponent } from './models/array-group/dynamic-form-a
|
|||||||
import { DsDynamicRelationGroupComponent } from './models/relation-group/dynamic-relation-group.components';
|
import { DsDynamicRelationGroupComponent } from './models/relation-group/dynamic-relation-group.components';
|
||||||
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './models/relation-group/dynamic-relation-group.model';
|
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './models/relation-group/dynamic-relation-group.model';
|
||||||
import { DsDatePickerInlineComponent } from './models/date-picker-inline/dynamic-date-picker-inline.component';
|
import { DsDatePickerInlineComponent } from './models/date-picker-inline/dynamic-date-picker-inline.component';
|
||||||
import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_RELATION } from './models/lookup-relation/dynamic-lookup-relation.model';
|
import { map } from 'rxjs/operators';
|
||||||
import { DsDynamicLookupRelationComponent } from './models/lookup-relation/dynamic-lookup-relation.component';
|
import { SelectableListState } from '../../../object-list/selectable-list/selectable-list.reducer';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { SearchResult } from '../../../search/search-result.model';
|
||||||
|
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { RelationshipService } from '../../../../core/data/relationship.service';
|
||||||
|
import { SelectableListService } from '../../../object-list/selectable-list/selectable-list.service';
|
||||||
|
import { DsDynamicEmptyComponent } from './models/empty/dynamic-empty.component';
|
||||||
|
import { DYNAMIC_FORM_CONTROL_TYPE_EMPTY } from './models/empty/dynamic-empty.model';
|
||||||
|
import { DsDynamicLookupRelationModalComponent } from './models/empty/dynamic-lookup-relation-modal.component';
|
||||||
|
|
||||||
export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
|
export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
|
||||||
switch (model.type) {
|
switch (model.type) {
|
||||||
@@ -126,8 +136,8 @@ export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<
|
|||||||
case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME:
|
case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME:
|
||||||
return DsDynamicLookupComponent;
|
return DsDynamicLookupComponent;
|
||||||
|
|
||||||
case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_RELATION:
|
case DYNAMIC_FORM_CONTROL_TYPE_EMPTY:
|
||||||
return DsDynamicLookupRelationComponent;
|
return DsDynamicEmptyComponent;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@@ -140,7 +150,7 @@ export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<
|
|||||||
templateUrl: './ds-dynamic-form-control-container.component.html',
|
templateUrl: './ds-dynamic-form-control-container.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.Default
|
changeDetection: ChangeDetectionStrategy.Default
|
||||||
})
|
})
|
||||||
export class DsDynamicFormControlContainerComponent extends DynamicFormControlContainerComponent implements OnChanges {
|
export class DsDynamicFormControlContainerComponent extends DynamicFormControlContainerComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
@ContentChildren(DynamicTemplateDirective) contentTemplateList: QueryList<DynamicTemplateDirective>;
|
@ContentChildren(DynamicTemplateDirective) contentTemplateList: QueryList<DynamicTemplateDirective>;
|
||||||
// tslint:disable-next-line:no-input-rename
|
// tslint:disable-next-line:no-input-rename
|
||||||
@@ -155,6 +165,13 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
|||||||
@Input() layout = null as DynamicFormLayout;
|
@Input() layout = null as DynamicFormLayout;
|
||||||
@Input() model: any;
|
@Input() model: any;
|
||||||
|
|
||||||
|
hasRelationLookup: boolean;
|
||||||
|
modalRef: NgbModalRef;
|
||||||
|
modalValuesString = '';
|
||||||
|
listId: string;
|
||||||
|
filter: string;
|
||||||
|
searchConfig: string;
|
||||||
|
|
||||||
/* tslint:disable:no-output-rename */
|
/* tslint:disable:no-output-rename */
|
||||||
@Output('dfBlur') blur: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
@Output('dfBlur') blur: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
||||||
@Output('dfChange') change: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
@Output('dfChange') change: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
||||||
@@ -169,18 +186,31 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
|||||||
return this.layoutService.getCustomComponentType(this.model) || dsDynamicFormControlMapFn(this.model);
|
return this.layoutService.getCustomComponentType(this.model) || dsDynamicFormControlMapFn(this.model);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected test: boolean;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected componentFactoryResolver: ComponentFactoryResolver,
|
protected componentFactoryResolver: ComponentFactoryResolver,
|
||||||
protected layoutService: DynamicFormLayoutService,
|
protected layoutService: DynamicFormLayoutService,
|
||||||
protected validationService: DynamicFormValidationService,
|
protected validationService: DynamicFormValidationService,
|
||||||
protected translateService: TranslateService
|
protected translateService: TranslateService,
|
||||||
|
private modalService: NgbModal,
|
||||||
|
private relationService: RelationshipService,
|
||||||
|
private selectableListService: SelectableListService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
super(componentFactoryResolver, layoutService, validationService);
|
super(componentFactoryResolver, layoutService, validationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.hasRelationLookup = hasValue(this.model.relationship);
|
||||||
|
if (this.hasRelationLookup) {
|
||||||
|
this.filter = this.model.relationship.filter;
|
||||||
|
this.searchConfig = this.model.relationship.searchConfiguration;
|
||||||
|
this.listId = 'list-' + this.model.relationship.relationshipType;
|
||||||
|
this.model.value = this.selectableListService.getSelectableList(this.listId).pipe(
|
||||||
|
map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes) {
|
if (changes) {
|
||||||
super.ngOnChanges(changes);
|
super.ngOnChanges(changes);
|
||||||
@@ -217,4 +247,27 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
|
|||||||
this.onChange(event);
|
this.onChange(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasResultsSelected(): Observable<boolean> {
|
||||||
|
return this.model.value.pipe(map((list: SearchResult<DSpaceObject>[]) => isNotEmpty(list)));
|
||||||
|
}
|
||||||
|
|
||||||
|
openLookup() {
|
||||||
|
this.modalRef = this.modalService.open(DsDynamicLookupRelationModalComponent, { size: 'lg' });
|
||||||
|
const modalComp = this.modalRef.componentInstance;
|
||||||
|
modalComp.repeatable = this.model.repeatable;
|
||||||
|
modalComp.relationKey = this.model.name;
|
||||||
|
modalComp.listId = this.listId;
|
||||||
|
modalComp.filter = this.filter;
|
||||||
|
modalComp.fieldName = this.searchConfig;
|
||||||
|
modalComp.label = this.model.label;
|
||||||
|
|
||||||
|
this.modalRef.result.then((resultString = '') => {
|
||||||
|
this.modalValuesString = resultString;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSelection(object: SearchResult<DSpaceObject>) {
|
||||||
|
this.selectableListService.deselectSingle(this.listId, object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,8 @@ import { AuthorityOptions } from '../../../../../core/integration/models/authori
|
|||||||
import { hasValue } from '../../../../empty.util';
|
import { hasValue } from '../../../../empty.util';
|
||||||
import { FormFieldMetadataValueObject } from '../../models/form-field-metadata-value.model';
|
import { FormFieldMetadataValueObject } from '../../models/form-field-metadata-value.model';
|
||||||
import { Workspaceitem } from '../../../../../core/submission/models/workspaceitem.model';
|
import { Workspaceitem } from '../../../../../core/submission/models/workspaceitem.model';
|
||||||
|
import { RelationshipOptions } from './empty/model/relationship-options.model';
|
||||||
|
import { Item } from '../../../../../core/shared/item.model';
|
||||||
|
|
||||||
export interface DsDynamicInputModelConfig extends DynamicInputModelConfig {
|
export interface DsDynamicInputModelConfig extends DynamicInputModelConfig {
|
||||||
workspaceItem: Workspaceitem;
|
workspaceItem: Workspaceitem;
|
||||||
@@ -18,6 +20,7 @@ export interface DsDynamicInputModelConfig extends DynamicInputModelConfig {
|
|||||||
languageCodes?: LanguageCode[];
|
languageCodes?: LanguageCode[];
|
||||||
language?: string;
|
language?: string;
|
||||||
value?: any;
|
value?: any;
|
||||||
|
relationship?: RelationshipOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DsDynamicInputModel extends DynamicInputModel {
|
export class DsDynamicInputModel extends DynamicInputModel {
|
||||||
@@ -27,12 +30,14 @@ export class DsDynamicInputModel extends DynamicInputModel {
|
|||||||
@serializable() private _language: string;
|
@serializable() private _language: string;
|
||||||
@serializable() languageUpdates: Subject<string>;
|
@serializable() languageUpdates: Subject<string>;
|
||||||
@serializable() workspaceItem: Workspaceitem;
|
@serializable() workspaceItem: Workspaceitem;
|
||||||
|
@serializable() relationship?: RelationshipOptions;
|
||||||
|
|
||||||
constructor(config: DsDynamicInputModelConfig, layout?: DynamicFormControlLayout) {
|
constructor(config: DsDynamicInputModelConfig, layout?: DynamicFormControlLayout) {
|
||||||
super(config, layout);
|
super(config, layout);
|
||||||
|
|
||||||
this.readOnly = config.readOnly;
|
this.readOnly = config.readOnly;
|
||||||
this.value = config.value;
|
this.value = config.value;
|
||||||
|
this.relationship = config.relationship;
|
||||||
this.workspaceItem = config.workspaceItem;
|
this.workspaceItem = config.workspaceItem;
|
||||||
this.language = config.language;
|
this.language = config.language;
|
||||||
if (!this.language) {
|
if (!this.language) {
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
<!--<div>-->
|
||||||
|
<!-- <div *ngIf="model.repeatable || !((model.value | async) && (model.value | async).length > 0)" class="form-row align-items-center">-->
|
||||||
|
<!-- <div class="col">-->
|
||||||
|
<!-- <input class="form-control"-->
|
||||||
|
<!-- [class.is-invalid]="showErrorMessages"-->
|
||||||
|
<!-- [value]="modalValuesString"-->
|
||||||
|
<!-- [disabled]="model.disabled"-->
|
||||||
|
<!-- [type]="model.inputType"-->
|
||||||
|
<!-- [placeholder]="model.placeholder | translate"-->
|
||||||
|
<!-- [readonly]="model.readOnly">-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="col-auto text-center">-->
|
||||||
|
<!-- <button class="btn btn-secondary"-->
|
||||||
|
<!-- type="submit"-->
|
||||||
|
<!-- ngbTooltip="{{'form.lookup-help' | translate}}"-->
|
||||||
|
<!-- placement="top"-->
|
||||||
|
<!-- (click)="openLookup(); $event.stopPropagation();">{{'form.lookup' | translate}}-->
|
||||||
|
<!-- </button>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="mt-3">-->
|
||||||
|
<!-- <ul class="list-unstyled">-->
|
||||||
|
<!-- <li *ngFor="let result of (model.value | async)">-->
|
||||||
|
<!-- <ng-container *ngVar="result.indexableObject as value">-->
|
||||||
|
<!-- <button type="button" class="close float-left" aria-label="Close button"-->
|
||||||
|
<!-- (click)="removeSelection(result)">-->
|
||||||
|
<!-- <span aria-hidden="true">×</span>-->
|
||||||
|
<!-- </button>-->
|
||||||
|
<!-- <span class="d-inline-block align-middle ml-1">{{value.name}}</span>-->
|
||||||
|
<!-- <input [dynamicId]="bindId && model.id"-->
|
||||||
|
<!-- [name]="model.name"-->
|
||||||
|
<!-- type="hidden"-->
|
||||||
|
<!-- [ngModel]="value.uuid"-->
|
||||||
|
<!-- [disabled]="true"-->
|
||||||
|
<!-- [readonly]="true">-->
|
||||||
|
<!-- </ng-container>-->
|
||||||
|
<!-- </li>-->
|
||||||
|
<!-- </ul>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!--</div>-->
|
@@ -0,0 +1,32 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
|
import { DynamicFormControlComponent, DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { DynamicEmptyModel } from './dynamic-empty.model';
|
||||||
|
|
||||||
|
/* TODO take a look at this when the REST entities submission is finished: we will probably need to get the fixed filter from the REST instead of filtering is out from the metadata field */
|
||||||
|
const RELATION_TYPE_METADATA_PREFIX = 'relation.isPublicationOf';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-dynamic-empty',
|
||||||
|
templateUrl: './dynamic-empty.component.html'
|
||||||
|
})
|
||||||
|
export class DsDynamicEmptyComponent extends DynamicFormControlComponent {
|
||||||
|
|
||||||
|
@Input() formId: string;
|
||||||
|
@Input() group: FormGroup;
|
||||||
|
@Input() model: DynamicEmptyModel;
|
||||||
|
|
||||||
|
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
@Output() focus: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
|
||||||
|
|
||||||
|
constructor(protected layoutService: DynamicFormLayoutService,
|
||||||
|
protected validationService: DynamicFormValidationService
|
||||||
|
) {
|
||||||
|
super(layoutService, validationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,26 @@
|
|||||||
|
import { DynamicFormControlLayout, serializable } from '@ng-dynamic-forms/core';
|
||||||
|
import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-input.model';
|
||||||
|
|
||||||
|
export const DYNAMIC_FORM_CONTROL_TYPE_EMPTY = 'EMPTY';
|
||||||
|
|
||||||
|
export interface DsDynamicEmptyModelConfig extends DsDynamicInputModelConfig {
|
||||||
|
value?: any;
|
||||||
|
repeatable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DynamicEmptyModel extends DsDynamicInputModel {
|
||||||
|
|
||||||
|
@serializable() readonly type: string = DYNAMIC_FORM_CONTROL_TYPE_EMPTY;
|
||||||
|
@serializable() value: any;
|
||||||
|
@serializable() repeatable: boolean;
|
||||||
|
|
||||||
|
constructor(config: DsDynamicEmptyModelConfig, layout?: DynamicFormControlLayout) {
|
||||||
|
|
||||||
|
super(config, layout);
|
||||||
|
|
||||||
|
this.readOnly = true;
|
||||||
|
this.disabled = true;
|
||||||
|
this.repeatable = config.repeatable;
|
||||||
|
this.valueUpdates.next(config.value);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,40 +0,0 @@
|
|||||||
<div>
|
|
||||||
<div *ngIf="model.repeatable || !((model.value | async) && (model.value | async).length > 0)" class="form-row align-items-center">
|
|
||||||
<div class="col">
|
|
||||||
<input class="form-control"
|
|
||||||
[class.is-invalid]="showErrorMessages"
|
|
||||||
[value]="modalValuesString"
|
|
||||||
[disabled]="model.disabled"
|
|
||||||
[type]="model.inputType"
|
|
||||||
[placeholder]="model.placeholder | translate"
|
|
||||||
[readonly]="model.readOnly">
|
|
||||||
</div>
|
|
||||||
<div class="col-auto text-center">
|
|
||||||
<button class="btn btn-secondary"
|
|
||||||
type="submit"
|
|
||||||
ngbTooltip="{{'form.lookup-help' | translate}}"
|
|
||||||
placement="top"
|
|
||||||
(click)="openLookup(); $event.stopPropagation();">{{'form.lookup' | translate}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-3">
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li *ngFor="let result of (model.value | async)">
|
|
||||||
<ng-container *ngVar="result.indexableObject as value">
|
|
||||||
<button type="button" class="close float-left" aria-label="Close button"
|
|
||||||
(click)="removeSelection(result)">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
<span class="d-inline-block align-middle ml-1">{{value.name}}</span>
|
|
||||||
<input [dynamicId]="bindId && model.id"
|
|
||||||
[name]="model.name"
|
|
||||||
type="hidden"
|
|
||||||
[ngModel]="value.uuid"
|
|
||||||
[disabled]="true"
|
|
||||||
[readonly]="true">
|
|
||||||
</ng-container>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@@ -1,81 +0,0 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
|
||||||
|
|
||||||
import { DynamicFormControlComponent, DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
|
||||||
import { FormGroup } from '@angular/forms';
|
|
||||||
import { hasValue, isNotEmpty } from '../../../../../empty.util';
|
|
||||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
import { DsDynamicLookupRelationModalComponent } from './dynamic-lookup-relation-modal.component';
|
|
||||||
import { DynamicLookupRelationModel } from './dynamic-lookup-relation.model';
|
|
||||||
import { DSpaceObject } from '../../../../../../core/shared/dspace-object.model';
|
|
||||||
import { RelationshipService } from '../../../../../../core/data/relationship.service';
|
|
||||||
import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service';
|
|
||||||
import { SelectableListState } from '../../../../../object-list/selectable-list/selectable-list.reducer';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
|
||||||
import { SearchResult } from '../../../../../search/search-result.model';
|
|
||||||
|
|
||||||
/* TODO take a look at this when the REST entities submission is finished: we will probably need to get the fixed filter from the REST instead of filtering is out from the metadata field */
|
|
||||||
const RELATION_TYPE_METADATA_PREFIX = 'relation.isPublicationOf';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-dynamic-lookup-relation',
|
|
||||||
templateUrl: './dynamic-lookup-relation.component.html'
|
|
||||||
})
|
|
||||||
export class DsDynamicLookupRelationComponent extends DynamicFormControlComponent implements OnInit {
|
|
||||||
|
|
||||||
@Input() formId: string;
|
|
||||||
@Input() group: FormGroup;
|
|
||||||
@Input() model: DynamicLookupRelationModel;
|
|
||||||
|
|
||||||
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
|
|
||||||
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
|
||||||
@Output() focus: EventEmitter<any> = new EventEmitter<any>();
|
|
||||||
|
|
||||||
modalRef: NgbModalRef;
|
|
||||||
modalValuesString = '';
|
|
||||||
listId: string;
|
|
||||||
filter: string;
|
|
||||||
searchConfig: string;
|
|
||||||
|
|
||||||
|
|
||||||
constructor(private modalService: NgbModal,
|
|
||||||
protected layoutService: DynamicFormLayoutService,
|
|
||||||
protected validationService: DynamicFormValidationService,
|
|
||||||
private relationService: RelationshipService,
|
|
||||||
private selectableListService: SelectableListService
|
|
||||||
) {
|
|
||||||
super(layoutService, validationService);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.filter = this.model.relationship.filter;
|
|
||||||
this.searchConfig = this.model.relationship.searchConfiguration;
|
|
||||||
this.listId = 'list-' + this.model.relationship.relationshipType;
|
|
||||||
this.model.value = this.selectableListService.getSelectableList(this.listId).pipe(
|
|
||||||
map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasResultsSelected(): Observable<boolean> {
|
|
||||||
return this.model.value.pipe(map((list: SearchResult<DSpaceObject>[]) => isNotEmpty(list)));
|
|
||||||
}
|
|
||||||
|
|
||||||
openLookup() {
|
|
||||||
this.modalRef = this.modalService.open(DsDynamicLookupRelationModalComponent, { size: 'lg' });
|
|
||||||
const modalComp = this.modalRef.componentInstance;
|
|
||||||
modalComp.repeatable = this.model.repeatable;
|
|
||||||
modalComp.relationKey = this.model.name;
|
|
||||||
modalComp.listId = this.listId;
|
|
||||||
modalComp.filter = this.filter;
|
|
||||||
modalComp.fieldName = this.searchConfig;
|
|
||||||
modalComp.label = this.model.label;
|
|
||||||
|
|
||||||
this.modalRef.result.then((resultString = '') => {
|
|
||||||
this.modalValuesString = resultString;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
removeSelection(object: SearchResult<DSpaceObject>) {
|
|
||||||
this.selectableListService.deselectSingle(this.listId, object);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,34 +0,0 @@
|
|||||||
import { DynamicFormControlLayout, serializable } from '@ng-dynamic-forms/core';
|
|
||||||
import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-input.model';
|
|
||||||
import { Item } from '../../../../../../core/shared/item.model';
|
|
||||||
import { RelationshipOptions } from './model/relationship-options.model';
|
|
||||||
|
|
||||||
export const DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_RELATION = 'LOOKUP_RELATION';
|
|
||||||
|
|
||||||
export interface DynamicLookupRelationModelConfig extends DsDynamicInputModelConfig {
|
|
||||||
value?: any;
|
|
||||||
repeatable: boolean;
|
|
||||||
item: Item;
|
|
||||||
relationship: RelationshipOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DynamicLookupRelationModel extends DsDynamicInputModel {
|
|
||||||
|
|
||||||
@serializable() readonly type: string = DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_RELATION;
|
|
||||||
@serializable() value: any;
|
|
||||||
@serializable() repeatable: boolean;
|
|
||||||
relationship: RelationshipOptions;
|
|
||||||
item: Item;
|
|
||||||
|
|
||||||
constructor(config: DynamicLookupRelationModelConfig, layout?: DynamicFormControlLayout) {
|
|
||||||
|
|
||||||
super(config, layout);
|
|
||||||
|
|
||||||
this.readOnly = true;
|
|
||||||
this.disabled = true;
|
|
||||||
this.repeatable = config.repeatable;
|
|
||||||
this.item = config.item;
|
|
||||||
this.relationship = config.relationship;
|
|
||||||
this.valueUpdates.next(config.value);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -21,15 +21,11 @@ import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qua
|
|||||||
import { SubmissionFormsModel } from '../../../core/config/models/config-submission-forms.model';
|
import { SubmissionFormsModel } from '../../../core/config/models/config-submission-forms.model';
|
||||||
import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model';
|
import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model';
|
||||||
import { RowParser } from './parsers/row-parser';
|
import { RowParser } from './parsers/row-parser';
|
||||||
import {
|
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP, DynamicRelationGroupModel } from './ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
|
||||||
DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP,
|
|
||||||
DynamicRelationGroupModel
|
|
||||||
} from './ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
|
|
||||||
import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
|
import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
|
||||||
import { DsDynamicInputModel } from './ds-dynamic-form-ui/models/ds-dynamic-input.model';
|
import { DsDynamicInputModel } from './ds-dynamic-form-ui/models/ds-dynamic-input.model';
|
||||||
import { FormFieldMetadataValueObject } from './models/form-field-metadata-value.model';
|
import { FormFieldMetadataValueObject } from './models/form-field-metadata-value.model';
|
||||||
import { isNgbDateStruct } from '../../date.util';
|
import { isNgbDateStruct } from '../../date.util';
|
||||||
import { WorkspaceitemSectionFormObject } from '../../../core/submission/models/workspaceitem-section-form.model';
|
|
||||||
import { Workspaceitem } from '../../../core/submission/models/workspaceitem.model';
|
import { Workspaceitem } from '../../../core/submission/models/workspaceitem.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@@ -2,7 +2,7 @@ import { autoserialize } from 'cerialize';
|
|||||||
import { FormRowModel } from '../../../../core/config/models/config-submission-forms.model';
|
import { FormRowModel } from '../../../../core/config/models/config-submission-forms.model';
|
||||||
import { LanguageCode } from './form-field-language-value.model';
|
import { LanguageCode } from './form-field-language-value.model';
|
||||||
import { FormFieldMetadataValueObject } from './form-field-metadata-value.model';
|
import { FormFieldMetadataValueObject } from './form-field-metadata-value.model';
|
||||||
import { RelationshipOptions } from '../ds-dynamic-form-ui/models/lookup-relation/model/relationship-options.model';
|
import { RelationshipOptions } from '../ds-dynamic-form-ui/models/empty/model/relationship-options.model';
|
||||||
|
|
||||||
export class FormFieldModel {
|
export class FormFieldModel {
|
||||||
|
|
||||||
|
11
src/app/shared/form/builder/parsers/empty-field-parser.ts
Normal file
11
src/app/shared/form/builder/parsers/empty-field-parser.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { FieldParser } from './field-parser';
|
||||||
|
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
|
||||||
|
import { DsDynamicEmptyModelConfig, DynamicEmptyModel } from '../ds-dynamic-form-ui/models/empty/dynamic-empty.model';
|
||||||
|
|
||||||
|
export class EmptyFieldParser extends FieldParser {
|
||||||
|
|
||||||
|
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
|
||||||
|
const emptyModelConfig: DsDynamicEmptyModelConfig = this.initModel(null, label);
|
||||||
|
return new DynamicEmptyModel(emptyModelConfig)
|
||||||
|
}
|
||||||
|
}
|
@@ -27,7 +27,6 @@ export abstract class FieldParser {
|
|||||||
&& (this.configData.input.type !== 'list')
|
&& (this.configData.input.type !== 'list')
|
||||||
&& (this.configData.input.type !== 'tag')
|
&& (this.configData.input.type !== 'tag')
|
||||||
&& (this.configData.input.type !== 'group')
|
&& (this.configData.input.type !== 'group')
|
||||||
&& (this.configData.input.type !== 'lookup-relation')
|
|
||||||
) {
|
) {
|
||||||
let arrayCounter = 0;
|
let arrayCounter = 0;
|
||||||
let fieldArrayCounter = 0;
|
let fieldArrayCounter = 0;
|
||||||
@@ -186,6 +185,7 @@ export abstract class FieldParser {
|
|||||||
controlModel.readOnly = this.parserOptions.readOnly;
|
controlModel.readOnly = this.parserOptions.readOnly;
|
||||||
controlModel.disabled = this.parserOptions.readOnly;
|
controlModel.disabled = this.parserOptions.readOnly;
|
||||||
controlModel.workspaceItem = this.workspaceItem;
|
controlModel.workspaceItem = this.workspaceItem;
|
||||||
|
controlModel.relationship = this.configData.selectableRelationships;
|
||||||
|
|
||||||
// Set label
|
// Set label
|
||||||
this.setLabel(controlModel, label, labelEmpty);
|
this.setLabel(controlModel, label, labelEmpty);
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
import { FieldParser } from './field-parser';
|
|
||||||
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
|
|
||||||
import { DynamicLookupRelationModel, DynamicLookupRelationModelConfig } from '../ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.model';
|
|
||||||
|
|
||||||
export class LookupRelationFieldParser extends FieldParser {
|
|
||||||
|
|
||||||
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
|
|
||||||
const lookupModelConfig: DynamicLookupRelationModelConfig = this.initModel(null, label);
|
|
||||||
lookupModelConfig.repeatable = this.configData.repeatable;
|
|
||||||
/* TODO what to do with multiple relationships? */
|
|
||||||
lookupModelConfig.relationship = this.configData.selectableRelationships[0];
|
|
||||||
return new DynamicLookupRelationModel(lookupModelConfig);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -12,7 +12,7 @@ import { NameFieldParser } from './name-field-parser';
|
|||||||
import { SeriesFieldParser } from './series-field-parser';
|
import { SeriesFieldParser } from './series-field-parser';
|
||||||
import { TagFieldParser } from './tag-field-parser';
|
import { TagFieldParser } from './tag-field-parser';
|
||||||
import { TextareaFieldParser } from './textarea-field-parser';
|
import { TextareaFieldParser } from './textarea-field-parser';
|
||||||
import { LookupRelationFieldParser } from './lookup-relation-field-parser';
|
import { EmptyFieldParser } from './empty-field-parser';
|
||||||
|
|
||||||
export class ParserFactory {
|
export class ParserFactory {
|
||||||
public static getConstructor(type: ParserType): GenericConstructor<FieldParser> {
|
public static getConstructor(type: ParserType): GenericConstructor<FieldParser> {
|
||||||
@@ -35,9 +35,6 @@ export class ParserFactory {
|
|||||||
case ParserType.LookupName: {
|
case ParserType.LookupName: {
|
||||||
return LookupNameFieldParser
|
return LookupNameFieldParser
|
||||||
}
|
}
|
||||||
case ParserType.LookupRelation: {
|
|
||||||
return LookupRelationFieldParser
|
|
||||||
}
|
|
||||||
case ParserType.Onebox: {
|
case ParserType.Onebox: {
|
||||||
return OneboxFieldParser
|
return OneboxFieldParser
|
||||||
}
|
}
|
||||||
@@ -53,7 +50,9 @@ export class ParserFactory {
|
|||||||
case ParserType.Textarea: {
|
case ParserType.Textarea: {
|
||||||
return TextareaFieldParser
|
return TextareaFieldParser
|
||||||
}
|
}
|
||||||
|
case undefined: {
|
||||||
|
return EmptyFieldParser
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ import { AuthorityValue } from '../../core/integration/models/authority.value';
|
|||||||
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
|
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
|
||||||
import { DynamicRowGroupModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
|
import { DynamicRowGroupModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
|
||||||
import { Workspaceitem } from '../../core/submission/models/workspaceitem.model';
|
import { Workspaceitem } from '../../core/submission/models/workspaceitem.model';
|
||||||
|
import { Item } from '../../core/shared/item.model';
|
||||||
|
|
||||||
export const qualdropSelectConfig = {
|
export const qualdropSelectConfig = {
|
||||||
name: 'dc.identifier_QUALDROP_METADATA',
|
name: 'dc.identifier_QUALDROP_METADATA',
|
||||||
|
@@ -78,7 +78,6 @@ import { SortablejsModule } from 'angular-sortablejs';
|
|||||||
import { NumberPickerComponent } from './number-picker/number-picker.component';
|
import { NumberPickerComponent } from './number-picker/number-picker.component';
|
||||||
import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component';
|
import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component';
|
||||||
import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component';
|
import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component';
|
||||||
import { DsDynamicLookupRelationComponent } from './form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component';
|
|
||||||
import { MockAdminGuard } from './mocks/mock-admin-guard.service';
|
import { MockAdminGuard } from './mocks/mock-admin-guard.service';
|
||||||
import { AlertComponent } from './alert/alert.component';
|
import { AlertComponent } from './alert/alert.component';
|
||||||
import { MyDSpaceResultListElementComponent } from './object-list/my-dspace-result-list-element/my-dspace-result-list-element.component';
|
import { MyDSpaceResultListElementComponent } from './object-list/my-dspace-result-list-element/my-dspace-result-list-element.component';
|
||||||
@@ -139,7 +138,7 @@ import { RoleDirective } from './roles/role.directive';
|
|||||||
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
|
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
|
||||||
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
||||||
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
||||||
import { DsDynamicLookupRelationModalComponent } from './form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component';
|
import { DsDynamicLookupRelationModalComponent } from './form/builder/ds-dynamic-form-ui/models/empty/dynamic-lookup-relation-modal.component';
|
||||||
import { SearchResultsComponent } from './search/search-results/search-results.component';
|
import { SearchResultsComponent } from './search/search-results/search-results.component';
|
||||||
import { SearchSidebarComponent } from './search/search-sidebar/search-sidebar.component';
|
import { SearchSidebarComponent } from './search/search-sidebar/search-sidebar.component';
|
||||||
import { SearchSettingsComponent } from './search/search-settings/search-settings.component';
|
import { SearchSettingsComponent } from './search/search-settings/search-settings.component';
|
||||||
@@ -160,6 +159,7 @@ import { SearchFacetSelectedOptionComponent } from './search/search-filters/sear
|
|||||||
import { SearchFacetRangeOptionComponent } from './search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component';
|
import { SearchFacetRangeOptionComponent } from './search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component';
|
||||||
import { SearchSwitchConfigurationComponent } from './search/search-switch-configuration/search-switch-configuration.component';
|
import { SearchSwitchConfigurationComponent } from './search/search-switch-configuration/search-switch-configuration.component';
|
||||||
import { SearchAuthorityFilterComponent } from './search/search-filters/search-filter/search-authority-filter/search-authority-filter.component';
|
import { SearchAuthorityFilterComponent } from './search/search-filters/search-filter/search-authority-filter/search-authority-filter.component';
|
||||||
|
import { DsDynamicEmptyComponent } from './form/builder/ds-dynamic-form-ui/models/empty/dynamic-empty.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -220,7 +220,7 @@ const COMPONENTS = [
|
|||||||
DsDynamicFormControlContainerComponent,
|
DsDynamicFormControlContainerComponent,
|
||||||
DsDynamicListComponent,
|
DsDynamicListComponent,
|
||||||
DsDynamicLookupComponent,
|
DsDynamicLookupComponent,
|
||||||
DsDynamicLookupRelationComponent,
|
DsDynamicEmptyComponent,
|
||||||
DsDynamicLookupRelationModalComponent,
|
DsDynamicLookupRelationModalComponent,
|
||||||
DsDynamicScrollableDropdownComponent,
|
DsDynamicScrollableDropdownComponent,
|
||||||
DsDynamicTagComponent,
|
DsDynamicTagComponent,
|
||||||
@@ -325,7 +325,7 @@ const ENTRY_COMPONENTS = [
|
|||||||
SearchResultGridElementComponent,
|
SearchResultGridElementComponent,
|
||||||
DsDynamicListComponent,
|
DsDynamicListComponent,
|
||||||
DsDynamicLookupComponent,
|
DsDynamicLookupComponent,
|
||||||
DsDynamicLookupRelationComponent,
|
DsDynamicEmptyComponent,
|
||||||
DsDynamicLookupRelationModalComponent,
|
DsDynamicLookupRelationModalComponent,
|
||||||
DsDynamicScrollableDropdownComponent,
|
DsDynamicScrollableDropdownComponent,
|
||||||
DsDynamicTagComponent,
|
DsDynamicTagComponent,
|
||||||
|
Reference in New Issue
Block a user