mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 13:03:04 +00:00
relation lookup progress/equatable
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { autoserialize, autoserializeAs } from 'cerialize';
|
import { autoserialize, autoserializeAs } from 'cerialize';
|
||||||
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
import { Equatable } from '../utilities/equatable';
|
||||||
|
import { hasValue } from '../../shared/empty.util';
|
||||||
export class BrowseEntry implements ListableObject {
|
|
||||||
|
|
||||||
|
export class BrowseEntry implements Equatable<BrowseEntry> {
|
||||||
@autoserialize
|
@autoserialize
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
@@ -15,7 +15,15 @@ export class BrowseEntry implements ListableObject {
|
|||||||
@autoserializeAs('valueLang')
|
@autoserializeAs('valueLang')
|
||||||
language: string;
|
language: string;
|
||||||
|
|
||||||
|
@excludeFromEquals
|
||||||
@autoserialize
|
@autoserialize
|
||||||
count: number;
|
count: number;
|
||||||
|
|
||||||
|
equals(other: BrowseEntry): boolean {
|
||||||
|
if (hasValue(other)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
39
src/app/core/utilities/equals.decorators.ts
Normal file
39
src/app/core/utilities/equals.decorators.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { isEmpty } from '../../shared/empty.util';
|
||||||
|
|
||||||
|
const excludedFromEquals = new Map();
|
||||||
|
const fieldsForEqualsMap = new Map();
|
||||||
|
|
||||||
|
export function excludeFromEquals(object: any, propertyName: string): any {
|
||||||
|
if (!object) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let list = excludedFromEquals.get(object.constructor);
|
||||||
|
if (isEmpty(list)) {
|
||||||
|
list = [];
|
||||||
|
}
|
||||||
|
excludedFromEquals.set(object.constructor, [...list, propertyName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExcludedFromEqualsFor(constructor: Function) {
|
||||||
|
return excludedFromEquals.get(constructor) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fieldsForEquals(...fields: string[]): any {
|
||||||
|
return function i(object: any, propertyName: string): any {
|
||||||
|
if (!object) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let fieldMap = fieldsForEqualsMap.get(object.constructor);
|
||||||
|
if (isEmpty(fieldMap)) {
|
||||||
|
fieldMap = new Map();
|
||||||
|
}
|
||||||
|
fieldMap.set(propertyName, fields);
|
||||||
|
fieldsForEqualsMap.set(object.constructor, fieldMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getFieldsForEquals(constructor: Function, field: string) {
|
||||||
|
const fieldMap = excludedFromEquals.get(constructor) || new Map();
|
||||||
|
return fieldMap.get(field);
|
||||||
|
}
|
33
src/app/core/utilities/equatable.ts
Normal file
33
src/app/core/utilities/equatable.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { getExcludedFromEqualsFor, getFieldsForEquals } from './equals.decorators';
|
||||||
|
import { hasNoValue, hasValue } from '../../shared/empty.util';
|
||||||
|
|
||||||
|
function equalsByFields(object1, object2, fieldList): boolean {
|
||||||
|
const unequalProperty = fieldList.find((key) => {
|
||||||
|
if (object1[key] === object2[key]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hasNoValue(object1[key]) && hasNoValue(object2[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hasNoValue(object1[key]) || hasNoValue(object2[key])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const mapping = getFieldsForEquals(this.constructor, key);
|
||||||
|
if (hasValue(mapping)) {
|
||||||
|
return !equalsByFields(object1[key], object2[key], mapping);
|
||||||
|
}
|
||||||
|
if (this[key] instanceof EquatableObject) {
|
||||||
|
return !object1[key].equals(object2[key]);
|
||||||
|
}
|
||||||
|
return object1[key] !== object2[key];
|
||||||
|
});
|
||||||
|
return hasNoValue(unequalProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class EquatableObject<T> {
|
||||||
|
equals(other: T): boolean {
|
||||||
|
const excludedKeys = getExcludedFromEqualsFor(this.constructor);
|
||||||
|
const keys = Object.keys(this).filter((key) => excludedKeys.findIndex((excludedKey) => key === excludedKey) < 0);
|
||||||
|
return equalsByFields(this, other, keys);
|
||||||
|
}
|
||||||
|
}
|
@@ -24,95 +24,6 @@
|
|||||||
[selectable]="true"
|
[selectable]="true"
|
||||||
[selectionConfig]="{ repeatable: repeatable, listId: listId }">
|
[selectionConfig]="{ repeatable: repeatable, listId: listId }">
|
||||||
</ds-search-results>
|
</ds-search-results>
|
||||||
<!--<ds-loading *ngIf="!resultsRD || resultsRD.isLoading"></ds-loading>-->
|
|
||||||
<!--<div *ngIf="resultsRD?.hasSucceeded && resultsRD.payload.page.length > 0">-->
|
|
||||||
<!--<div *ngIf="repeatable">-->
|
|
||||||
<!--<div class="input-group mb-3">-->
|
|
||||||
<!--<div class="input-group-prepend">-->
|
|
||||||
<!--<div class="input-group-text">-->
|
|
||||||
<!--<!– In theory we don't need separate checkboxes for this,-->
|
|
||||||
<!--but I wasn't able to get this to work correctly without them.-->
|
|
||||||
<!--Checkboxes that are in the indeterminate state always switch to checked when clicked-->
|
|
||||||
<!--This seemed like the cleanest and clearest solution to solve this issue for now.-->
|
|
||||||
<!--–>-->
|
|
||||||
<!--<input *ngIf="!isAllSelected() && !isSomeSelected()"-->
|
|
||||||
<!--type="checkbox"-->
|
|
||||||
<!--[indeterminate]="false"-->
|
|
||||||
<!--(change)="selectAll()">-->
|
|
||||||
<!--<input *ngIf="!isAllSelected() && isSomeSelected()"-->
|
|
||||||
<!--type="checkbox"-->
|
|
||||||
<!--[indeterminate]="true"-->
|
|
||||||
<!--(change)="deselectAll()">-->
|
|
||||||
<!--<input *ngIf="isAllSelected()" type="checkbox"-->
|
|
||||||
<!--[checked]="true"-->
|
|
||||||
<!--(change)="deselectAll()">-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--<button *ngIf="selectAllLoading" type="button"-->
|
|
||||||
<!--class="btn btn-outline-secondary">-->
|
|
||||||
<!--<span class="spinner-border spinner-border-sm" role="status"-->
|
|
||||||
<!--aria-hidden="true"></span>-->
|
|
||||||
<!--<span class="sr-only">Loading...</span>-->
|
|
||||||
<!--</button>-->
|
|
||||||
<!--<div ngbDropdown class="input-group-append">-->
|
|
||||||
<!--<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>-->
|
|
||||||
<!--</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>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--<ds-pagination-->
|
|
||||||
<!--[paginationOptions]="searchConfig.pagination"-->
|
|
||||||
<!--[collectionSize]="resultsRD?.payload?.totalElements"-->
|
|
||||||
<!--[sortOptions]="searchConfig.sort"-->
|
|
||||||
<!--[hideGear]="true"-->
|
|
||||||
<!--[hidePagerWhenSinglePage]="true"-->
|
|
||||||
<!--(paginationChange)="onPaginationChange($event.pagination)">-->
|
|
||||||
<!--<div class="form-check"-->
|
|
||||||
<!--*ngFor="let result of resultsRD?.payload?.page; let i = index">-->
|
|
||||||
<!--<input *ngIf="repeatable" class="form-check-input" type="checkbox"-->
|
|
||||||
<!--[name]="'checkbox' + i"-->
|
|
||||||
<!--[id]="'object'+i"-->
|
|
||||||
<!--[checked]="isSelected(result.indexableObject)"-->
|
|
||||||
<!--[disabled]="isDisabled(result.indexableObject)"-->
|
|
||||||
<!--(change)="selectCheckbox($event.currentTarget.checked, result.indexableObject)">-->
|
|
||||||
<!--<input *ngIf="!repeatable" class="form-check-input" type="radio"-->
|
|
||||||
<!--[name]="'radio' + i"-->
|
|
||||||
<!--[id]="'object'+i"-->
|
|
||||||
<!--[checked]="isSelected(result.indexableObject)"-->
|
|
||||||
<!--(change)="selectRadio($event.currentTarget.checked, result.indexableObject)">-->
|
|
||||||
<!--<label class="form-check-label" [for]="'object'+i">-->
|
|
||||||
<!--<ds-wrapper-list-element class="result-list-element"-->
|
|
||||||
<!--[object]="result"-->
|
|
||||||
<!--[index]="i"></ds-wrapper-list-element>-->
|
|
||||||
<!--</label>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--</ds-pagination>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--<div *ngIf="resultsRD?.hasSucceeded && resultsRD.payload.page.length === 0">-->
|
|
||||||
<!--{{ 'form.no-results' | translate}}-->
|
|
||||||
<!--</div>-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -52,7 +52,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.resetRoute();
|
this.resetRoute();
|
||||||
this.onPaginationChange(this.initialPagination);
|
this.onPaginationChange(this.initialPagination);
|
||||||
this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []));
|
this.selection = this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []));
|
||||||
}
|
}
|
||||||
|
|
||||||
search(query: string) {
|
search(query: string) {
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
export interface ListableObject {}
|
|
@@ -68,7 +68,7 @@ export class SelectableListDeselectAction extends SelectableListAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SelectableListSetSelectionAction extends SelectableListAction {
|
export class SelectableListSetSelectionAction extends SelectableListAction {
|
||||||
payload: ListableObject;
|
payload: ListableObject[];
|
||||||
|
|
||||||
constructor(id: string, objects: ListableObject[]) {
|
constructor(id: string, objects: ListableObject[]) {
|
||||||
super(SelectableListActionTypes.SET_SELECTION, id);
|
super(SelectableListActionTypes.SET_SELECTION, id);
|
||||||
|
@@ -71,7 +71,7 @@ function select(state: SelectableListState, action: SelectableListSelectAction)
|
|||||||
|
|
||||||
function selectSingle(state: SelectableListState, action: SelectableListSelectSingleAction) {
|
function selectSingle(state: SelectableListState, action: SelectableListSelectSingleAction) {
|
||||||
let newSelection;
|
let newSelection;
|
||||||
if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload)) {
|
if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload.object)) {
|
||||||
newSelection = [...state.selection, action.payload.object];
|
newSelection = [...state.selection, action.payload.object];
|
||||||
} else {
|
} else {
|
||||||
newSelection = [action.payload.object];
|
newSelection = [action.payload.object];
|
||||||
@@ -80,20 +80,19 @@ function selectSingle(state: SelectableListState, action: SelectableListSelectSi
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deselect(state: SelectableListState, action: SelectableListDeselectAction) {
|
function deselect(state: SelectableListState, action: SelectableListDeselectAction) {
|
||||||
const newSelection = state.selection.filter((selected) => hasNoValue(action.payload.find((object) => object === selected)));
|
const newSelection = state.selection.filter((selected) => hasNoValue(action.payload.find((object) => object.uuid === selected.uuid)));
|
||||||
return Object.assign({}, state, { selection: newSelection });
|
return Object.assign({}, state, { selection: newSelection });
|
||||||
}
|
}
|
||||||
|
|
||||||
function deselectSingle(state: SelectableListState, action: SelectableListDeselectSingleAction) {
|
function deselectSingle(state: SelectableListState, action: SelectableListDeselectSingleAction) {
|
||||||
const newSelection = state.selection.filter((selected) => {
|
const newSelection = state.selection.filter((selected) => {
|
||||||
return selected !== action.payload
|
return selected.uuid !== action.payload.uuid
|
||||||
});
|
});
|
||||||
return Object.assign({}, state, { selection: newSelection });
|
return Object.assign({}, state, { selection: newSelection });
|
||||||
}
|
}
|
||||||
|
|
||||||
function setList(state: SelectableListState, action: SelectableListSetSelectionAction) {
|
function setList(state: SelectableListState, action: SelectableListSetSelectionAction) {
|
||||||
const newSelection = [...state.selection, action.payload];
|
return Object.assign({}, state, { selection: action.payload });
|
||||||
return Object.assign({}, state, { selection: newSelection });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearSelection(id: string) {
|
function clearSelection(id: string) {
|
||||||
@@ -102,5 +101,5 @@ function clearSelection(id: string) {
|
|||||||
|
|
||||||
|
|
||||||
function isObjectInSelection(selection: ListableObject[], object: ListableObject) {
|
function isObjectInSelection(selection: ListableObject[], object: ListableObject) {
|
||||||
return selection.findIndex((selected) => selected === object) >= 0
|
return selection.findIndex((selected) => selected.uuid === object.uuid) >= 0
|
||||||
}
|
}
|
||||||
|
@@ -16,4 +16,7 @@ export class SearchResult<T extends DSpaceObject> implements ListableObject {
|
|||||||
*/
|
*/
|
||||||
hitHighlights: MetadataMap;
|
hitHighlights: MetadataMap;
|
||||||
|
|
||||||
|
get id(): string {
|
||||||
|
return this.indexableObject.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user