finished second selection tab

This commit is contained in:
lotte
2019-09-04 15:45:08 +02:00
parent 77e2fde15a
commit 11ad52c120
19 changed files with 278 additions and 172 deletions

View File

@@ -524,6 +524,9 @@
"search.filters.applied.f.namedresourcetype": "Status",
"search.filters.applied.f.subject": "Subject",
"search.filters.applied.f.submitter": "Submitter",
"search.filters.applied.f.jobTitle": "Job Title",
"search.filters.applied.f.birthDate.max": "End birth date",
"search.filters.applied.f.birthDate.min": "Start birth date",
"search.filters.filter.author.head": "Author",
"search.filters.filter.author.placeholder": "Author name",
"search.filters.filter.birthDate.head": "Birth Date",
@@ -603,19 +606,30 @@
"submission.general.save-later": "Save for later",
"submission.mydspace": {},
"submission.sections.describe.relationship-lookup.close": "Close",
"submission.sections.describe.relationship-lookup.deselect-all": "Deselect all",
"submission.sections.describe.relationship-lookup.deselect-page": "Deselect page",
"submission.sections.describe.relationship-lookup.loading": "Loading...",
"submission.sections.describe.relationship-lookup.placeholder": "Search query",
"submission.sections.describe.relationship-lookup.search": "Go",
"submission.sections.describe.relationship-lookup.select-all": "Select all",
"submission.sections.describe.relationship-lookup.select-page": "Select page",
"submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Deselect all",
"submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Deselect page",
"submission.sections.describe.relationship-lookup.search-tab.loading": "Loading...",
"submission.sections.describe.relationship-lookup.search-tab.placeholder": "Search query",
"submission.sections.describe.relationship-lookup.search-tab.search": "Go",
"submission.sections.describe.relationship-lookup.search-tab.select-all": "Select all",
"submission.sections.describe.relationship-lookup.search-tab.select-page": "Select page",
"submission.sections.describe.relationship-lookup.selected": "Selected {{ size }} items",
"submission.sections.describe.relationship-lookup.title.Journal Issue": "Select a Journal Issue",
"submission.sections.describe.relationship-lookup.title.Journal Volume": "Select a Journal Volume",
"submission.sections.describe.relationship-lookup.title.Journal": "Select a Journal",
"submission.sections.describe.relationship-lookup.title.Author": "Select an Author",
"submission.sections.describe.relationship-lookup.toggle-dropdown": "Toggle dropdown",
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Author": "Search for Authors",
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Search for Journals",
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal Issue": "Search for Journal Issues",
"submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal Volume": "Search for Journal Volumes",
"submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Current Selection ({{ count }})",
"submission.sections.describe.relationship-lookup.title.Journal Issue": "Journal Issues",
"submission.sections.describe.relationship-lookup.title.Journal Volume": "Journal Volumes",
"submission.sections.describe.relationship-lookup.title.Journal": "Journals",
"submission.sections.describe.relationship-lookup.title.Author": "Authors",
"submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Toggle dropdown",
"submission.sections.describe.relationship-lookup.selection-tab.settings": "Settings",
"submission.sections.describe.relationship-lookup.selection-tab.no-selection": "Your selection is currently empty.",
"submission.sections.describe.relationship-lookup.selection-tab.title.Author": "Selected Authors",
"submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Selected Journals",
"submission.sections.describe.relationship-lookup.selection-tab.title.Journal Volume": "Selected Journal Volume",
"submission.sections.describe.relationship-lookup.selection-tab.title.Journal Issue": "Selected Issue",
"submission.sections.general.add-more": "Add more",
"submission.sections.general.collection": "Collection",
"submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.",

View File

