Merge pull request #3412 from alexandrevryghem/w2p-117287_fix-item-version-performance-issues_contribute-8_x

[Port dspace-8_x] Fixed Edit Item's Version History crashing
This commit is contained in:
Tim Donohue
2024-10-11 14:14:47 -05:00
committed by GitHub
2 changed files with 113 additions and 107 deletions

View File

@@ -1,91 +1,90 @@
<div *ngVar="(versionsRD$ | async)?.payload as versions"> <div *ngIf="(versionsDTO$ | async) as versionsDTO; else noItemVersion" class="mb-2">
<div *ngVar="(versionRD$ | async)?.payload as itemVersion"> <div *ngIf="(versionRD$ | async)?.payload as itemVersion">
<div class="mb-2" *ngIf="versions?.page?.length > 0 || displayWhenEmpty"> <h2 *ngIf="displayTitle" class="h4">{{"item.version.history.head" | translate}}</h2>
<h2 *ngIf="displayTitle" class="h4">{{"item.version.history.head" | translate}}</h2> <ds-alert [type]="AlertTypeEnum.Info">
<ds-alert [type]="AlertTypeEnum.Info" *ngIf="itemVersion"> {{ "item.version.history.selected.alert" | translate : { version: itemVersion.version } }}
{{ "item.version.history.selected.alert" | translate : {version: itemVersion.version} }} </ds-alert>
</ds-alert> <ds-pagination *ngIf="versionsDTO.versionDTOs.length > 0"
<ds-pagination *ngIf="versions?.page?.length > 0" (paginationChange)="onPageChange()"
(paginationChange)="onPageChange()" [hideGear]="true"
[hideGear]="true" [hidePagerWhenSinglePage]="true"
[hidePagerWhenSinglePage]="true" [paginationOptions]="options"
[paginationOptions]="options" [collectionSize]="versionsDTO.totalElements"
[collectionSize]="versions?.totalElements" [retainScrollPosition]="true">
[retainScrollPosition]="true"> <table class="table table-striped table-bordered align-middle my-2">
<table class="table table-striped table-bordered align-middle my-2"> <thead>
<thead> <tr>
<tr> <th scope="col">{{ "item.version.history.table.version" | translate }}</th>
<th scope="col">{{"item.version.history.table.version" | translate}}</th> <th scope="col" *ngIf="(showSubmitter$ | async)">{{ "item.version.history.table.editor" | translate }}</th>
<th scope="col" *ngIf="(showSubmitter$ | async)">{{"item.version.history.table.editor" | translate}}</th> <th scope="col">{{ "item.version.history.table.date" | translate }}</th>
<th scope="col">{{"item.version.history.table.date" | translate}}</th> <th scope="col">{{ "item.version.history.table.summary" | translate }}</th>
<th scope="col">{{"item.version.history.table.summary" | translate}}</th> </tr>
</tr> </thead>
</thead> <tbody>
<tbody> <tr *ngFor="let versionDTO of versionsDTO.versionDTOs" [id]="'version-row-' + versionDTO.version.id">
<tr *ngFor="let version of versions?.page" [id]="'version-row-' + version.id"> <td class="version-row-element-version">
<td class="version-row-element-version"> <ds-item-versions-row-element-version [hasDraftVersion]="hasDraftVersion$ | async"
<ds-item-versions-row-element-version [hasDraftVersion]="hasDraftVersion$ | async" [version]="versionDTO.version"
[version]="version" [item]="item" [displayActions]="displayActions"
[item]="item" [displayActions]="displayActions" [itemVersion]="itemVersion"
[itemVersion]="itemVersion" [versionBeingEditedNumber]="versionBeingEditedNumber"
[versionBeingEditedNumber]="versionBeingEditedNumber" (versionsHistoryChange)="getAllVersions($event)"
(versionsHistoryChange)="getAllVersions($event)" ></ds-item-versions-row-element-version>
></ds-item-versions-row-element-version> </td>
</td> <td class="version-row-element-editor" *ngIf="(showSubmitter$ | async)">
<td class="version-row-element-editor" *ngIf="(showSubmitter$ | async)"> {{ versionDTO.version.submitterName }}
{{version?.submitterName}} </td>
</td> <td class="version-row-element-date">
<td class="version-row-element-date"> {{ versionDTO.version.created | date : 'yyyy-MM-dd HH:mm:ss' }}
{{version?.created | date : 'yyyy-MM-dd HH:mm:ss'}} </td>
</td> <td class="version-row-element-summary">
<td class="version-row-element-summary"> <div class="float-left">
<div class="float-left"> <ng-container
<ng-container *ngIf="isThisBeingEdited(version); then editSummary else showSummary"></ng-container> *ngIf="isThisBeingEdited(versionDTO.version); then editSummary else showSummary"></ng-container>
<ng-template #showSummary>{{version?.summary}}</ng-template> <ng-template #showSummary>{{ versionDTO.version.summary }}</ng-template>
<ng-template #editSummary> <ng-template #editSummary>
<input [attr.aria-label]="'item.version.history.table.action.editSummary' | translate" <input [attr.aria-label]="'item.version.history.table.action.editSummary' | translate"
[(ngModel)]="versionBeingEditedSummary" (keyup.enter)="onSummarySubmit()" [(ngModel)]="versionBeingEditedSummary" (keyup.enter)="onSummarySubmit()"
class="form-control" type="text"/> class="form-control" type="text"/>
</ng-template> </ng-template>
</div> </div>
<div class="float-right btn-group edit-field space-children-mr" *ngIf="displayActions"> <div class="float-right btn-group edit-field space-children-mr" *ngIf="displayActions && versionDTO.canEditVersion | async">
<!--DISCARD EDIT --> <ng-container *ngIf="isThisBeingEdited(versionDTO.version); else notThisBeingEdited">
<ng-container *ngIf="(canEditVersion$(version) | async) && isThisBeingEdited(version)"> <!--DISCARD EDIT-->
<button class="btn btn-sm" <button class="btn btn-sm btn-outline-warning"
[ngClass]="isThisBeingEdited(version) ? 'btn-outline-warning' : 'btn-outline-primary'" (click)="disableVersionEditing()"
(click)="disableVersionEditing()" title="{{'item.version.history.table.action.discardSummary' | translate}}">
title="{{'item.version.history.table.action.discardSummary' | translate}}"> <i class="fas fa-undo-alt fa-fw"></i>
<i class="fas fa-undo-alt fa-fw"></i> </button>
</button> <!--SAVE-->
</ng-container> <button class="btn btn-outline-success btn-sm"
<!--EDIT / SAVE--> (click)="onSummarySubmit()"
<ng-container *ngIf="canEditVersion$(version) | async"> title="{{'item.version.history.table.action.saveSummary' | translate}}">
<button class="btn btn-outline-primary btn-sm version-row-element-edit" <i class="fas fa-check fa-fw"></i>
*ngIf="!isThisBeingEdited(version)" </button>
[disabled]="isAnyBeingEdited()" </ng-container>
(click)="enableVersionEditing(version)" <ng-template #notThisBeingEdited>
title="{{'item.version.history.table.action.editSummary' | translate}}"> <!--EDIT-->
<i class="fas fa-edit fa-fw"></i> <button class="btn btn-outline-primary btn-sm version-row-element-edit"
</button> [disabled]="isAnyBeingEdited()"
<button class="btn btn-outline-success btn-sm" (click)="enableVersionEditing(versionDTO.version)"
*ngIf="isThisBeingEdited(version)" title="{{'item.version.history.table.action.editSummary' | translate}}">
(click)="onSummarySubmit()" <i class="fas fa-edit fa-fw"></i>
title="{{'item.version.history.table.action.saveSummary' | translate}}"> </button>
<i class="fas fa-check fa-fw"></i> </ng-template>
</button> </div>
</ng-container> </td>
</div> </tr>
</tbody>
</table>
</td> <div>*&nbsp;{{"item.version.history.selected" | translate}}</div>
</tr> </ds-pagination>
</tbody>
</table>
<div>*&nbsp;{{"item.version.history.selected" | translate}}</div>
</ds-pagination>
<ds-alert *ngIf="!itemVersion || versions?.page?.length === 0" [content]="'item.version.history.empty'"
[type]="AlertTypeEnum.Info"></ds-alert>
</div>
</div> </div>
</div> </div>
<ng-template #noItemVersion>
<ds-alert *ngIf="displayWhenEmpty"
[content]="'item.version.history.empty'"
[type]="AlertTypeEnum.Info">
</ds-alert>
</ng-template>

