[CST-4633] Change dynamic-lookup-relation-search-tab.component in order to use search-component

This commit is contained in:
Giuseppe Digilio
2022-01-14 12:24:44 +01:00
parent 1f01cbaa93
commit d7388bcfd8
5 changed files with 101 additions and 114 deletions

View File

@@ -26,6 +26,7 @@
[toRemove]="toRemove"
(selectObject)="select($event)"
(deselectObject)="deselect($event)"
(resultFound)="setTotalInternals($event.pageInfo.totalElements)"
class="d-block pt-3">
</ds-dynamic-lookup-relation-search-tab>
</ng-template>
@@ -81,7 +82,7 @@
<i class="fas fa-times"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.metadata.discard-button" | translate}}</span>
</button>
<button class="btn btn-primary submit"
<button class="btn btn-primary submit"
[disabled]="(toAdd.length == 0 && toRemove.length == 0) || isPending"
(click)="submitEv()">
<span *ngIf="isPending" class="spinner-border spinner-border-sm" role="status"

View File

@@ -29,6 +29,7 @@ import { RemoteDataBuildService } from '../../../../../core/cache/builders/remot
import { getAllSucceededRemoteDataPayload } from '../../../../../core/shared/operators';
import { followLink } from '../../../../utils/follow-link-config.model';
import { RelationshipType } from '../../../../../core/shared/item-relationships/relationship-type.model';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
@Component({
selector: 'ds-dynamic-lookup-relation-modal',
@@ -111,7 +112,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
/**
* The total amount of internal items for the current options
*/
totalInternal$: Observable<number>;
totalInternal$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
/**
* The total amount of results for each external source using the current options
@@ -219,7 +220,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
select(...selectableObjects: SearchResult<Item>[]) {
this.zone.runOutsideAngular(
() => {
const obs: Observable<any[]> = observableCombineLatest(...selectableObjects.map((sri: SearchResult<Item>) => {
const obs: Observable<any[]> = observableCombineLatest([...selectableObjects.map((sri: SearchResult<Item>) => {
this.addNameVariantSubscription(sri);
return this.relationshipService.getNameVariant(this.listId, sri.indexableObject.uuid)
.pipe(
@@ -232,7 +233,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
})
);
})
);
]);
obs
.subscribe((arr: any[]) => {
return arr.forEach((object: any) => {
@@ -281,21 +282,22 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
* Calculate and set the total entries available for each tab
*/
setTotals() {
this.totalInternal$ = this.searchConfigService.paginatedSearchOptions.pipe(
switchMap((options) => this.lookupRelationService.getTotalLocalResults(this.relationshipOptions, options))
);
const externalSourcesAndOptions$ = observableCombineLatest(
const externalSourcesAndOptions$ = observableCombineLatest([
this.externalSourcesRD$,
this.searchConfigService.paginatedSearchOptions
);
]);
this.totalExternal$ = externalSourcesAndOptions$.pipe(
switchMap(([sources, options]) =>
observableCombineLatest(...sources.map((source: ExternalSource) => this.lookupRelationService.getTotalExternalResults(source, options))))
observableCombineLatest([...sources.map((source: ExternalSource) => this.lookupRelationService.getTotalExternalResults(source, options))]))
);
}
setTotalInternals(totalPages: number) {
this.totalInternal$.next(totalPages);
}
ngOnDestroy() {
this.router.navigate([], {});
Object.values(this.subMap).forEach((subscription) => subscription.unsubscribe());

View File

@@ -1,73 +1,62 @@
<div class="row">
<ds-search-sidebar class="col-4" id="search-sidebar"
[resultCount]="(resultsRD$ | async)?.payload?.totalElements"
[inPlaceSearch]="true" [showViewModes]="false"></ds-search-sidebar>
<div class="col-8">
<ds-search-form [query]="(searchConfigService.paginatedSearchOptions | async)?.query"
[inPlaceSearch]="true"
[searchPlaceholder]="'submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder' | translate">
</ds-search-form>
<ds-search *ngIf="this.relationship.searchConfiguration && context"
[configuration]="this.relationship.searchConfiguration"
[context]="context"
[fixedFilterQuery]="this.relationship.filter"
[inPlaceSearch]="true"
[linkType]="linkTypes.ExternalLink"
[searchFormPlaceholder]="'submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder'"
[selectable]="true"
[selectionConfig]="{ repeatable: repeatable, listId: listId }"
(resultFound)="onResultFound($event)"
(deselectObject)="deselectObject.emit($event)"
(selectObject)="selectObject.emit($event)">
<div additionalSearchOptions *ngIf="repeatable" class="position-absolute">
<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. -->
<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">
<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="!allSelected && !(someSelected$ | async)"
type="checkbox"
[indeterminate]="false"
(change)="selectAll()">
<input *ngIf="!allSelected && (someSelected$ | async)"
type="checkbox"
[indeterminate]="true"
(change)="deselectAll()">
<input *ngIf="allSelected" type="checkbox"
[checked]="true"
(change)="deselectAll()">
</div>
</div>
<div ngbDropdown class="input-group-append">
<button *ngIf="selectAllLoading" type="button"
class="btn btn-outline-secondary rounded-right">
<input *ngIf="!allSelected && !(someSelected$ | async)"
type="checkbox"
[indeterminate]="false"
(change)="selectAll()">
<input *ngIf="!allSelected && (someSelected$ | async)"
type="checkbox"
[indeterminate]="true"
(change)="deselectAll()">
<input *ngIf="allSelected" type="checkbox"
[checked]="true"
(change)="deselectAll()">
</div>
</div>
<div ngbDropdown class="input-group-append">
<button *ngIf="selectAllLoading" type="button"
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.search-tab.loading' | translate) }}</span>
</button>
<button id="resultdropdown" type="button"
ngbDropdownToggle
class="btn btn-outline-secondary dropdown-toggle-split"
data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false"
[hidden]="selectAllLoading">
<span class="sr-only">{{ ('submission.sections.describe.relationship-lookup.toggle-dropdown' | translate) }}</span>
</button>
<div ngbDropdownMenu aria-labelledby="resultdropdown" *ngVar="(resultsRD$ | async) as resultsRD">
<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>
<span class="sr-only">{{ ('submission.sections.describe.relationship-lookup.search-tab.loading' | translate) }}</span>
</button>
<button id="resultdropdown" type="button"
ngbDropdownToggle
class="btn btn-outline-secondary dropdown-toggle-split"
data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false"
[hidden]="selectAllLoading">
<span class="sr-only">{{ ('submission.sections.describe.relationship-lookup.toggle-dropdown' | translate) }}</span>
</button>
<div ngbDropdownMenu aria-labelledby="resultdropdown" *ngVar="(resultsRD$ | async) as resultsRD">
<button class="dropdown-item"
(click)="selectPage(resultsRD?.page)">{{ ('submission.sections.describe.relationship-lookup.search-tab.select-page' | translate) }}</button>
<button class="dropdown-item"
(click)="deselectPage(resultsRD?.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>
<ds-search-results [searchResults]="(resultsRD$ | async)"
[sortConfig]="this.lookupRelationService.searchConfig?.sort"
[searchConfig]="this.lookupRelationService.searchConfig"
[selectable]="true"
[selectionConfig]="{ repeatable: repeatable, listId: listId }"
[linkType]="linkTypes.ExternalLink"
[context]="context"
(deselectObject)="deselectObject.emit($event)"
(selectObject)="selectObject.emit($event)">
</ds-search-results>
</div>
</div>
</div>
</div>
</ds-search>

View File

@@ -4,7 +4,6 @@ import { DsDynamicLookupRelationSearchTabComponent } from './dynamic-lookup-rela
import { SearchService } from '../../../../../../core/shared/search/search.service';
import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service';
import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service';
import { RouteService } from '../../../../../../core/services/route.service';
import { RouterTestingModule } from '@angular/router/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { VarDirective } from '../../../../../utils/var.directive';
@@ -15,13 +14,13 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../remote-data.ut
import { buildPaginatedList } from '../../../../../../core/data/paginated-list.model';
import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model';
import { Item } from '../../../../../../core/shared/item.model';
import { ActivatedRoute } from '@angular/router';
import { LookupRelationService } from '../../../../../../core/data/lookup-relation.service';
import { PaginationService } from '../../../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub';
import { RelationshipService } from '../../../../../../core/data/relationship.service';
import { relatedRelationships } from '../../../../../testing/related-relationships.mock';
import { RelationshipType } from '../../../../../../core/shared/item-relationships/relationship-type.model';
import { SearchObjects } from '../../../../../search/models/search-objects.model';
describe('DsDynamicLookupRelationSearchTabComponent', () => {
@@ -41,6 +40,7 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => {
let selection$;
let results;
let searchResult;
let selectableListService;
let lookupRelationService;
const relationshipService = jasmine.createSpyObj('searchByItemsAndType',{
@@ -79,6 +79,9 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => {
selection$ = observableOf([searchResult1, searchResult2]);
results = buildPaginatedList(undefined, [searchResult1, searchResult2, searchResult3]);
searchResult = Object.assign(new SearchObjects(), {
page: [searchResult1, searchResult2, searchResult3]
});
selectableListService = jasmine.createSpyObj('selectableListService', ['deselect', 'select', 'deselectAll']);
lookupRelationService = jasmine.createSpyObj('lookupRelationService', {
getLocalResults: createSuccessfulRemoteDataObject$(results)
@@ -101,14 +104,6 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => {
paginatedSearchOptions: observableOf(pSearchOptions)
}
},
{
provide: RouteService, useValue: {
setParameter: () => {
// do nothing
}
}
},
{ provide: ActivatedRoute, useValue: { snapshot: { queryParams: {} } } },
{ provide: LookupRelationService, useValue: lookupRelationService },
{ provide: PaginationService, useValue: new PaginationServiceStub() },
{ provide: RelationshipService, useValue: relationshipService }
@@ -186,6 +181,7 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => {
describe('check searchByItemsAndType', () => {
it('should call relationshipService.searchByItemsAndType', () => {
component.onResultFound(searchResult);
expect(relationshipService.searchByItemsAndType).toHaveBeenCalled();
});
});

View File

@@ -4,18 +4,15 @@ import { SearchConfigurationService } from '../../../../../../core/shared/search
import { Item } from '../../../../../../core/shared/item.model';
import { SearchResult } from '../../../../../search/models/search-result.model';
import { PaginatedList } from '../../../../../../core/data/paginated-list.model';
import { RemoteData } from '../../../../../../core/data/remote-data';
import { Observable } from 'rxjs';
import { RelationshipOptions } from '../../../models/relationship-options.model';
import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model';
import { ListableObject } from '../../../../../object-collection/shared/listable-object.model';
import { SearchService } from '../../../../../../core/shared/search/search.service';
import { ActivatedRoute, Router } from '@angular/router';
import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service';
import { hasValue } from '../../../../../empty.util';
import { map, mapTo, startWith, switchMap, take, tap } from 'rxjs/operators';
import { map, mapTo, switchMap, take, tap } from 'rxjs/operators';
import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../../../../../../core/shared/operators';
import { RouteService } from '../../../../../../core/services/route.service';
import { CollectionElementLinkType } from '../../../../../object-collection/collection-element-link.type';
import { Context } from '../../../../../../core/shared/context.model';
import { LookupRelationService } from '../../../../../../core/data/lookup-relation.service';
@@ -24,6 +21,9 @@ import { RelationshipService } from '../../../../../../core/data/relationship.se
import { RelationshipType } from '../../../../../../core/shared/item-relationships/relationship-type.model';
import { Relationship } from '../../../../../../core/shared/item-relationships/relationship.model';
import { SearchObjects } from '../../../../../search/models/search-objects.model';
import { DSpaceObject } from '../../../../../../core/shared/dspace-object.model';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
@Component({
@@ -107,7 +107,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
/**
* Search results
*/
resultsRD$: Observable<RemoteData<PaginatedList<SearchResult<Item>>>>;
resultsRD$: BehaviorSubject<SearchObjects<DSpaceObject>> = new BehaviorSubject<SearchObjects<DSpaceObject>>(null);
/**
* Are all results selected?
@@ -142,13 +142,15 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
*/
linkTypes = CollectionElementLinkType;
/**
* Emits an event with the current search result entries
*/
@Output() resultFound: EventEmitter<SearchObjects<DSpaceObject>> = new EventEmitter<SearchObjects<DSpaceObject>>();
constructor(
private searchService: SearchService,
private router: Router,
private route: ActivatedRoute,
private selectableListService: SelectableListService,
public searchConfigService: SearchConfigurationService,
private routeService: RouteService,
public lookupRelationService: LookupRelationService,
private relationshipService: RelationshipService,
private paginationService: PaginationService
@@ -160,21 +162,6 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
*/
ngOnInit(): void {
this.resetRoute();
this.routeService.setParameter('fixedFilterQuery', this.relationship.filter);
this.routeService.setParameter('configuration', this.relationship.searchConfiguration);
this.resultsRD$ = this.searchConfigService.paginatedSearchOptions.pipe(
switchMap((options) => this.lookupRelationService.getLocalResults(this.relationship, options).pipe(
tap( res => {
if ( !!res && res.hasSucceeded && this.isEditRelationship ) {
const idOfItems = res.payload.page.map( itemSearchResult => {
return itemSearchResult.indexableObject.uuid;
});
this.setSelectedIds(idOfItems,res.payload.page);
}
}),
startWith(undefined),
))
);
}
/**
@@ -188,7 +175,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
* Selects a page in the store
* @param page The page to select
*/
selectPage(page: SearchResult<Item>[]) {
selectPage(page: SearchResult<DSpaceObject>[]) {
this.selection$
.pipe(take(1))
.subscribe((selection: SearchResult<Item>[]) => {
@@ -202,7 +189,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
* Deselects a page in the store
* @param page the page to deselect
*/
deselectPage(page: SearchResult<Item>[]) {
deselectPage(page: SearchResult<DSpaceObject>[]) {
this.allSelected = false;
this.selection$
.pipe(take(1))
@@ -306,4 +293,16 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest
this.subscription.unsubscribe();
}
}
onResultFound($event: SearchObjects<DSpaceObject>) {
console.log($event);
this.resultsRD$.next($event);
this.resultFound.emit($event);
if (this.isEditRelationship ) {
const idOfItems = $event.page.map( itemSearchResult => {
return itemSearchResult.indexableObject.uuid;
});
this.setSelectedIds(idOfItems, $event);
}
}
}