@@ -11,7 +11,11 @@
[scopes]="(scopeListRD$ | async)"
[inPlaceSearch]="inPlaceSearch">
</ds-search-form>
<ds-search-labels *ngIf="searchEnabled" [inPlaceSearch]="inPlaceSearch"></ds-search-labels>
<div class="row mb-3 mb-md-1">
<div class="labels col-sm-9 offset-sm-3">
<ds-search-labels *ngIf="searchEnabled" [inPlaceSearch]="inPlaceSearch"></ds-search-labels>
</div>
</div>
<div class="row">
<div id="search-body"
class="row-offcanvas row-offcanvas-left"
@@ -28,7 +32,7 @@
<button (click)="openSidebar()" aria-controls="#search-body"
class="btn btn-outline-primary float-right open-sidebar"><i
class="fas fa-sliders"></i> {{"search.sidebar.open"
| translate}}
| translate}}
</button>
</div>
<ds-search-results [searchResults]="resultsRD$ | async"

View File

@@ -1,9 +1,26 @@
import { autoserialize, autoserializeAs } from 'cerialize';
import { hasValue } from '../../shared/empty.util';
/**
* Represents the state of a paginated response
*/
export class PageInfo {
constructor(
options?: {
elementsPerPage: number,
totalElements: number,
totalPages: number,
currentPage: number
}
) {
if (hasValue(options)) {
this.elementsPerPage = options.elementsPerPage;
this.totalElements = options.totalElements;
this.totalPages = options.totalPages;
this.currentPage = options.currentPage;
}
}
/**
* The number of elements on a page
*/

View File

@@ -20,7 +20,7 @@ function equalsByFields(object1, object2, fieldList): boolean {
return !object1[key].equals(object2[key]);
}
if (typeof object1[key] === 'object') {
equalsByFields(object1[key], object2[key], Object.keys(object1))
return !equalsByFields(object1[key], object2[key], Object.keys(object1))
}
return object1[key] !== object2[key];
});

View File

@@ -88,6 +88,9 @@ import { RemoteData } from '../../../../core/data/remote-data';
import { Item } from '../../../../core/shared/item.model';
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
import { ItemDataService } from '../../../../core/data/item-data.service';
import { RemoveRelationshipAction } from './relation-lookup-modal/relationship.actions';
import { Store } from '@ngrx/store';
import { AppState } from '../../../../app.reducer';
export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
switch (model.type) {
@@ -202,7 +205,8 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
private selectableListService: SelectableListService,
private itemService: ItemDataService,
private relationshipService: RelationshipService,
private zone: NgZone
private zone: NgZone,
private store: Store<AppState>
) {
super(componentFactoryResolver, layoutService, validationService);
}
@@ -279,11 +283,10 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
removeSelection(object: SearchResult<Item>) {
this.selectableListService.deselectSingle(this.listId, object);
this.zone.runOutsideAngular(
this.model.workspaceItem.item.pipe(
() => this.model.workspaceItem.item.pipe(
getSucceededRemoteData(),
switchMap((itemRD: RemoteData<Item>) => this.relationshipService.getRelationshipByItemsAndLabel(itemRD.payload, object.indexableObject, this.model.relationship.relationshipType)),
switchMap((relationship: Relationship) => this.relationshipService.deleteRelationship(relationship.id)),
take(1)
).subscribe());
tap((itemRD: RemoteData<Item>) => this.store.dispatch(new RemoveRelationshipAction(itemRD.payload, object.indexableObject, this.model.relationship.relationshipType)))
).subscribe()
);
}
}

View File