View File

@@ -18,7 +18,6 @@ import {
TranslateService, TranslateService,
} from '@ngx-translate/core'; } from '@ngx-translate/core';
import { import {
BehaviorSubject,
combineLatest, combineLatest,
Observable, Observable,
Subscription, Subscription,
@@ -64,6 +63,16 @@ import { VarDirective } from '../../shared/utils/var.directive';
import { getItemPageRoute } from '../item-page-routing-paths'; import { getItemPageRoute } from '../item-page-routing-paths';
import { ItemVersionsRowElementVersionComponent } from './item-versions-row-element-version/item-versions-row-element-version.component'; import { ItemVersionsRowElementVersionComponent } from './item-versions-row-element-version/item-versions-row-element-version.component';
interface VersionsDTO {
totalElements: number;
versionDTOs: VersionDTO[];
}
interface VersionDTO {
version: Version;
canEditVersion: Observable<boolean>;
}
@Component({ @Component({
selector: 'ds-item-versions', selector: 'ds-item-versions',
templateUrl: './item-versions.component.html', templateUrl: './item-versions.component.html',
@@ -126,16 +135,15 @@ export class ItemVersionsComponent implements OnDestroy, OnInit {
versionHistory$: Observable<VersionHistory>; versionHistory$: Observable<VersionHistory>;
/** /**
* The version history's list of versions * The version history information that is used to render the HTML
*/ */
versionsRD$: BehaviorSubject<RemoteData<PaginatedList<Version>>> = new BehaviorSubject<RemoteData<PaginatedList<Version>>>(null); versionsDTO$: Observable<VersionsDTO>;
/** /**
* Verify if the list of versions has at least one e-person to display * Verify if the list of versions has at least one e-person to display
* Used to hide the "Editor" column when no e-persons are present to display * Used to hide the "Editor" column when no e-persons are present to display
*/ */
hasEpersons$: Observable<boolean>; hasEpersons$: Observable<boolean>;
/** /**
* Verify if there is an inprogress submission in the version history * Verify if there is an inprogress submission in the version history
* Used to disable the "Create version" button * Used to disable the "Create version" button
@@ -186,9 +194,6 @@ export class ItemVersionsComponent implements OnDestroy, OnInit {
*/ */
versionBeingEditedSummary: string; versionBeingEditedSummary: string;
canCreateVersion$: Observable<boolean>;
createVersionTitle$: Observable<string>;
constructor(private versionHistoryService: VersionHistoryDataService, constructor(private versionHistoryService: VersionHistoryDataService,
private versionService: VersionDataService, private versionService: VersionDataService,
private paginationService: PaginationService, private paginationService: PaginationService,
@@ -305,16 +310,22 @@ export class ItemVersionsComponent implements OnDestroy, OnInit {
*/ */
getAllVersions(versionHistory$: Observable<VersionHistory>): void { getAllVersions(versionHistory$: Observable<VersionHistory>): void {
const currentPagination = this.paginationService.getCurrentPagination(this.options.id, this.options); const currentPagination = this.paginationService.getCurrentPagination(this.options.id, this.options);
combineLatest([versionHistory$, currentPagination]).pipe( this.versionsDTO$ = combineLatest([versionHistory$, currentPagination]).pipe(
switchMap(([versionHistory, options]: [VersionHistory, PaginationComponentOptions]) => { switchMap(([versionHistory, options]: [VersionHistory, PaginationComponentOptions]) => {
return this.versionHistoryService.getVersions(versionHistory.id, return this.versionHistoryService.getVersions(versionHistory.id,
new PaginatedSearchOptions({ pagination: Object.assign({}, options, { currentPage: options.currentPage }) }), new PaginatedSearchOptions({ pagination: Object.assign({}, options, { currentPage: options.currentPage }) }),
false, true, followLink('item'), followLink('eperson')); false, true, followLink('item'), followLink('eperson'));
}), }),
getFirstCompletedRemoteData(), getFirstCompletedRemoteData(),
).subscribe((res: RemoteData<PaginatedList<Version>>) => { getRemoteDataPayload(),
this.versionsRD$.next(res); map((versions: PaginatedList<Version>) => ({
}); totalElements: versions.totalElements,
versionDTOs: (versions?.page ?? []).map((version: Version) => ({
version: version,
canEditVersion: this.canEditVersion$(version),
})),
})),
);
} }
/** /**
@@ -348,16 +359,12 @@ export class ItemVersionsComponent implements OnDestroy, OnInit {
); );
this.getAllVersions(this.versionHistory$); this.getAllVersions(this.versionHistory$);
this.hasEpersons$ = this.versionsRD$.pipe( this.hasEpersons$ = this.versionsDTO$.pipe(
getAllSucceededRemoteData(), map((versionsDTO: VersionsDTO) => versionsDTO.versionDTOs.filter((versionDTO: VersionDTO) => versionDTO.version.eperson !== undefined).length > 0),
getRemoteDataPayload(),
hasValueOperator(),
map((versions: PaginatedList<Version>) => versions.page.filter((version: Version) => version.eperson !== undefined).length > 0),
startWith(false), startWith(false),
); );
this.itemPageRoutes$ = this.versionsRD$.pipe( this.itemPageRoutes$ = this.versionsDTO$.pipe(
getAllSucceededRemoteDataPayload(), switchMap((versionsDTO: VersionsDTO) => combineLatest(versionsDTO.versionDTOs.map((versionDTO: VersionDTO) => versionDTO.version.item.pipe(getAllSucceededRemoteDataPayload())))),
switchMap((versions) => combineLatest(versions.page.map((version) => version.item.pipe(getAllSucceededRemoteDataPayload())))),
map((versions) => { map((versions) => {
const itemPageRoutes = {}; const itemPageRoutes = {};
versions.forEach((item) => itemPageRoutes[item.uuid] = getItemPageRoute(item)); versions.forEach((item) => itemPageRoutes[item.uuid] = getItemPageRoute(item));