mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
62849: fixed issues with multiple selections, improved UX, updating to use new REST response
This commit is contained in:
@@ -431,7 +431,6 @@
|
||||
"volume-title": "Volume Title",
|
||||
"publisher": "Publisher",
|
||||
"description": "Description"
|
||||
|
||||
},
|
||||
"listelement": {
|
||||
"badge": "Publication"
|
||||
@@ -570,7 +569,7 @@
|
||||
}
|
||||
},
|
||||
"switch-configuration": {
|
||||
"title":"Show"
|
||||
"title": "Show"
|
||||
},
|
||||
"view-switch": {
|
||||
"show-list": "Show as list",
|
||||
@@ -1016,7 +1015,7 @@
|
||||
"no-results": "No {{ type }} found"
|
||||
},
|
||||
"submission": {
|
||||
"general":{
|
||||
"general": {
|
||||
"cannot_submit": "You have not the privilege to make a new submission.",
|
||||
"deposit": "Deposit",
|
||||
"discard": {
|
||||
@@ -1038,10 +1037,8 @@
|
||||
"title": "Edit Submission"
|
||||
},
|
||||
"mydspace": {
|
||||
|
||||
},
|
||||
"sections": {
|
||||
|
||||
"general": {
|
||||
"add-more": "Add more",
|
||||
"no-sections": "No options available",
|
||||
@@ -1066,7 +1063,6 @@
|
||||
"submit.progressbar.license": "Deposit license",
|
||||
"submit.progressbar.cclicense": "Creative commons license",
|
||||
"submit.progressbar.detect-duplicate": "Potential duplicates",
|
||||
|
||||
"upload": {
|
||||
"no-entry": "No",
|
||||
"no-file-uploaded": "No file uploaded yet.",
|
||||
@@ -1097,6 +1093,21 @@
|
||||
"info": "This operation can't be undone. Are you sure?"
|
||||
}
|
||||
}
|
||||
},
|
||||
"describe": {
|
||||
"relationship-lookup": {
|
||||
"search": "Go",
|
||||
"loading": "Loading...",
|
||||
"title": "Select a {{ label }}",
|
||||
"toggle-dropdown": "Toggle dropdown",
|
||||
"select-page": "Select page",
|
||||
"deselect-page": "Deselect page",
|
||||
"select-all": "Select all",
|
||||
"deselect-all": "Deselect all",
|
||||
"close": "Close",
|
||||
"selected": "Selected {{ size }} items",
|
||||
"placeholder": "Search query"
|
||||
}
|
||||
}
|
||||
},
|
||||
"workflow": {
|
||||
@@ -1132,7 +1143,6 @@
|
||||
"reject_help": "If you have reviewed the item and found it is <strong>not</strong> suitable for inclusion in the collection, select \"Reject\". You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.",
|
||||
"return": "Return to pool",
|
||||
"return_help": "Return the task to the pool so that another user may perform the task."
|
||||
|
||||
},
|
||||
"pool": {
|
||||
"claim": "Claim",
|
||||
|
@@ -8,39 +8,24 @@
|
||||
"input": {
|
||||
"type": "lookup-relation"
|
||||
},
|
||||
"label": "Journal Issue",
|
||||
"label": "Author",
|
||||
"mandatory": true,
|
||||
"repeatable": true,
|
||||
"mandatoryMessage": "Required field!",
|
||||
"hints": "Select a journal issue for this publication.",
|
||||
"selectableMetadata": [
|
||||
"mandatoryMessage": "At least one author (plain text or relationship) is required",
|
||||
"hints": "Add an author",
|
||||
"selectableRelationships": [
|
||||
{
|
||||
"metadata": "relation.isPublicationOfJournalIssue",
|
||||
"label": null,
|
||||
"authority": null,
|
||||
"closed": null
|
||||
"relationshipType": "isAuthorOfPublication",
|
||||
"filter": null,
|
||||
"searchConfiguration": "personConfiguration"
|
||||
}
|
||||
],
|
||||
"languageCodes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fields": [
|
||||
{
|
||||
"input": {
|
||||
"type": "name"
|
||||
},
|
||||
"label": "Authors",
|
||||
"mandatory": false,
|
||||
"repeatable": true,
|
||||
"hints": "Enter the names of the authors of this item.",
|
||||
"selectableMetadata": [
|
||||
{
|
||||
"metadata": "dc.contributor.author",
|
||||
"label": null,
|
||||
"authority": null,
|
||||
"closed": null
|
||||
"closed": false
|
||||
}
|
||||
],
|
||||
"languageCodes": []
|
||||
|
@@ -206,7 +206,7 @@ export class SearchConfigurationService implements OnDestroy {
|
||||
* @returns {Observable<string>} Emits the current fixed filter as a string
|
||||
*/
|
||||
getCurrentFixedFilter(): Observable<string> {
|
||||
return this.routeService.getRouteParameterValue('fixedFilterQuery').pipe(tap((t) => console.log(t)));
|
||||
return this.routeService.getRouteParameterValue('fixedFilterQuery');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,8 +1,26 @@
|
||||
import { isEmpty } from '../../shared/empty.util';
|
||||
import { GenericConstructor } from '../shared/generic-constructor';
|
||||
import { EquatableObject } from './equatable';
|
||||
|
||||
const excludedFromEquals = new Map();
|
||||
const fieldsForEqualsMap = new Map();
|
||||
|
||||
export function inheritEquatable(parentCo: GenericConstructor<EquatableObject<any>>) {
|
||||
return function decorator(childCo: GenericConstructor<EquatableObject<any>>) {
|
||||
const parentExcludedFields = getExcludedFromEqualsFor(parentCo) || [];
|
||||
const excludedFields = getExcludedFromEqualsFor(childCo) || [];
|
||||
excludedFromEquals.set(childCo, [...excludedFields, ...parentExcludedFields]);
|
||||
|
||||
const mappedFields = fieldsForEqualsMap.get(childCo) || new Map();
|
||||
const parentMappedFields = fieldsForEqualsMap.get(parentCo) || new Map();
|
||||
Array.from(parentMappedFields.keys())
|
||||
.filter((key) => !Array.from(mappedFields.keys()).includes(key))
|
||||
.forEach((key) => {
|
||||
fieldsForEquals(...parentMappedFields.get(key))(new childCo(), key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function excludeFromEquals(object: any, propertyName: string): any {
|
||||
if (!object) {
|
||||
return;
|
||||
@@ -14,7 +32,7 @@ export function excludeFromEquals(object: any, propertyName: string): any {
|
||||
excludedFromEquals.set(object.constructor, [...list, propertyName]);
|
||||
}
|
||||
|
||||
export function getExcludedFromEqualsFor(constructor: Function) {
|
||||
export function getExcludedFromEqualsFor(constructor: Function): string[] {
|
||||
return excludedFromEquals.get(constructor) || [];
|
||||
}
|
||||
|
||||
@@ -33,7 +51,7 @@ export function fieldsForEquals(...fields: string[]): any {
|
||||
}
|
||||
|
||||
|
||||
export function getFieldsForEquals(constructor: Function, field: string) {
|
||||
export function getFieldsForEquals(constructor: Function, field: string): string[] {
|
||||
const fieldMap = fieldsForEqualsMap.get(constructor) || new Map();
|
||||
return fieldMap.get(field);
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-title">Choose a {{fieldName}}</h4>
|
||||
<h4 class="modal-title" id="modal-title">{{ ('submission.sections.describe.relationship-lookup.title' | translate:{label: label}) }}</h4>
|
||||
<button type="button" class="close" aria-label="Close button" aria-describedby="modal-title"
|
||||
(click)="modal.dismiss()">
|
||||
<span aria-hidden="true">×</span>
|
||||
@@ -13,10 +13,10 @@
|
||||
<div class="col-8">
|
||||
<form class="input-group mb-3" #queryForm="ngForm"
|
||||
(ngSubmit)="search(queryForm.value.query)">
|
||||
<input type="text" class="form-control" name="query" placeholder="Search query"
|
||||
<input type="text" class="form-control" name="query" [placeholder]="'submission.sections.describe.relationship-lookup.placeholder' | translate"
|
||||
[ngModel]="searchQuery">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" type="submit">Go</button>
|
||||
<button class="btn btn-outline-secondary" type="submit">{{ ('submission.sections.describe.relationship-lookup.search' | translate) }}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div *ngIf="repeatable" class="position-absolute">
|
||||
@@ -46,20 +46,20 @@
|
||||
class="btn btn-outline-secondary rounded-right">
|
||||
<span class="spinner-border spinner-border-sm" role="status"
|
||||
aria-hidden="true"></span>
|
||||
<span class="sr-only">Loading...</span>
|
||||
<span class="sr-only">{{ ('submission.sections.describe.relationship-lookup.loading' | translate) }}</span>
|
||||
</button>
|
||||
<button *ngIf="!selectAllLoading" id="resultdropdown" type="button"
|
||||
ngbDropdownToggle
|
||||
class="btn btn-outline-secondary dropdown-toggle-split"
|
||||
data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
<span class="sr-only">{{ ('submission.sections.describe.relationship-lookup.toggle-dropdown' | translate) }}</span>
|
||||
</button>
|
||||
<div ngbDropdownMenu aria-labelledby="resultdropdown">
|
||||
<button class="dropdown-item" (click)="selectPage(resultsRD?.payload?.page)">Select page</button>
|
||||
<button class="dropdown-item" (click)="deselectPage(resultsRD?.payload?.page)">Deselect page</button>
|
||||
<button class="dropdown-item" (click)="selectAll()">Select all</button>
|
||||
<button class="dropdown-item" (click)="deselectAll()">Deselect all</button>
|
||||
<button class="dropdown-item" (click)="selectPage(resultsRD?.payload?.page)">{{ ('submission.sections.describe.relationship-lookup.select-page' | translate) }}</button>
|
||||
<button class="dropdown-item" (click)="deselectPage(resultsRD?.payload?.page)">{{ ('submission.sections.describe.relationship-lookup.deselect-page' | translate) }}</button>
|
||||
<button class="dropdown-item" (click)="selectAll()">{{ ('submission.sections.describe.relationship-lookup.select-all' | translate) }}</button>
|
||||
<button class="dropdown-item" (click)="deselectAll()">{{ ('submission.sections.describe.relationship-lookup.deselect-all' | translate) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -68,15 +68,16 @@
|
||||
[sortConfig]="this.searchConfig?.sort"
|
||||
[searchConfig]="this.searchConfig"
|
||||
[selectable]="true"
|
||||
[selectionConfig]="{ repeatable: repeatable, listId: listId }">
|
||||
[selectionConfig]="{ repeatable: repeatable, listId: listId }"
|
||||
(deselectObject)="allSelected = false"
|
||||
>
|
||||
</ds-search-results>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<small>Selected {{(selection$ | async)?.length || 0}} items</small>
|
||||
<small>{{ ('submission.sections.describe.relationship-lookup.selected' | translate:{size: (selection$ | async)?.length || 0}) }}</small>
|
||||
<div>
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="modal.dismiss()">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" (click)="close()">Ok</button>
|
||||
<button type="button" class="btn btn-danger" (click)="close()">{{ ('submission.sections.describe.relationship-lookup.close' | translate) }}</button>
|
||||
</div>
|
||||
</div>
|
@@ -35,7 +35,9 @@ const RELATION_TYPE_FILTER_PREFIX = 'f.entityType=';
|
||||
})
|
||||
export class DsDynamicLookupRelationModalComponent implements OnInit {
|
||||
relationKey: string;
|
||||
fieldName: string;
|
||||
label: string;
|
||||
filter: string;
|
||||
searchConfiguration: string;
|
||||
listId: string;
|
||||
resultsRD$: Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>>;
|
||||
searchConfig: PaginatedSearchOptions;
|
||||
@@ -49,21 +51,20 @@ export class DsDynamicLookupRelationModalComponent implements OnInit {
|
||||
pageSize: 10
|
||||
});
|
||||
selection$: Observable<ListableObject[]>;
|
||||
fixedFilter: string;
|
||||
|
||||
constructor(public modal: NgbActiveModal, private searchService: SearchService, private router: Router, private selectableListService: SelectableListService, private searchConfigService: SearchConfigurationService, private routeService: RouteService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.resetRoute();
|
||||
this.fixedFilter = RELATION_TYPE_FILTER_PREFIX + this.fieldName;
|
||||
this.routeService.setParameter('fixedFilterQuery', this.fixedFilter);
|
||||
this.routeService.setParameter('fixedFilterQuery', this.filter);
|
||||
this.routeService.setParameter('configuration', this.searchConfiguration);
|
||||
|
||||
this.selection$ = this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []));
|
||||
this.someSelected$ = this.selection$.pipe(map((selection) => isNotEmpty(selection)));
|
||||
this.resultsRD$ = this.searchConfigService.paginatedSearchOptions.pipe(
|
||||
map((options) => {
|
||||
return Object.assign(new PaginatedSearchOptions({}), options, { fixedFilter: RELATION_TYPE_FILTER_PREFIX + this.fieldName })
|
||||
return Object.assign(new PaginatedSearchOptions({}), options, { fixedFilter: this.filter, configuration: this.searchConfiguration })
|
||||
}),
|
||||
switchMap((options) => {
|
||||
this.searchConfig = options;
|
||||
@@ -85,9 +86,9 @@ export class DsDynamicLookupRelationModalComponent implements OnInit {
|
||||
}
|
||||
|
||||
search(query: string) {
|
||||
this.allSelected = false;
|
||||
this.searchQuery = query;
|
||||
this.resetRoute();
|
||||
this.selectableListService.deselectAll(this.listId);
|
||||
}
|
||||
|
||||
close() {
|
||||
@@ -100,7 +101,6 @@ export class DsDynamicLookupRelationModalComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
selectPage(page: SearchResult<DSpaceObject>[]) {
|
||||
this.selectableListService.select(this.listId, page);
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
<script src="dynamic-lookup-relation.component.ts"></script>
|
||||
<div>
|
||||
<div *ngIf="model.repeatable || !((model.value | async) && (model.value | async).length > 0)" class="form-row align-items-center">
|
||||
<div class="col">
|
||||
@@ -12,29 +11,19 @@
|
||||
</div>
|
||||
<div class="col-auto text-center">
|
||||
<button class="btn btn-secondary"
|
||||
type="button"
|
||||
type="submit"
|
||||
ngbTooltip="{{'form.lookup-help' | translate}}"
|
||||
placement="top"
|
||||
(click)="openLookup(); $event.stopPropagation();">{{'form.lookup' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
<!--<div class="col-auto text-center">-->
|
||||
<!--<button class="btn btn-secondary"-->
|
||||
<!--type="button"-->
|
||||
<!--ngbTooltip="{{'form.add-help' | translate}}"-->
|
||||
<!--#tooltip = ngbTooltip-->
|
||||
<!--placement="top"-->
|
||||
<!--[disabled]="!hasResultsSelected()"-->
|
||||
<!--(click)="add(); tooltip.close(); $event.stopPropagation();">{{'form.add' | 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(value)">
|
||||
(click)="removeSelection(result)">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<span class="d-inline-block align-middle ml-1">{{value.name}}</span>
|
||||
|
@@ -1,10 +1,6 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/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';
|
||||
@@ -12,11 +8,9 @@ import { DsDynamicLookupRelationModalComponent } from './dynamic-lookup-relation
|
||||
import { DynamicLookupRelationModel } from './dynamic-lookup-relation.model';
|
||||
import { DSpaceObject } from '../../../../../../core/shared/dspace-object.model';
|
||||
import { RelationshipService } from '../../../../../../core/data/relationship.service';
|
||||
import { Item } from '../../../../../../core/shared/item.model';
|
||||
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 { ListableObject } from '../../../../../object-collection/shared/listable-object.model';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { SearchResult } from '../../../../../search/search-result.model';
|
||||
|
||||
@@ -39,8 +33,10 @@ export class DsDynamicLookupRelationComponent extends DynamicFormControlComponen
|
||||
|
||||
modalRef: NgbModalRef;
|
||||
modalValuesString = '';
|
||||
fieldName: string;
|
||||
listId: string;
|
||||
filter: string;
|
||||
searchConfig: string;
|
||||
|
||||
|
||||
constructor(private modalService: NgbModal,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
@@ -52,8 +48,9 @@ export class DsDynamicLookupRelationComponent extends DynamicFormControlComponen
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.fieldName = this.model.name.substring(RELATION_TYPE_METADATA_PREFIX.length);
|
||||
this.listId = 'list-' + this.fieldName;
|
||||
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 : []),
|
||||
);
|
||||
@@ -69,27 +66,15 @@ export class DsDynamicLookupRelationComponent extends DynamicFormControlComponen
|
||||
modalComp.repeatable = this.model.repeatable;
|
||||
modalComp.relationKey = this.model.name;
|
||||
modalComp.listId = this.listId;
|
||||
modalComp.fieldName = this.fieldName;
|
||||
modalComp.filter = this.filter;
|
||||
modalComp.fieldName = this.searchConfig;
|
||||
modalComp.label = this.model.label;
|
||||
|
||||
this.modalRef.result.then((resultString = '') => {
|
||||
this.modalValuesString = resultString;
|
||||
});
|
||||
}
|
||||
|
||||
// add() {
|
||||
// if (isNotEmpty(this.model.value)) {
|
||||
// this.model.value = [...this.model.value, ...this.selectedResults];
|
||||
// } else {
|
||||
// this.model.value = this.selectedResults;
|
||||
// }
|
||||
//
|
||||
// this.modalValuesString = '';
|
||||
// this.selectedResults = [];
|
||||
// this.selectedResults.forEach((item: Item) => {
|
||||
// this.relationService.addRelationship(this.model.item, item);
|
||||
// })
|
||||
// }
|
||||
|
||||
removeSelection(object: SearchResult<DSpaceObject>) {
|
||||
this.selectableListService.deselectSingle(this.listId, object);
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
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';
|
||||
|
||||
@@ -8,6 +9,7 @@ export interface DynamicLookupRelationModelConfig extends DsDynamicInputModelCon
|
||||
value?: any;
|
||||
repeatable: boolean;
|
||||
item: Item;
|
||||
relationship: RelationshipOptions;
|
||||
}
|
||||
|
||||
export class DynamicLookupRelationModel extends DsDynamicInputModel {
|
||||
@@ -15,6 +17,7 @@ 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) {
|
||||
@@ -25,6 +28,7 @@ export class DynamicLookupRelationModel extends DsDynamicInputModel {
|
||||
this.disabled = true;
|
||||
this.repeatable = config.repeatable;
|
||||
this.item = config.item;
|
||||
this.relationship = config.relationship;
|
||||
this.valueUpdates.next(config.value);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,5 @@
|
||||
export interface RelationshipOptions {
|
||||
relationshipType: string;
|
||||
filter: string;
|
||||
searchConfiguration: string;
|
||||
}
|
@@ -2,6 +2,7 @@ import { autoserialize } from 'cerialize';
|
||||
import { FormRowModel } from '../../../../core/config/models/config-submission-forms.model';
|
||||
import { LanguageCode } from './form-field-language-value.model';
|
||||
import { FormFieldMetadataValueObject } from './form-field-metadata-value.model';
|
||||
import { RelationshipOptions } from '../ds-dynamic-form-ui/models/lookup-relation/model/relationship-options.model';
|
||||
|
||||
export class FormFieldModel {
|
||||
|
||||
@@ -32,6 +33,9 @@ export class FormFieldModel {
|
||||
@autoserialize
|
||||
selectableMetadata: FormFieldMetadataValueObject[];
|
||||
|
||||
@autoserialize
|
||||
selectableRelationships: RelationshipOptions[];
|
||||
|
||||
@autoserialize
|
||||
rows: FormRowModel[];
|
||||
|
||||
|
@@ -1,20 +1,14 @@
|
||||
import { FieldParser } from './field-parser';
|
||||
import {
|
||||
DynamicLookupModel,
|
||||
DynamicLookupModelConfig
|
||||
} from '../ds-dynamic-form-ui/models/lookup/dynamic-lookup.model';
|
||||
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
|
||||
import {
|
||||
DynamicLookupRelationModel,
|
||||
DynamicLookupRelationModelConfig
|
||||
} from '../ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.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);
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@
|
||||
(pageChange)="onPageChange($event)"
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||
(deselectObject)="deselectObject.emit($event)"
|
||||
(selectObject)="selectObject.emit($event)"
|
||||
(sortFieldChange)="onSortFieldChange($event)"
|
||||
[selectable]="selectable"
|
||||
[selectionConfig]="selectionConfig"
|
||||
|
@@ -35,6 +35,8 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
|
||||
@Input() hideGear = false;
|
||||
@Input() selectable = false;
|
||||
@Input() selectionConfig: {repeatable: boolean, listId: string};
|
||||
@Output() deselectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
|
||||
@Output() selectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
|
||||
|
||||
pageInfo: Observable<PageInfo>;
|
||||
private sub;
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import { SearchResult } from '../../search/search-result.model';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
import { searchResultFor } from '../../search/search-result-element-decorator';
|
||||
import { inheritEquatable } from '../../../core/utilities/equals.decorators';
|
||||
|
||||
@searchResultFor(Item)
|
||||
@inheritEquatable(SearchResult)
|
||||
export class ItemSearchResult extends SearchResult<Item> {
|
||||
}
|
||||
|
@@ -79,8 +79,11 @@ export class ObjectListComponent {
|
||||
*/
|
||||
@Output() sortDirectionChange: EventEmitter<SortDirection> = new EventEmitter<SortDirection>();
|
||||
|
||||
@Output() paginationChange: EventEmitter<SortDirection> = new EventEmitter<any>();
|
||||
@Output() paginationChange: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output() deselectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
|
||||
|
||||
@Output() selectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
|
||||
/**
|
||||
* An event fired when the sort field is changed.
|
||||
* Event's payload equals to the newly selected sort field.
|
||||
@@ -108,66 +111,24 @@ export class ObjectListComponent {
|
||||
this.paginationChange.emit(event);
|
||||
}
|
||||
|
||||
// isDisabled(object: ListableObject): boolean {
|
||||
// return hasValue(this.previousSelection.find((selected) => selected === object));
|
||||
// }
|
||||
|
||||
selectCheckbox(value: boolean, object: ListableObject) {
|
||||
if (value) {
|
||||
this.selectionService.selectSingle(this.selectionConfig.listId, object);
|
||||
this.selectObject.emit(object);
|
||||
|
||||
} else {
|
||||
this.selectionService.deselectSingle(this.selectionConfig.listId, object);
|
||||
this.deselectObject.emit(object);
|
||||
}
|
||||
}
|
||||
|
||||
selectRadio(value: boolean, object: ListableObject) {
|
||||
if (value) {
|
||||
this.selectionService.selectSingle(this.selectionConfig.listId, object, false);
|
||||
this.selectObject.emit(object);
|
||||
} else {
|
||||
this.selectionService.deselectSingle(this.selectionConfig.listId, object);
|
||||
this.deselectObject.emit(object);
|
||||
}
|
||||
}
|
||||
|
||||
selectPage(page: SearchResult<DSpaceObject>[]) {
|
||||
this.selectionService.select(this.selectionConfig.listId, this.objects.payload.page);
|
||||
}
|
||||
|
||||
deselectPage(page: SearchResult<DSpaceObject>[]) {
|
||||
this.selectionService.deselect(this.selectionConfig.listId, this.objects.payload.page);
|
||||
|
||||
}
|
||||
|
||||
deselectAll() {
|
||||
this.selectionService.deselectAll(this.selectionConfig.listId);
|
||||
}
|
||||
|
||||
// isAllSelected() {
|
||||
// return this.allSelected;
|
||||
// }
|
||||
//
|
||||
// isSomeSelected() {
|
||||
// return isNotEmpty(this.selection);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// selectAll() {
|
||||
// this.allSelected = true;
|
||||
// this.selectAllLoading = true;
|
||||
// const fullPagination = Object.assign(new PaginationComponentOptions(), {
|
||||
// query: this.searchQuery,
|
||||
// currentPage: 1,
|
||||
// pageSize: Number.POSITIVE_INFINITY
|
||||
// });
|
||||
// const fullSearchConfig = Object.assign(this.searchConfig, { pagination: fullPagination });
|
||||
// const results = this.searchService.search(fullSearchConfig);
|
||||
// results.pipe(
|
||||
// getSucceededRemoteData(),
|
||||
// map((resultsRD) => resultsRD.payload.page),
|
||||
// tap(() => this.selectAllLoading = false)
|
||||
// )
|
||||
// .subscribe((results) =>
|
||||
// this.selection = results
|
||||
// .map((searchResult) => searchResult.indexableObject)
|
||||
// .filter((dso) => hasNoValue(this.previousSelection.find((object) => object === dso)))
|
||||
// );
|
||||
// }
|
||||
|
||||
}
|
||||
|
@@ -71,11 +71,13 @@ function select(state: SelectableListState, action: SelectableListSelectAction)
|
||||
|
||||
function selectSingle(state: SelectableListState, action: SelectableListSelectSingleAction) {
|
||||
let newSelection;
|
||||
if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload.object)) {
|
||||
if (!isObjectInSelection(state.selection, action.payload.object)) {
|
||||
if (action.payload.multipleSelectionsAllowed) {
|
||||
newSelection = [...state.selection, action.payload.object];
|
||||
} else {
|
||||
newSelection = [action.payload.object];
|
||||
}
|
||||
}
|
||||
return Object.assign({}, state, { selection: newSelection });
|
||||
}
|
||||
|
||||
|
@@ -37,8 +37,9 @@ export class SelectableListService {
|
||||
* Select an object in a specific list in the store
|
||||
* @param {string} id The id of the list on which the object should be selected
|
||||
* @param {ListableObject} object The object to select
|
||||
* @param {boolean} multipleSelectionsAllowed Defines if the multiple selections are allowed for this selectable list
|
||||
*/
|
||||
selectSingle(id: string, object: ListableObject, multipleSelectionsAllowed?) {
|
||||
selectSingle(id: string, object: ListableObject, multipleSelectionsAllowed?: boolean) {
|
||||
this.store.dispatch(new SelectableListSelectSingleAction(id, object, multipleSelectionsAllowed));
|
||||
}
|
||||
|
||||
@@ -86,7 +87,7 @@ export class SelectableListService {
|
||||
isObjectSelected(id: string, object: ListableObject): Observable<boolean> {
|
||||
return this.getSelectableList(id).pipe(
|
||||
filter((state: SelectableListState) => hasValue(state)),
|
||||
map((state: SelectableListState) => isNotEmpty(state.selection) && hasValue(state.selection.find((selected) => selected === object))),
|
||||
map((state: SelectableListState) => isNotEmpty(state.selection) && hasValue(state.selection.find((selected) => selected.equals(object)))),
|
||||
startWith(false),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
|
@@ -7,6 +7,8 @@
|
||||
[hideGear]="true"
|
||||
[selectable]="selectable"
|
||||
[selectionConfig]="selectionConfig"
|
||||
(deselectObject)="deselectObject.emit($event)"
|
||||
(selectObject)="selectObject.emit($event)"
|
||||
>
|
||||
</ds-viewable-collection>
|
||||
</div>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { fadeIn, fadeInOut } from '../../animations/fade';
|
||||
@@ -8,6 +8,7 @@ import { SearchResult } from '../search-result.model';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||
import { hasNoValue, isNotEmpty } from '../../empty.util';
|
||||
import { SortOptions } from '../../../core/cache/models/sort-options.model';
|
||||
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-results',
|
||||
@@ -58,6 +59,11 @@ export class SearchResultsComponent {
|
||||
@Input() selectable = false;
|
||||
|
||||
@Input() selectionConfig: {repeatable: boolean, listId: string};
|
||||
|
||||
@Output() deselectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
|
||||
|
||||
@Output() selectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
|
||||
|
||||
/**
|
||||
* Method to change the given string by surrounding it by quotes if not already present.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user