@@ -7,28 +7,28 @@
</div>
<div class="modal-body">
<ngb-tabset>
<ngb-tab title="Search">
<ngb-tab [title]="'submission.sections.describe.relationship-lookup.search-tab.tab-title.' + label | translate">
<ng-template ngbTabContent>
<ds-dynamic-lookup-relation-search-tab
[label]="label"
[itemRD$]="itemRD$"
[selection$]="selection$"
[listId]="listId"
[relationship]="relationship"
[repeatable]="repeatable"
(selectObject)="select($event)"
(deselectObject)="deselect($event)"
class="d-block pt-3">
</ds-dynamic-lookup-relation-search-tab>
</ng-template>
</ngb-tab>
<ngb-tab title="Selection">
<ngb-tab [title]="'submission.sections.describe.relationship-lookup.selection-tab.tab-title' | translate : {count: (selection$ | async)?.length}">
<ng-template ngbTabContent>
<ds-dynamic-lookup-relation-selection-tab
[label]="label"
[itemRD$]="itemRD$"
[selection$]="selection$"
[listId]="listId"
[relationship]="relationship"
[label]="label"
[repeatable]="repeatable"
(selectObject)="select($event)"
(deselectObject)="deselect($event)"
class="d-block pt-3">
</ds-dynamic-lookup-relation-selection-tab>
</ng-template>

View File

