mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-12 04:23:04 +00:00
55946: Multi-list object select support
This commit is contained in:
@@ -15,11 +15,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ngb-tabset (tabChange)="tabChange($event)">
|
<ngb-tabset (tabChange)="tabChange($event)" [destroyOnHide]="false">
|
||||||
<ngb-tab title="{{'collection.item-mapper.tabs.browse' | translate}}">
|
<ngb-tab title="{{'collection.item-mapper.tabs.browse' | translate}}">
|
||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<ds-item-select class="mt-2"
|
<ds-item-select class="mt-2"
|
||||||
|
[key]="'browse'"
|
||||||
[dsoRD$]="collectionItemsRD$"
|
[dsoRD$]="collectionItemsRD$"
|
||||||
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
||||||
[confirmButton]="'collection.item-mapper.remove'"
|
[confirmButton]="'collection.item-mapper.remove'"
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<ds-item-select class="mt-2"
|
<ds-item-select class="mt-2"
|
||||||
|
[key]="'map'"
|
||||||
[dsoRD$]="mappingItemsRD$"
|
[dsoRD$]="mappingItemsRD$"
|
||||||
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
||||||
[confirmButton]="'collection.item-mapper.confirm'"
|
[confirmButton]="'collection.item-mapper.confirm'"
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<ds-collection-select class="mt-2"
|
<ds-collection-select class="mt-2"
|
||||||
|
[key]="'browse'"
|
||||||
[dsoRD$]="itemCollectionsRD$"
|
[dsoRD$]="itemCollectionsRD$"
|
||||||
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
||||||
[confirmButton]="'item.edit.item-mapper.buttons.remove'"
|
[confirmButton]="'item.edit.item-mapper.buttons.remove'"
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<ds-collection-select class="mt-2"
|
<ds-collection-select class="mt-2"
|
||||||
|
[key]="'map'"
|
||||||
[dsoRD$]="mappingCollectionsRD$"
|
[dsoRD$]="mappingCollectionsRD$"
|
||||||
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
||||||
[confirmButton]="'item.edit.item-mapper.buttons.add'"
|
[confirmButton]="'item.edit.item-mapper.buttons.add'"
|
||||||
|
@@ -14,7 +14,11 @@ import {
|
|||||||
} from './+search-page/search-filters/search-filter/search-filter.reducer';
|
} from './+search-page/search-filters/search-filter/search-filter.reducer';
|
||||||
import { notificationsReducer, NotificationsState } from './shared/notifications/notifications.reducers';
|
import { notificationsReducer, NotificationsState } from './shared/notifications/notifications.reducers';
|
||||||
import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer';
|
import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer';
|
||||||
import { objectSelectionReducer, ObjectSelectionsState } from './shared/object-select/object-select.reducer';
|
import {
|
||||||
|
ObjectSelectionListState,
|
||||||
|
objectSelectionReducer,
|
||||||
|
ObjectSelectionsState
|
||||||
|
} from './shared/object-select/object-select.reducer';
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
router: fromRouter.RouterReducerState;
|
router: fromRouter.RouterReducerState;
|
||||||
@@ -25,7 +29,7 @@ export interface AppState {
|
|||||||
searchSidebar: SearchSidebarState;
|
searchSidebar: SearchSidebarState;
|
||||||
searchFilter: SearchFiltersState;
|
searchFilter: SearchFiltersState;
|
||||||
truncatable: TruncatablesState,
|
truncatable: TruncatablesState,
|
||||||
objectSelection: ObjectSelectionsState
|
objectSelection: ObjectSelectionListState
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appReducers: ActionReducerMap<AppState> = {
|
export const appReducers: ActionReducerMap<AppState> = {
|
||||||
|
@@ -37,11 +37,11 @@ export function objectSelectionReducer(state = initialState, action: ObjectSelec
|
|||||||
case ObjectSelectionActionTypes.INITIAL_SELECT: {
|
case ObjectSelectionActionTypes.INITIAL_SELECT: {
|
||||||
if (isEmpty(state) || isEmpty(state[action.key]) || isEmpty(state[action.key][action.id])) {
|
if (isEmpty(state) || isEmpty(state[action.key]) || isEmpty(state[action.key][action.id])) {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.key]: {
|
[action.key]: Object.assign({}, state[action.key], {
|
||||||
[action.id]: {
|
[action.id]: {
|
||||||
checked: true
|
checked: true
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
@@ -50,11 +50,11 @@ export function objectSelectionReducer(state = initialState, action: ObjectSelec
|
|||||||
case ObjectSelectionActionTypes.INITIAL_DESELECT: {
|
case ObjectSelectionActionTypes.INITIAL_DESELECT: {
|
||||||
if (isEmpty(state) || isEmpty(state[action.key]) || isEmpty(state[action.key][action.id])) {
|
if (isEmpty(state) || isEmpty(state[action.key]) || isEmpty(state[action.key][action.id])) {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.key]: {
|
[action.key]: Object.assign({}, state[action.key], {
|
||||||
[action.id]: {
|
[action.id]: {
|
||||||
checked: false
|
checked: false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
@@ -62,31 +62,31 @@ export function objectSelectionReducer(state = initialState, action: ObjectSelec
|
|||||||
|
|
||||||
case ObjectSelectionActionTypes.SELECT: {
|
case ObjectSelectionActionTypes.SELECT: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.key]: {
|
[action.key]: Object.assign({}, state[action.key], {
|
||||||
[action.id]: {
|
[action.id]: {
|
||||||
checked: true
|
checked: true
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
case ObjectSelectionActionTypes.DESELECT: {
|
case ObjectSelectionActionTypes.DESELECT: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.key]: {
|
[action.key]: Object.assign({}, state[action.key], {
|
||||||
[action.id]: {
|
[action.id]: {
|
||||||
checked: false
|
checked: false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
case ObjectSelectionActionTypes.SWITCH: {
|
case ObjectSelectionActionTypes.SWITCH: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
[action.key]: {
|
[action.key]: Object.assign({}, state[action.key], {
|
||||||
[action.id]: {
|
[action.id]: {
|
||||||
checked: (isEmpty(state) || isEmpty(state[action.key]) || isEmpty(state[action.key][action.id])) ? true : !state[action.key][action.id].checked
|
checked: (isEmpty(state) || isEmpty(state[action.key]) || isEmpty(state[action.key][action.id])) ? true : !state[action.key][action.id].checked
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,7 +12,6 @@ import { hasValue } from '../empty.util';
|
|||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { AppState } from '../../app.reducer';
|
import { AppState } from '../../app.reducer';
|
||||||
|
|
||||||
const selectionStateSelector = (state: ObjectSelectionsState) => state.objectSelection;
|
|
||||||
const objectSelectionsStateSelector = (state: ObjectSelectionListState) => state.objectSelection;
|
const objectSelectionsStateSelector = (state: ObjectSelectionListState) => state.objectSelection;
|
||||||
const objectSelectionListStateSelector = (state: AppState) => state.objectSelection;
|
const objectSelectionListStateSelector = (state: AppState) => state.objectSelection;
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@ const objectSelectionListStateSelector = (state: AppState) => state.objectSelect
|
|||||||
export class ObjectSelectService {
|
export class ObjectSelectService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<ObjectSelectionsState>,
|
private store: Store<ObjectSelectionListState>,
|
||||||
private appStore: Store<AppState>
|
private appStore: Store<AppState>
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,7 @@ export class ObjectSelectService {
|
|||||||
* @returns {Observable<boolean>} Emits the current selection state of the given object, if it's unavailable, return false
|
* @returns {Observable<boolean>} Emits the current selection state of the given object, if it's unavailable, return false
|
||||||
*/
|
*/
|
||||||
getSelected(key: string, id: string): Observable<boolean> {
|
getSelected(key: string, id: string): Observable<boolean> {
|
||||||
return this.store.select(selectionByIdSelector(id)).pipe(
|
return this.store.select(selectionByKeyAndIdSelector(key, id)).pipe(
|
||||||
map((object: ObjectSelectionState) => {
|
map((object: ObjectSelectionState) => {
|
||||||
if (object) {
|
if (object) {
|
||||||
return object.checked;
|
return object.checked;
|
||||||
@@ -47,12 +46,12 @@ export class ObjectSelectService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request the current selection of all objects
|
* Request the current selection of all objects within a specific list
|
||||||
* @returns {Observable<boolean>} Emits the current selection state of all objects
|
* @returns {Observable<boolean>} Emits the current selection state of all objects
|
||||||
*/
|
*/
|
||||||
getAllSelected(): Observable<string[]> {
|
getAllSelected(key: string): Observable<string[]> {
|
||||||
return this.appStore.select(objectSelectionsStateSelector).pipe(
|
return this.appStore.select(objectSelectionListStateSelector).pipe(
|
||||||
map((state: ObjectSelectionsState) => Object.keys(state).filter((key) => state[key].checked))
|
map((state: ObjectSelectionListState) => Object.keys(state[key]).filter((id) => state[key][id].checked))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,14 +110,14 @@ export class ObjectSelectService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectionByIdSelector(id: string): MemoizedSelector<ObjectSelectionsState, ObjectSelectionState> {
|
function selectionByKeyAndIdSelector(key: string, id: string): MemoizedSelector<ObjectSelectionListState, ObjectSelectionState> {
|
||||||
return keySelector<ObjectSelectionState>(id);
|
return keyAndIdSelector<ObjectSelectionState>(key, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function keySelector<T>(key: string): MemoizedSelector<ObjectSelectionsState, T> {
|
export function keyAndIdSelector<T>(key: string, id: string): MemoizedSelector<ObjectSelectionListState, T> {
|
||||||
return createSelector(selectionStateSelector, (state: ObjectSelectionState) => {
|
return createSelector(objectSelectionsStateSelector, (state: ObjectSelectionsState) => {
|
||||||
if (hasValue(state)) {
|
if (hasValue(state) && hasValue(state[key])) {
|
||||||
return state[key];
|
return state[key][id];
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,9 @@ import { ObjectSelectService } from '../object-select.service';
|
|||||||
*/
|
*/
|
||||||
export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestroy {
|
export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
key: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of DSpaceObjects to display
|
* The list of DSpaceObjects to display
|
||||||
*/
|
*/
|
||||||
@@ -49,11 +52,11 @@ export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestro
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.selectedIds$ = this.objectSelectService.getAllSelected();
|
this.selectedIds$ = this.objectSelectService.getAllSelected(this.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.objectSelectService.reset();
|
this.objectSelectService.reset(this.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,7 +64,7 @@ export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestro
|
|||||||
* @param {string} id
|
* @param {string} id
|
||||||
*/
|
*/
|
||||||
switch(id: string) {
|
switch(id: string) {
|
||||||
this.objectSelectService.switch(id);
|
this.objectSelectService.switch(this.key, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,7 +73,7 @@ export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestro
|
|||||||
* @returns {Observable<boolean>}
|
* @returns {Observable<boolean>}
|
||||||
*/
|
*/
|
||||||
getSelected(id: string): Observable<boolean> {
|
getSelected(id: string): Observable<boolean> {
|
||||||
return this.objectSelectService.getSelected(id);
|
return this.objectSelectService.getSelected(this.key, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +85,7 @@ export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestro
|
|||||||
take(1)
|
take(1)
|
||||||
).subscribe((ids: string[]) => {
|
).subscribe((ids: string[]) => {
|
||||||
this.confirm.emit(ids);
|
this.confirm.emit(ids);
|
||||||
this.objectSelectService.reset();
|
this.objectSelectService.reset(this.key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user