diff --git a/src/app/core/data/bundle-data.service.ts b/src/app/core/data/bundle-data.service.ts index 027ec4e68a7..79f877fadd7 100644 --- a/src/app/core/data/bundle-data.service.ts +++ b/src/app/core/data/bundle-data.service.ts @@ -82,7 +82,10 @@ export class BundleDataService extends IdentifiableDataService implement */ // TODO should be implemented rest side findByItemAndName(item: Item, bundleName: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, options?: FindListOptions, ...linksToFollow: FollowLinkConfig[]): Observable> { - return this.findAllByItem(item, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe( + //Since we filter by bundleName where the pagination options are not indicated we need to load all the possible bundles. + // This is a workaround, in substitution of the previously recursive call with expand + const paginationOptions = options ?? { elementsPerPage: 9999 }; + return this.findAllByItem(item, paginationOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe( map((rd: RemoteData>) => { if (hasValue(rd.payload) && hasValue(rd.payload.page)) { const matchingBundle = rd.payload.page.find((bundle: Bundle) => @@ -115,47 +118,6 @@ export class BundleDataService extends IdentifiableDataService implement ); } - // findByItemAndName(item: Item, bundleName: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable> { - // return this.findAllByItem(item, { elementsPerPage: 1, currentPage: 1 }, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow).pipe( - // expand((rd: RemoteData>) => { - // if (rd.hasSucceeded && hasValue(rd.payload) && hasValue(rd.payload.page) && rd.payload.currentPage < rd.payload.totalPages) { - // const nextPageOptions = { elementsPerPage: 1, currentPage: rd.payload.currentPage + 1 }; - // return this.findAllByItem(item, nextPageOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); - // } else { - // return EMPTY; - // } - // }), - // map((rd: RemoteData>) => { - // if (hasValue(rd.payload) && hasValue(rd.payload.page)) { - // const matchingBundle = rd.payload.page.find((bundle: Bundle) => bundle.name === bundleName); - // if (hasValue(matchingBundle)) { - // return new RemoteData( - // rd.timeCompleted, - // rd.msToLive, - // rd.lastUpdated, - // RequestEntryState.Success, - // null, - // matchingBundle, - // 200 - // ); - // } else { - // return new RemoteData( - // rd.timeCompleted, - // rd.msToLive, - // rd.lastUpdated, - // RequestEntryState.Error, - // `The bundle with name ${bundleName} was not found.`, - // null, - // 404 - // ); - // } - // } else { - // return rd as any; - // } - // }) - // ); - // } - /** * Get the bitstreams endpoint for a bundle * @param bundleId diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html index 1564d3abc79..6ac44b5ac20 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html @@ -40,7 +40,7 @@ aria-describedby="reorder-description">
- +
-
- +
+
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts index 49b4bd11be9..c1964db1e75 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts @@ -9,6 +9,7 @@ import { Component, EventEmitter, Input, + OnDestroy, OnInit, Output, } from '@angular/core'; @@ -28,7 +29,10 @@ import { } from '@ng-dynamic-forms/core'; import { TranslateModule } from '@ngx-translate/core'; import findKey from 'lodash/findKey'; -import { BehaviorSubject } from 'rxjs'; +import { + BehaviorSubject, + Subscription, +} from 'rxjs'; import { map, tap, @@ -43,6 +47,7 @@ import { hasValue, isNotEmpty, } from '../../../../../empty.util'; +import { ThemedLoadingComponent } from '../../../../../loading/themed-loading.component'; import { FormBuilderService } from '../../../form-builder.service'; import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model'; import { DynamicListRadioGroupModel } from './dynamic-list-radio-group.model'; @@ -69,10 +74,11 @@ export interface ListItem { ReactiveFormsModule, AsyncPipe, TranslateModule, + ThemedLoadingComponent, ], standalone: true, }) -export class DsDynamicListComponent extends DynamicFormControlComponent implements OnInit { +export class DsDynamicListComponent extends DynamicFormControlComponent implements OnInit, OnDestroy { @Input() group: UntypedFormGroup; @Input() model: any; @@ -82,9 +88,10 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen @Output() focus: EventEmitter = new EventEmitter(); public items: ListItem[][] = []; - public showLoadMore$: BehaviorSubject = new BehaviorSubject(false); + public isLoading$: BehaviorSubject = new BehaviorSubject(true); protected optionsList: VocabularyEntry[] = []; private nextPageInfo: PageInfo; + private subs: Subscription[] = []; constructor(private vocabularyService: VocabularyService, private cdr: ChangeDetectorRef, @@ -104,6 +111,12 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen } } + ngOnDestroy() { + if (this.subs.length > 0) { + this.subs.forEach(sub => sub.unsubscribe()); + } + } + /** * Emits a blur event containing a given value. * @param event The value to emit. @@ -178,9 +191,9 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen setPaginationInfo(response: PaginatedList) { if (response.pageInfo.currentPage < response.pageInfo.totalPages) { this.nextPageInfo = Object.assign(new PageInfo(), response.pageInfo, { currentPage: response.currentPage + 1 }); - this.showLoadMore$.next(true); + this.isLoading$.next(true); } else { - this.showLoadMore$.next(false); + this.isLoading$.next(false); } } @@ -194,47 +207,53 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen listGroup = this.group.controls[this.model.id] as UntypedFormGroup; } - this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.nextPageInfo).pipe( - getFirstSucceededRemoteDataPayload(), - tap((response) => this.setPaginationInfo(response)), - map(entries => entries.page), - ).subscribe((allEntries: VocabularyEntry[]) => { - this.optionsList = [...this.optionsList, ...allEntries]; - let groupCounter = (this.items.length > 0) ? (this.items.length - 1) : 0; - let itemsPerGroup = 0; - let tempList: ListItem[] = []; - - // Make a list of available options (checkbox/radio) and split in groups of 'model.groupLength' - allEntries.forEach((option: VocabularyEntry, key: number) => { - const value = option.authority || option.value; - const checked: boolean = isNotEmpty(findKey( - this.model.value, - (v) => v?.value === option.value)); - - const item: ListItem = { - id: `${this.model.id}_${value}`, - label: option.display, - value: checked, - index: key, - }; - if (this.model.repeatable) { - this.formBuilderService.addFormGroupControl(listGroup, (this.model as DynamicListCheckboxGroupModel), new DynamicCheckboxModel(item)); - } else { - (this.model as DynamicListRadioGroupModel).options.push({ - label: item.label, - value: option, - }); - } - tempList.push(item); - itemsPerGroup++; - this.items[groupCounter] = tempList; - if (itemsPerGroup === this.model.groupLength) { - groupCounter++; - itemsPerGroup = 0; - tempList = []; + this.subs.push( + this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.nextPageInfo).pipe( + getFirstSucceededRemoteDataPayload(), + tap((response) => this.setPaginationInfo(response)), + map(entries => entries.page), + ).subscribe((allEntries: VocabularyEntry[]) => { + this.optionsList = [...this.optionsList, ...allEntries]; + let groupCounter = this.items.length; + let itemsPerGroup = 0; + let tempList: ListItem[] = []; + + // Make a list of available options (checkbox/radio) and split in groups of 'model.groupLength' + allEntries.forEach((option: VocabularyEntry) => { + const value = option.authority || option.value; + const checked: boolean = isNotEmpty(findKey( + this.model.value, + (v) => v?.value === option.value)); + + const item: ListItem = { + id: `${this.model.id}_${value}`, + label: option.display, + value: checked, + index: this.optionsList.indexOf(option), + }; + if (this.model.repeatable) { + this.formBuilderService.addFormGroupControl(listGroup, (this.model as DynamicListCheckboxGroupModel), new DynamicCheckboxModel(item)); + } else { + (this.model as DynamicListRadioGroupModel).options.push({ + label: item.label, + value: option, + }); + } + tempList.push(item); + itemsPerGroup++; + this.items[groupCounter] = tempList; + if (itemsPerGroup === this.model.groupLength) { + groupCounter++; + itemsPerGroup = 0; + tempList = []; + } + }); + this.cdr.markForCheck(); + // If the paginated request did not reach the end keep loading the entries in the background + if (this.isLoading$.value) { + this.loadEntries(); } - }); - this.cdr.markForCheck(); - }); + }), + ); } }