@@ -1,14 +1,23 @@
import { Component, OnInit } from '@angular/core';
import { Component, NgZone, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { hasValue } from '../../../../empty.util';
import { map } from 'rxjs/operators';
import { map, tap } from 'rxjs/operators';
import { SEARCH_CONFIG_SERVICE } from '../../../../../+my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../../../../core/shared/search/search-configuration.service';
import { SelectableListService } from '../../../../object-list/selectable-list/selectable-list.service';
import { SelectableListState } from '../../../../object-list/selectable-list/selectable-list.reducer';
import { ListableObject } from '../../../../object-collection/shared/listable-object.model';
import { RelationshipOptions } from '../../models/relationship-options.model';
import { SearchResult } from '../../../../search/search-result.model';
import { Item } from '../../../../../core/shared/item.model';
import { getSucceededRemoteData } from '../../../../../core/shared/operators';
import { RemoteData } from '../../../../../core/data/remote-data';
import { AddRelationshipAction, RemoveRelationshipAction } from './relationship.actions';
import { RelationshipService } from '../../../../../core/data/relationship.service';
import { RelationshipTypeService } from '../../../../../core/data/relationship-type.service';
import { Store } from '@ngrx/store';
import { AppState } from '../../../../../app.reducer';
@Component({
selector: 'ds-dynamic-lookup-relation-modal',
@@ -33,6 +42,10 @@ export class DsDynamicLookupRelationModalComponent implements OnInit {
constructor(
public modal: NgbActiveModal,
private selectableListService: SelectableListService,
private relationshipService: RelationshipService,
private relationshipTypeService: RelationshipTypeService,
private zone: NgZone,
private store: Store<AppState>
) {
}
@@ -44,4 +57,32 @@ export class DsDynamicLookupRelationModalComponent implements OnInit {
close() {
this.modal.close();
}
select(...selectableObjects: SearchResult<Item>[]) {
this.zone.runOutsideAngular(
() => this.itemRD$
.pipe(
getSucceededRemoteData(),
tap((itemRD: RemoteData<Item>) => {
return selectableObjects.forEach((object) =>
this.store.dispatch(new AddRelationshipAction(itemRD.payload, object.indexableObject, this.relationship.relationshipType))
);
})
).subscribe());
}
deselect(...selectableObjects: SearchResult<Item>[]) {
this.zone.runOutsideAngular(
() => this.itemRD$.pipe(
getSucceededRemoteData(),
tap((itemRD: RemoteData<Item>) => {
return selectableObjects.forEach((object) =>
this.store.dispatch(new RemoveRelationshipAction(itemRD.payload, object.indexableObject, this.relationship.relationshipType))
);
})
).subscribe()
);
}
}

View File

@@ -5,12 +5,15 @@
<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]="'submission.sections.describe.relationship-lookup.placeholder' | translate"
<input type="text" class="form-control" name="query" [placeholder]="'submission.sections.describe.relationship-lookup.search-tab.placeholder' | translate"
[ngModel]="searchQuery">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="submit">{{ ('submission.sections.describe.relationship-lookup.search' | translate) }}</button>
<button class="btn btn-outline-secondary" type="submit">{{ ('submission.sections.describe.relationship-lookup.search-tab.search' | translate) }}</button>
</div>
</form>
<ds-search-labels [inPlaceSearch]="true"></ds-search-labels>
<div *ngIf="repeatable" class="position-absolute">
<div class="input-group mb-3">
<div class="input-group-prepend">
@@ -38,7 +41,7 @@
class="btn btn-outline-secondary rounded-right">
<span class="spinner-border spinner-border-sm" role="status"
aria-hidden="true"></span>
<span class="sr-only">{{ ('submission.sections.describe.relationship-lookup.loading' | translate) }}</span>
<span class="sr-only">{{ ('submission.sections.describe.relationship-lookup.search-tab.loading' | translate) }}</span>
</button>
<button id="resultdropdown" type="button"
ngbDropdownToggle
@@ -49,10 +52,12 @@
<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)">{{ ('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>
<button class="dropdown-item"
(click)="selectPage(resultsRD?.payload?.page)">{{ ('submission.sections.describe.relationship-lookup.search-tab.select-page' | translate) }}</button>
<button class="dropdown-item"
(click)="deselectPage(resultsRD?.payload?.page)">{{ ('submission.sections.describe.relationship-lookup.search-tab.deselect-page' | translate) }}</button>
<button class="dropdown-item" (click)="selectAll()">{{ ('submission.sections.describe.relationship-lookup.search-tab.select-all' | translate) }}</button>
<button class="dropdown-item" (click)="deselectAll()">{{ ('submission.sections.describe.relationship-lookup.search-tab.deselect-all' | translate) }}</button>
</div>
</div>
</div>
@@ -62,9 +67,8 @@
[searchConfig]="this.searchConfig"
[selectable]="true"
[selectionConfig]="{ repeatable: repeatable, listId: listId }"
(deselectObject)="deselect($event)"
(selectObject)="select($event)"
>
(deselectObject)="deselectObject.emit($event)"
(selectObject)="selectObject.emit($event)">
</ds-search-results>
</div>
</div>

View File

@@ -1,4 +1,4 @@
import { Component, Input, NgZone, OnDestroy, OnInit } from '@angular/core';
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { SEARCH_CONFIG_SERVICE } from '../../../../../../+my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service';
import { Item } from '../../../../../../core/shared/item.model';
@@ -14,16 +14,11 @@ import { SearchService } from '../../../../../../core/shared/search/search.servi
import { Router } from '@angular/router';
import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service';
import { RouteService } from '../../../../../services/route.service';
import { RelationshipService } from '../../../../../../core/data/relationship.service';
import { RelationshipTypeService } from '../../../../../../core/data/relationship-type.service';
import { Store } from '@ngrx/store';
import { AppState } from '../../../../../../app.reducer';
import { SelectableListState } from '../../../../../object-list/selectable-list/selectable-list.reducer';
import { hasValue, isNotEmpty } from '../../../../../empty.util';
import { concat, map, multicast, switchMap, take, takeWhile, tap } from 'rxjs/operators';
import { DSpaceObject } from '../../../../../../core/shared/dspace-object.model';
import { getSucceededRemoteData } from '../../../../../../core/shared/operators';
import { AddRelationshipAction, RemoveRelationshipAction } from '../relationship.actions';
@Component({
selector: 'ds-dynamic-lookup-relation-search-tab',
@@ -38,12 +33,12 @@ import { AddRelationshipAction, RemoveRelationshipAction } from '../relationship
})
export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDestroy {
@Input() label: string;
@Input() relationship: RelationshipOptions;
@Input() listId: string;
@Input() itemRD$;
@Input() repeatable: boolean;
@Input() selection$: Observable<ListableObject[]>;
@Output() deselectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
@Output() selectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
resultsRD$: Observable<RemoteData<PaginatedList<SearchResult<Item>>>>;
searchConfig: PaginatedSearchOptions;
searchQuery;
@@ -62,10 +57,6 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
private selectableListService: SelectableListService,
private searchConfigService: SearchConfigurationService,
private routeService: RouteService,
private relationshipService: RelationshipService,
private relationshipTypeService: RelationshipTypeService,
private zone: NgZone,
private store: Store<AppState>
) {
}
@@ -74,13 +65,13 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
this.routeService.setParameter('fixedFilterQuery', this.relationship.filter);
this.routeService.setParameter('configuration', this.relationship.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: this.relationship.filter, configuration: this.relationship.searchConfiguration })
}),
switchMap((options) => {
this.searchQuery = options.query;
this.searchConfig = options;
return this.searchService.search(options).pipe(
/* Make sure to only listen to the first x results, until loading is finished */
@@ -96,6 +87,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
)
})
);
this.resultsRD$.subscribe((t) => console.log(t));
}
@@ -116,7 +108,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
.pipe(take(1))
.subscribe((selection: SearchResult<Item>[]) => {
const filteredPage = page.filter((pageItem) => selection.findIndex((selected) => selected.equals(pageItem)) < 0)
this.select(...filteredPage);
this.selectObject.emit(...filteredPage);
});
this.selectableListService.select(this.listId, page);
}
@@ -127,7 +119,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
.pipe(take(1))
.subscribe((selection: SearchResult<Item>[]) => {
const filteredPage = page.filter((pageItem) => selection.findIndex((selected) => selected.equals(pageItem)) >= 0)
this.deselect(...filteredPage);
this.deselectObject.emit(...filteredPage);
});
this.selectableListService.deselect(this.listId, page);
}
@@ -151,7 +143,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
.pipe(take(1))
.subscribe((selection: SearchResult<Item>[]) => {
const filteredResults = results.filter((pageItem) => selection.findIndex((selected) => selected.equals(pageItem)) < 0);
this.select(...filteredResults);
this.selectObject.emit(...filteredResults);
});
this.selectableListService.select(this.listId, results);
}
@@ -162,38 +154,10 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
this.allSelected = false;
this.selection$
.pipe(take(1))
.subscribe((selection: SearchResult<Item>[]) => this.deselect(...selection));
.subscribe((selection: SearchResult<Item>[]) => this.deselectObject.emit(...selection));
this.selectableListService.deselectAll(this.listId);
}
select(...selectableObjects: SearchResult<Item>[]) {
this.zone.runOutsideAngular(
() => this.itemRD$
.pipe(
getSucceededRemoteData(),
tap((itemRD: RemoteData<Item>) => {
return selectableObjects.forEach((object) =>
this.store.dispatch(new AddRelationshipAction(itemRD.payload, object.indexableObject, this.relationship.relationshipType))
);
})
).subscribe());
}
deselect(...selectableObjects: SearchResult<Item>[]) {
this.zone.runOutsideAngular(
() => this.itemRD$.pipe(
getSucceededRemoteData(),
tap((itemRD: RemoteData<Item>) => {
return selectableObjects.forEach((object) =>
this.store.dispatch(new RemoveRelationshipAction(itemRD.payload, object.indexableObject, this.relationship.relationshipType))
);
})
).subscribe()
);
}
ngOnDestroy(): void {
if (hasValue(this.subscription)
) {

View File

@@ -1,10 +1,22 @@
<ds-search-sidebar class="col-4" id="search-sidebar"
[resultCount]=""
[inPlaceSearch]="true" [showViewModes]="false"></ds-search-sidebar>
<div class="col-8">
<ds-viewable-collection [objects]="selectionRD$ | async"
[selectable]="true"
[selectionConfig]="{ repeatable: repeatable, listId: listId }"
[config]="initialPagination"
></ds-viewable-collection>
<div class="row">
<div class="col-4">
<h3>{{ 'submission.sections.describe.relationship-lookup.selection-tab.settings' | translate}}</h3>
<ds-page-size-selector></ds-page-size-selector>
</div>
<div class="col-8">
<div *ngIf="(selectionRD$ | async)?.payload.page < 1">
{{'submission.sections.describe.relationship-lookup.selection-tab.no-selection' | translate}}
</div>
<div *ngIf="(selectionRD$ | async)?.payload.page.length >= 1">
<h3>{{ 'submission.sections.describe.relationship-lookup.selection-tab.title.' + label | translate}}</h3>
<ds-viewable-collection [objects]="selectionRD$ | async"
[selectable]="true"
[selectionConfig]="{ repeatable: repeatable, listId: listId }"
[config]="initialPagination"
[hideGear]="true"
(deselectObject)="deselectObject.emit($event)"
(selectObject)="selectObject.emit($event)"
></ds-viewable-collection>
</div>
</div>
</div>

View File

@@ -1,14 +1,20 @@
import { Component, Input } from '@angular/core';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { SEARCH_CONFIG_SERVICE } from '../../../../../../+my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service';
import { Observable } from 'rxjs';
import { RelationshipOptions } from '../../../models/relationship-options.model';
import { ListableObject } from '../../../../../object-collection/shared/listable-object.model';
import { RemoteData } from '../../../../../../core/data/remote-data';
import { map, take } from 'rxjs/operators';
import { map, switchMap, take } from 'rxjs/operators';
import { createSuccessfulRemoteDataObject } from '../../../../../testing/utils';
import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model';
import { PaginatedList } from '../../../../../../core/data/paginated-list';
import { Router } from '@angular/router';
import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service';
import { RouteService } from '../../../../../services/route.service';
import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model';
import { size } from 'memory-cache';
import { PageInfo } from '../../../../../../core/shared/page-info.model';
@Component({
selector: 'ds-dynamic-lookup-relation-selection-tab',
@@ -24,24 +30,54 @@ import { PaginatedList } from '../../../../../../core/data/paginated-list';
export class DsDynamicLookupRelationSelectionTabComponent {
@Input() label: string;
@Input() relationship: RelationshipOptions;
@Input() listId: string;
@Input() itemRD$;
@Input() repeatable: boolean;
@Input() selection$: Observable<ListableObject[]>;
@Input() selectionRD$: Observable<RemoteData<PaginatedList<ListableObject>>>;
@Output() deselectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
@Output() selectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
initialPagination = Object.assign(new PaginationComponentOptions(), {
id: 'submission-relation-list',
pageSize: 5
});
constructor() {
constructor(private router: Router,
private searchConfigService: SearchConfigurationService) {
}
ngOnInit() {
this.selectionRD$ = this.selection$.pipe(
take(1),
map((selection) => createSuccessfulRemoteDataObject(new PaginatedList({} as any, selection)))
);
this.resetRoute();
this.selectionRD$ = this.searchConfigService.paginatedSearchOptions
.pipe(
map((options: PaginatedSearchOptions) => options.pagination),
switchMap((pagination: PaginationComponentOptions) => {
return this.selection$.pipe(
take(1),
map((selected) => {
const offset = (pagination.currentPage - 1) * pagination.pageSize;
const end = (offset + pagination.pageSize) > selected.length ? selected.length : offset + pagination.pageSize;
const selection = selected.slice(offset, end);
const pageInfo = new PageInfo(
{
elementsPerPage: pagination.pageSize,
totalElements: selected.length,
currentPage: pagination.currentPage,
totalPages: Math.ceil(selected.length / pagination.pageSize)
});
return createSuccessfulRemoteDataObject(new PaginatedList(pageInfo, selection))
})
);
})
)
}
resetRoute() {
this.router.navigate([], {
queryParams: Object.assign({}, { page: 1, pageSize: this.initialPagination.pageSize }),
});
}
}

View File

@@ -0,0 +1,10 @@
<div class="setting-option page-size-settings mb-3 p-3">
<h5>{{ 'search.sidebar.settings.rpp' | translate}}</h5>
<select class="form-control" (change)="reloadRPP($event)">
<option *ngFor="let pageSizeOption of (paginationOptions$ | async).pageSizeOptions"
[value]="pageSizeOption"
[selected]="pageSizeOption === +(paginationOptions$ | async).pageSize ? 'selected': null">
{{pageSizeOption}}
</option>
</select>
</div>

View File

@@ -0,0 +1,3 @@
.setting-option {
border: 1px solid map-get($theme-colors, light);
}

View File

@@ -0,0 +1,52 @@
import { Component, Inject, Input, OnInit } from '@angular/core';
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
import { Observable } from 'rxjs';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
import { PaginatedSearchOptions } from '../search/paginated-search-options.model';
import { map } from 'rxjs/operators';
@Component({
selector: 'ds-page-size-selector',
styleUrls: ['./page-size-selector.component.scss'],
templateUrl: './page-size-selector.component.html'
})
/**
* This component represents the part of the search sidebar that contains the general search settings.
*/
export class PageSizeSelectorComponent implements OnInit {
/**
* The configuration for the current paginated search results
*/
paginationOptions$: Observable<PaginationComponentOptions>;
constructor(private route: ActivatedRoute,
private router: Router,
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigurationService: SearchConfigurationService) {
}
/**
* Initialize paginated search options
*/
ngOnInit(): void {
this.paginationOptions$ = this.searchConfigurationService.paginatedSearchOptions.pipe(map((options: PaginatedSearchOptions) => options.pagination));
}
/**
* Method to change the current page size (results per page)
* @param {Event} event Change event containing the new page size value
*/
reloadRPP(event: Event) {
const value = (event.target as HTMLInputElement).value;
const navigationExtras: NavigationExtras = {
queryParams: {
pageSize: value,
page: 1
},
queryParamsHandling: 'merge'
};
this.router.navigate([], navigationExtras);
}
}

View File

@@ -1,13 +1,9 @@
<div class="row mb-3 mb-md-1">
<div class="labels col-sm-9 offset-sm-3">
<ng-container *ngFor="let key of ((appliedFilters | async) | dsObjectKeys)"><!--Do not remove this to prevent uneven spacing
<ng-container *ngFor="let key of ((appliedFilters | async) | dsObjectKeys)"><!--Do not remove this to prevent uneven spacing
--><a *ngFor="let values of (appliedFilters | async)[key]"
class="badge badge-primary mr-1 mb-1 text-capitalize"
[routerLink]="getSearchLink()"
[queryParams]="(getRemoveParams(key, values) | async)" queryParamsHandling="merge">
{{('search.filters.applied.' + key) | translate}}: {{normalizeFilterValue(values)}}
<span> ×</span>
</a><!--Do not remove this to prevent uneven spacing
{{('search.filters.applied.' + key) | translate}}: {{normalizeFilterValue(values)}}
<span> ×</span>
</a><!--Do not remove this to prevent uneven spacing
--></ng-container>
</div>
</div>

View File

@@ -1,24 +1,14 @@
<ng-container *ngVar="(searchOptions$ | async) as config">
<h3>{{ 'search.sidebar.settings.title' | translate}}</h3>
<div *ngIf="config?.sort" class="setting-option result-order-settings mb-3 p-3">
<h5>{{ 'search.sidebar.settings.sort-by' | translate}}</h5>
<select class="form-control" (change)="reloadOrder($event)">
<option *ngFor="let sortOption of searchOptionPossibilities"
[value]="sortOption.field + ',' + sortOption.direction.toString()"
[selected]="sortOption.field === config?.sort.field && sortOption.direction === (config?.sort.direction)? 'selected': null">
{{'sorting.' + sortOption.field + '.' + sortOption.direction | translate}}
</option>
</select>
</div>
<div class="setting-option page-size-settings mb-3 p-3">
<h5>{{ 'search.sidebar.settings.rpp' | translate}}</h5>
<select class="form-control" (change)="reloadRPP($event)">
<option *ngFor="let pageSizeOption of config?.pagination.pageSizeOptions"
[value]="pageSizeOption"
[selected]="pageSizeOption === +config?.pagination.pageSize ? 'selected': null">
{{pageSizeOption}}
<h5>{{ 'search.sidebar.settings.sort-by' | translate}}</h5>
<select class="form-control" (change)="reloadOrder($event)">
<option *ngFor="let sortOption of searchOptionPossibilities"
[value]="sortOption.field + ',' + sortOption.direction.toString()"
[selected]="sortOption.field === config?.sort.field && sortOption.direction === (config?.sort.direction)? 'selected': null">
{{'sorting.' + sortOption.field + '.' + sortOption.direction | translate}}
</option>
</select>
</div>
<ds-page-size-selector></ds-page-size-selector>
</ng-container>

View File

@@ -18,12 +18,6 @@ import { currentPath } from '../../utils/route.utils';
* This component represents the part of the search sidebar that contains the general search settings.
*/
export class SearchSettingsComponent implements OnInit {
/**
* True when the search component should show results on the current page
*/
@Input() inPlaceSearch;
/**
* The configuration for the current paginated search results
*/
@@ -47,22 +41,6 @@ export class SearchSettingsComponent implements OnInit {
this.searchOptions$ = this.searchConfigurationService.paginatedSearchOptions;
}
/**
* Method to change the current page size (results per page)
* @param {Event} event Change event containing the new page size value
*/
reloadRPP(event: Event) {
const value = (event.target as HTMLInputElement).value;
const navigationExtras: NavigationExtras = {
queryParams: {
pageSize: value,
page: 1
},
queryParamsHandling: 'merge'
};
this.router.navigate(this.getSearchLinkParts(), navigationExtras);
}
/**
* Method to change the current sort field and direction
* @param {Event} event Change event containing the sort direction and sort field
@@ -77,26 +55,6 @@ export class SearchSettingsComponent implements OnInit {
},
queryParamsHandling: 'merge'
};
this.router.navigate(this.getSearchLinkParts(), navigationExtras);
}
/**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/
public getSearchLink(): string {
if (this.inPlaceSearch) {
return currentPath(this.router);
}
return this.service.getSearchLink();
}
/**
* @returns {string[]} The base path to the search page, or the current page when inPlaceSearch is true, split in separate pieces
*/
public getSearchLinkParts(): string[] {
if (this.service) {
return [];
}
return this.getSearchLink().split('/');
this.router.navigate([], navigationExtras);
}
}

View File

@@ -12,7 +12,7 @@
<div class="sidebar-content">
<ds-search-switch-configuration [inPlaceSearch]="inPlaceSearch" *ngIf="configurationList" [configurationList]="configurationList"></ds-search-switch-configuration>
<ds-search-filters [inPlaceSearch]="inPlaceSearch"></ds-search-filters>
<ds-search-settings [inPlaceSearch]="inPlaceSearch"></ds-search-settings>
<ds-search-settings></ds-search-settings>
</div>
</div>
</div>

View File

@@ -162,6 +162,7 @@ import { SearchAuthorityFilterComponent } from './search/search-filters/search-f
import { DsDynamicDisabledComponent } from './form/builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component';
import { DsDynamicLookupRelationSearchTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component';
import { DsDynamicLookupRelationSelectionTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component';
import { PageSizeSelectorComponent } from './page-size-selector/page-size-selector.component';
const MODULES = [
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
@@ -305,6 +306,7 @@ const COMPONENTS = [
SearchFacetRangeOptionComponent,
SearchSwitchConfigurationComponent,
SearchAuthorityFilterComponent,
PageSizeSelectorComponent
];
const ENTRY_COMPONENTS = [