diff --git a/resources/i18n/en.json b/resources/i18n/en.json index 9927bcc4b9..af19466123 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -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 not 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", diff --git a/src/app/core/dspace-rest-v2/mocks/mock-submission-response.json b/src/app/core/dspace-rest-v2/mocks/mock-submission-response.json index 49f8713df8..4848ede023 100644 --- a/src/app/core/dspace-rest-v2/mocks/mock-submission-response.json +++ b/src/app/core/dspace-rest-v2/mocks/mock-submission-response.json @@ -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": [] diff --git a/src/app/core/shared/search/search-configuration.service.ts b/src/app/core/shared/search/search-configuration.service.ts index 8d77b2f095..dd04fc50f9 100644 --- a/src/app/core/shared/search/search-configuration.service.ts +++ b/src/app/core/shared/search/search-configuration.service.ts @@ -206,7 +206,7 @@ export class SearchConfigurationService implements OnDestroy { * @returns {Observable} Emits the current fixed filter as a string */ getCurrentFixedFilter(): Observable { - return this.routeService.getRouteParameterValue('fixedFilterQuery').pipe(tap((t) => console.log(t))); + return this.routeService.getRouteParameterValue('fixedFilterQuery'); } /** diff --git a/src/app/core/utilities/equals.decorators.ts b/src/app/core/utilities/equals.decorators.ts index efa6a6c053..dd2aef8bfa 100644 --- a/src/app/core/utilities/equals.decorators.ts +++ b/src/app/core/utilities/equals.decorators.ts @@ -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>) { + return function decorator(childCo: GenericConstructor>) { + 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); } \ No newline at end of file diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html index 98c3ee7a6f..410a139b02 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.html @@ -1,5 +1,5 @@
@@ -46,20 +46,20 @@ class="btn btn-outline-secondary rounded-right"> - Loading... + {{ ('submission.sections.describe.relationship-lookup.loading' | translate) }}
- - - - + + + +
@@ -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" + > \ No newline at end of file diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts index ce9ac71787..23f37bde2e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation-modal.component.ts @@ -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>>>; searchConfig: PaginatedSearchOptions; @@ -49,21 +51,20 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { pageSize: 10 }); selection$: Observable; - 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[]) { this.selectableListService.select(this.listId, page); } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.html index 9baf2e4af8..4445b0452c 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.html @@ -1,4 +1,3 @@ -
@@ -12,29 +11,19 @@
- - - - - - - - - -
  • {{value.name}} diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.ts index 00f8cadc73..b1d69ea2f6 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.component.ts @@ -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) { this.selectableListService.deselectSingle(this.listId, object); } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.model.ts index e0e580e1f8..fd015d9a90 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/dynamic-lookup-relation.model.ts @@ -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); } } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/model/relationship-options.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/model/relationship-options.model.ts new file mode 100644 index 0000000000..cd6e00e7dc --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup-relation/model/relationship-options.model.ts @@ -0,0 +1,5 @@ +export interface RelationshipOptions { + relationshipType: string; + filter: string; + searchConfiguration: string; +} diff --git a/src/app/shared/form/builder/models/form-field.model.ts b/src/app/shared/form/builder/models/form-field.model.ts index 439bf89f8f..e86bc2791a 100644 --- a/src/app/shared/form/builder/models/form-field.model.ts +++ b/src/app/shared/form/builder/models/form-field.model.ts @@ -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[]; diff --git a/src/app/shared/form/builder/parsers/lookup-relation-field-parser.ts b/src/app/shared/form/builder/parsers/lookup-relation-field-parser.ts index 202edfec8e..ddd2449de8 100644 --- a/src/app/shared/form/builder/parsers/lookup-relation-field-parser.ts +++ b/src/app/shared/form/builder/parsers/lookup-relation-field-parser.ts @@ -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); } } diff --git a/src/app/shared/object-collection/object-collection.component.html b/src/app/shared/object-collection/object-collection.component.html index 0323251b12..af65b652bb 100644 --- a/src/app/shared/object-collection/object-collection.component.html +++ b/src/app/shared/object-collection/object-collection.component.html @@ -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" diff --git a/src/app/shared/object-collection/object-collection.component.ts b/src/app/shared/object-collection/object-collection.component.ts index fcc3bd330e..4dde335c98 100644 --- a/src/app/shared/object-collection/object-collection.component.ts +++ b/src/app/shared/object-collection/object-collection.component.ts @@ -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 = new EventEmitter(); + @Output() selectObject: EventEmitter = new EventEmitter(); pageInfo: Observable; private sub; diff --git a/src/app/shared/object-collection/shared/item-search-result.model.ts b/src/app/shared/object-collection/shared/item-search-result.model.ts index 89a9d782a6..bea0a6f24a 100644 --- a/src/app/shared/object-collection/shared/item-search-result.model.ts +++ b/src/app/shared/object-collection/shared/item-search-result.model.ts @@ -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 { } diff --git a/src/app/shared/object-list/object-list.component.ts b/src/app/shared/object-list/object-list.component.ts index a8467d92af..6070cad37d 100644 --- a/src/app/shared/object-list/object-list.component.ts +++ b/src/app/shared/object-list/object-list.component.ts @@ -79,8 +79,11 @@ export class ObjectListComponent { */ @Output() sortDirectionChange: EventEmitter = new EventEmitter(); - @Output() paginationChange: EventEmitter = new EventEmitter(); + @Output() paginationChange: EventEmitter = new EventEmitter(); + @Output() deselectObject: EventEmitter = new EventEmitter(); + + @Output() selectObject: EventEmitter = new EventEmitter(); /** * 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[]) { - this.selectionService.select(this.selectionConfig.listId, this.objects.payload.page); - } - - deselectPage(page: SearchResult[]) { - 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))) - // ); - // } - } diff --git a/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts b/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts index 61a56bedd8..e3f0479d7b 100644 --- a/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts +++ b/src/app/shared/object-list/selectable-list/selectable-list.reducer.ts @@ -71,10 +71,12 @@ function select(state: SelectableListState, action: SelectableListSelectAction) function selectSingle(state: SelectableListState, action: SelectableListSelectSingleAction) { let newSelection; - if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload.object)) { - newSelection = [...state.selection, action.payload.object]; - } else { - newSelection = [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 }); } diff --git a/src/app/shared/object-list/selectable-list/selectable-list.service.ts b/src/app/shared/object-list/selectable-list/selectable-list.service.ts index 097e7da30f..2ea495691f 100644 --- a/src/app/shared/object-list/selectable-list/selectable-list.service.ts +++ b/src/app/shared/object-list/selectable-list/selectable-list.service.ts @@ -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 { 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() ); diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index bbf84f305c..70e527373c 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -7,6 +7,8 @@ [hideGear]="true" [selectable]="selectable" [selectionConfig]="selectionConfig" + (deselectObject)="deselectObject.emit($event)" + (selectObject)="selectObject.emit($event)" >
diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index 09178e9cad..7bc9f391cd 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -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 = new EventEmitter(); + + @Output() selectObject: EventEmitter = new EventEmitter(); + /** * Method to change the given string by surrounding it by quotes if not already present. */