[CST-7755] WIP refactoring

This commit is contained in:
Giuseppe Digilio
2023-02-10 19:47:20 +01:00
parent 52cd98a7d3
commit d82526af8a
16 changed files with 330 additions and 75 deletions

View File

@@ -6,9 +6,13 @@
</div>
<ds-listable-object-component-loader *ngIf="item$ | async"
[object]="item$ | async"
[supervisionOrders]="supervisionOrder$ | async"
[viewMode]="viewModes.ListElement"
[index]="index"
[linkType]="linkType"
[listID]="listID"></ds-listable-object-component-loader>
<div class="my-1">
<ds-supervision-order-status [supervisionOrderList]="supervisionOrder$ | async"
(delete)="deleteSupervisionOrder($event)"></ds-supervision-order-status>
</div>
<ds-workflow-item-admin-workflow-actions-element [wfi]="dso" [small]="false"></ds-workflow-item-admin-workflow-actions-element>

View File

@@ -1,21 +1,46 @@
import { Component, Inject, OnInit } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, mergeMap, take, tap } from 'rxjs/operators';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { ViewMode } from '../../../../../core/shared/view-mode.model';
import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import {
listableObjectComponent
} from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
import { Context } from '../../../../../core/shared/context.model';
import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model';
import { Observable } from 'rxjs';
import { LinkService } from '../../../../../core/cache/builders/link.service';
import { followLink } from '../../../../../shared/utils/follow-link-config.model';
import { RemoteData } from '../../../../../core/data/remote-data';
import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../core/shared/operators';
import {
getAllSucceededRemoteData,
getFirstCompletedRemoteData,
getRemoteDataPayload
} from '../../../../../core/shared/operators';
import { Item } from '../../../../../core/shared/item.model';
import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import {
SearchResultListElementComponent
} from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
import {
WorkflowItemSearchResult
} from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
import { APP_CONFIG, AppConfig } from '../../../../../../config/app-config.interface';
import { WorkspaceItemSearchResult } from '../../../../../shared/object-collection/shared/workspace-item-search-result.model';
import {
WorkspaceItemSearchResult
} from '../../../../../shared/object-collection/shared/workspace-item-search-result.model';
import { SupervisionOrder } from '../../../../../core/supervision-order/models/supervision-order.model';
import { SupervisionOrderDataService } from '../../../../../core/supervision-order/supervision-order-data.service';
import { PaginatedList } from '../../../../../core/data/paginated-list.model';
import { ConfirmationModalComponent } from '../../../../../shared/confirmation-modal/confirmation-modal.component';
import { hasValue } from '../../../../../shared/empty.util';
import {
SupervisionOrderListEntry
} from '../../../../../shared/object-list/supervision-order-status/supervision-order-status.component';
import { NotificationsService } from '../../../../../shared/notifications/notifications.service';
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.ListElement, Context.AdminWorkflowSearch)
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.ListElement, Context.AdminWorkflowSearch)
@@ -25,7 +50,7 @@ import { SupervisionOrder } from '../../../../../core/supervision-order/models/s
templateUrl: './workflow-item-search-result-admin-workflow-list-element.component.html'
})
/**
* The component for displaying a list element for an workflow item on the admin workflow search page
* The component for displaying a list element for a workflow item on the admin workflow search page
*/
export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends SearchResultListElementComponent<WorkflowItemSearchResult, WorkflowItem> implements OnInit {
@@ -34,14 +59,25 @@ export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends S
*/
public item$: Observable<Item>;
/**
* The id of the item linked to the workflow item
*/
public itemId: string;
/**
* The supervision orders linked to the workflow item
*/
public supervisionOrder$: Observable<SupervisionOrder>;
public supervisionOrder$: BehaviorSubject<SupervisionOrder[]> = new BehaviorSubject<SupervisionOrder[]>([]);
private messagePrefix = 'workflow-item.search.result';
constructor(private linkService: LinkService,
protected truncatableService: TruncatableService,
protected dsoNameService: DSONameService,
protected modalService: NgbModal,
protected notificationsService: NotificationsService,
protected supervisionOrderDataService: SupervisionOrderDataService,
protected translateService: TranslateService,
protected truncatableService: TruncatableService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(truncatableService, dsoNameService, appConfig);
@@ -53,7 +89,78 @@ export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends S
ngOnInit(): void {
super.ngOnInit();
this.dso = this.linkService.resolveLink(this.dso, followLink('item'));
this.supervisionOrder$ = (this.dso.supervisionOrders as Observable<RemoteData<SupervisionOrder>>)?.pipe(getAllSucceededRemoteData(), getRemoteDataPayload());
this.item$ = (this.dso.item as Observable<RemoteData<Item>>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload());
this.item$.pipe(
take(1),
tap((item: Item) => this.itemId = item.id),
mergeMap((item: Item) => this.retrieveSupervisorOrders(item.id))
).subscribe((supervisionOrderList: SupervisionOrder[]) => {
this.supervisionOrder$.next(supervisionOrderList);
})
}
/**
* Deletes the Group from the Repository. The Group will be the only that this form is showing.
* It'll either show a success or error message depending on whether the delete was successful or not.
*/
deleteSupervisionOrder(supervisionOrderEntry: SupervisionOrderListEntry) {
const modalRef = this.modalService.open(ConfirmationModalComponent);
modalRef.componentInstance.dso = supervisionOrderEntry.group;
modalRef.componentInstance.headerLabel = this.messagePrefix + '.delete-supervision.modal.header';
modalRef.componentInstance.infoLabel = this.messagePrefix + '.delete-supervision.modal.info';
modalRef.componentInstance.cancelLabel = this.messagePrefix + '.delete-supervision.modal.cancel';
modalRef.componentInstance.confirmLabel = this.messagePrefix + '.delete-supervision.modal.confirm';
modalRef.componentInstance.brandColor = 'danger';
modalRef.componentInstance.confirmIcon = 'fas fa-trash';
modalRef.componentInstance.response.pipe(
take(1),
mergeMap((confirm: boolean) => {
if (confirm && hasValue(supervisionOrderEntry.supervisionOrder.id)) {
return this.supervisionOrderDataService.delete(supervisionOrderEntry.supervisionOrder.id).pipe(
take(1),
tap((result: boolean) => {
if (result) {
this.notificationsService.success(
null,
this.translateService.get(
this.messagePrefix + '.notification.deleted.success',
{ name: this.dsoNameService.getName(supervisionOrderEntry.group) }
)
);
} else {
this.notificationsService.error(
null,
this.translateService.get(
this.messagePrefix + '.notification.deleted.failure',
{ name: this.dsoNameService.getName(supervisionOrderEntry.group) }
)
);
}
}),
mergeMap((result: boolean) => result ? this.retrieveSupervisorOrders(this.itemId) : this.supervisionOrder$.asObservable())
)
} else {
return this.supervisionOrder$.asObservable()
}
})
).subscribe((supervisionOrderList: SupervisionOrder[]) => {
this.supervisionOrder$.next(supervisionOrderList)
})
}
/**
* Retrieve the list of SupervisionOrder object related to the given item
*
* @param itemId
* @private
*/
private retrieveSupervisorOrders(itemId): Observable<SupervisionOrder[]> {
return this.supervisionOrderDataService.searchByItem(
itemId, false, true, followLink('group')
).pipe(
getFirstCompletedRemoteData(),
map((soRD: RemoteData<PaginatedList<SupervisionOrder>>) => soRD.hasSucceeded && !soRD.hasNoContent ? soRD.payload.page : [])
);
}
}

View File

@@ -15,6 +15,8 @@ import { excludeFromEquals } from '../../utilities/equals.decorators';
import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
import { CacheableObject } from '../../cache/cacheable-object.model';
import { SUPERVISION_ORDER } from '../../supervision-order/models/supervision-order.resource-type';
import { PaginatedList } from '../../data/paginated-list.model';
import { SupervisionOrder } from '../../supervision-order/models/supervision-order.model';
export interface SubmissionObjectError {
message: string;
@@ -101,6 +103,6 @@ export abstract class SubmissionObject extends DSpaceObject implements Cacheable
*/
@link(SUPERVISION_ORDER)
/* This was changed from 'Observable<RemoteData<WorkspaceItem>> | WorkspaceItem' to 'any' to prevent issues in templates with async */
supervisionOrders?: any;
supervisionOrders?: Observable<RemoteData<PaginatedList<SupervisionOrder>>>;
}

View File

@@ -13,7 +13,7 @@ import {
ViewChild
} from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { ListableObject } from '../listable-object.model';
@@ -41,11 +41,6 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
*/
@Input() object: ListableObject;
/**
* The supervision order to determine supervision orders
*/
@Input() supervisionOrders: Observable<any>;
/**
* The index of the object in the list
*/
@@ -76,6 +71,11 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
*/
@Input() showLabel = true;
/**
* Whether to show the supervision orders badges or not
*/
@Input() showSupervisionOrderBadges = false;
/**
* The value to display for this element
*/
@@ -128,7 +128,7 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
*/
protected inAndOutputNames: string[] = [
'object',
'supervisionOrders',
'showSupervisionOrderBadges',
'index',
'linkType',
'listID',

View File

@@ -46,6 +46,11 @@ export class AbstractListableElementComponent<T extends ListableObject> {
*/
@Input() showLabel = true;
/**
* Whether to show the supervision orders badges or not
*/
@Input() showSupervisionOrderBadges = false;
/**
* The context we matched on to get this component
*/

View File

@@ -1 +1 @@
<ds-item-search-result-list-element [showLabel]="showLabel" [object]="{ indexableObject: object, hitHighlights: {} }" [supervisionOrders]="supervisionOrders" [linkType]="linkType"></ds-item-search-result-list-element>
<ds-item-search-result-list-element [showLabel]="showLabel" [showSupervisionOrderBadges]="showSupervisionOrderBadges" [object]="{ indexableObject: object, hitHighlights: {} }" [supervisionOrders]="supervisionOrders" [linkType]="linkType"></ds-item-search-result-list-element>

View File

@@ -25,8 +25,13 @@
<ds-importable-list-item-control *ngIf="importable" [object]="object"
[importConfig]="importConfig"
(importObject)="importObject.emit($event)"></ds-importable-list-item-control>
<ds-listable-object-component-loader [object]="object" [viewMode]="viewMode" [index]="i" [context]="context" [linkType]="linkType"
<ds-listable-object-component-loader [object]="object"
[viewMode]="viewMode"
[index]="i"
[context]="context"
[linkType]="linkType"
[listID]="selectionConfig?.listId"
[showSupervisionOrderBadges]="showSupervisionOrderBadges"
(contentChange)="contentChange.emit($event)"></ds-listable-object-component-loader>
</li>
</ul>

View File

@@ -81,6 +81,11 @@ export class ObjectListComponent {
*/
@Input() showPaginator = true;
/**
* Whether to show the supervision orders badges or not
*/
@Input() showSupervisionOrderBadges = false;
/**
* Emit when one of the listed object has changed.
*/

View File

@@ -41,19 +41,6 @@
[innerHTML]="firstMetadataValue('dc.description.abstract')"></span>
</ds-truncatable-part>
</div>
<ng-container *ngVar="(supervisionOrder$ | async) as supervisionOrders">
<div class="item-list-supervision row" *ngIf="supervisionOrders?.length > 0">
<div class="col-md-3">
<span>{{'item.search.result.list.element.supervised-by' | translate}} </span>
</div>
<div class="col-md-9">
<span class="badge badge-primary d-table mt-1" *ngFor="let supervisionOrder of supervisionOrders">
{{supervisionOrder.group._name}}
<a [ngbTooltip]="'Remove supervision group'" (click)="deleteSupervisionOrder(supervisionOrder)">X</a>
</span>
</div>
</div>
</ng-container>
</ds-truncatable>
</div>
</div>

View File

@@ -1,5 +1,7 @@
import { Component, Inject } from '@angular/core';
import { listableObjectComponent } from '../../../../../object-collection/shared/listable-object/listable-object.decorator';
import {
listableObjectComponent
} from '../../../../../object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../../../../core/shared/view-mode.model';
import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model';
import { SearchResultListElementComponent } from '../../../search-result-list-element.component';
@@ -8,7 +10,7 @@ import { getItemPageRoute } from '../../../../../../item-page/item-page-routing-
import { SupervisionOrderDataService } from '../../../../../../core/supervision-order/supervision-order-data.service';
import { TruncatableService } from '../../../../../../shared/truncatable/truncatable.service';
import { DSONameService } from '../../../../../../core/breadcrumbs/dso-name.service';
import { AppConfig, APP_CONFIG } from '../../../../../../../config/app-config.interface';
import { APP_CONFIG, AppConfig } from '../../../../../../../config/app-config.interface';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { combineLatest, filter, map, Observable, switchMap, take } from 'rxjs';
import { ConfirmationModalComponent } from '../../../../../../shared/confirmation-modal/confirmation-modal.component';
@@ -16,11 +18,15 @@ import { hasValue } from '../../../../../../shared/empty.util';
import { NotificationsService } from '../../../../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { followLink } from '../../../../../../shared/utils/follow-link-config.model';
import { getAllSucceededRemoteListPayload, getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
import {
getAllSucceededRemoteData,
getAllSucceededRemoteListPayload,
getFirstSucceededRemoteDataPayload,
getRemoteDataPayload
} from '../../../../../../core/shared/operators';
import { SupervisionOrder } from '../../../../../../core/supervision-order/models/supervision-order.model';
import { Group } from '../../../../../../core/eperson/models/group.model';
import { ResourcePolicyDataService } from '../../../../../../core/resource-policy/resource-policy-data.service';
import { getAllSucceededRemoteData, getRemoteDataPayload } from '../../../../../../core/shared/operators';
import { AuthService } from '../../../../../../core/auth/auth.service';
import { EPerson } from '../../../../../../core/eperson/models/eperson.model';
import { EPersonDataService } from '../../../../../../core/eperson/eperson-data.service';

View File

@@ -0,0 +1,13 @@
<ng-container *ngVar="(supervisionOrderEntries$ | async) as supervisionOrders">
<div class="item-list-supervision row" *ngIf="supervisionOrders?.length > 0">
<div class="col-md-3">
<span>{{'workflow-item.search.result.list.element.supervised-by' | translate}} </span>
</div>
<div class="col-md-9">
<span class="badge badge-primary d-table mt-1" *ngFor="let supervisionOrder of supervisionOrders">
{{supervisionOrder.group.name}}
<a [ngbTooltip]="'workflow-item.search.result.list.element.supervised.remove-tooltip' | translate" (click)="deleteSupervisionOrder(supervisionOrder)">X</a>
</span>
</div>
</div>
</ng-container>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SupervisionOrderStatusComponent } from './supervision-order-status.component';
describe('SupervisionOrderStatusComponent', () => {
let component: SupervisionOrderStatusComponent;
let fixture: ComponentFixture<SupervisionOrderStatusComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ SupervisionOrderStatusComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(SupervisionOrderStatusComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,88 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { BehaviorSubject, from, Observable } from 'rxjs';
import { map, mergeMap, reduce } from 'rxjs/operators';
import { SupervisionOrder } from '../../../core/supervision-order/models/supervision-order.model';
import { Group } from '../../../core/eperson/models/group.model';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { isNotEmpty } from '../../empty.util';
import { RemoteData } from '../../../core/data/remote-data';
export interface SupervisionOrderListEntry {
supervisionOrder: SupervisionOrder;
group: Group
}
@Component({
selector: 'ds-supervision-order-status',
templateUrl: './supervision-order-status.component.html',
styleUrls: ['./supervision-order-status.component.scss']
})
export class SupervisionOrderStatusComponent implements OnChanges {
/**
* The list of supervision order object to show
*/
@Input() supervisionOrderList: SupervisionOrder[] = [];
/**
* The groups the user belongs to
*/
groups: Group[];
/**
* List of the supervision orders combined with the group
*/
supervisionOrderEntries$: BehaviorSubject<SupervisionOrderListEntry[]> = new BehaviorSubject([]);
@Output() delete: EventEmitter<SupervisionOrderListEntry> = new EventEmitter<SupervisionOrderListEntry>();
ngOnChanges(changes: SimpleChanges): void {
if (changes && changes.supervisionOrderList) {
this.getSupervisionOrderEntries(changes.supervisionOrderList.currentValue)
.subscribe((supervisionOrderEntries: SupervisionOrderListEntry[]) => {
this.supervisionOrderEntries$.next(supervisionOrderEntries)
})
}
console.log('ngOnChanges', changes);
}
/**
* Create a list of SupervisionOrderListEntry by the given SupervisionOrder list
*
* @param supervisionOrderList
*/
private getSupervisionOrderEntries(supervisionOrderList: SupervisionOrder[]): Observable<SupervisionOrderListEntry[]> {
return from(supervisionOrderList).pipe(
mergeMap((so: SupervisionOrder) => so.group.pipe(
getFirstCompletedRemoteData(),
map((sogRD: RemoteData<Group>) => {
if (sogRD.hasSucceeded) {
const entry: SupervisionOrderListEntry = {
supervisionOrder: so,
group: sogRD.payload
};
return entry;
} else {
return null;
}
})
)),
reduce((acc: SupervisionOrderListEntry[], value: any) => {
if (isNotEmpty(value)) {
return [...acc, value]
} else {
return acc;
}
}, []),
)
}
/**
* Emit a delete event with the given SupervisionOrderListEntry.
*/
deleteSupervisionOrder(supervisionOrder: SupervisionOrderListEntry) {
this.delete.emit(supervisionOrder);
}
}

View File

@@ -242,14 +242,20 @@ import { MenuModule } from './menu/menu.module';
import {
ListableNotificationObjectComponent
} from './object-list/listable-notification-object/listable-notification-object.component';
import { SupervisionGroupSelectorComponent } from './dso-selector/modal-wrappers/supervision-group-selector/supervision-group-selector.component';
import {
SupervisionGroupSelectorComponent
} from './dso-selector/modal-wrappers/supervision-group-selector/supervision-group-selector.component';
import { EpersonGroupListComponent } from './form/eperson-group-list/eperson-group-list.component';
import { EpersonSearchBoxComponent } from './form/eperson-group-list/eperson-search-box/eperson-search-box.component';
import { GroupSearchBoxComponent } from './form/eperson-group-list/group-search-box/group-search-box.component';
import { ThemedCollectionDropdownComponent } from './collection-dropdown/themed-collection-dropdown.component';
import { MetadataFieldWrapperComponent } from './metadata-field-wrapper/metadata-field-wrapper.component';
import { LogInExternalProviderComponent } from './log-in/methods/log-in-external-provider/log-in-external-provider.component';
import {
LogInExternalProviderComponent
} from './log-in/methods/log-in-external-provider/log-in-external-provider.component';
import {
SupervisionOrderStatusComponent
} from './object-list/supervision-order-status/supervision-order-status.component';
const MODULES = [
@@ -452,6 +458,7 @@ const DIRECTIVES = [
...COMPONENTS,
...ENTRY_COMPONENTS,
...DIRECTIVES,
SupervisionOrderStatusComponent,
],
providers: [
...PROVIDERS
@@ -463,6 +470,7 @@ const DIRECTIVES = [
...ENTRY_COMPONENTS,
...DIRECTIVES,
TranslateModule,
SupervisionOrderStatusComponent,
]
})

View File

@@ -2271,21 +2271,21 @@
"item.truncatable-part.show-less": "Collapse",
"item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
"workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
"item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order",
"workflow-item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order",
"item.search.result.delete-supervision.modal.cancel": "Cancel",
"workflow-item.search.result.delete-supervision.modal.cancel": "Cancel",
"item.search.result.delete-supervision.modal.confirm": "Delete",
"workflow-item.search.result.delete-supervision.modal.confirm": "Delete",
"item.search.result.notification.deleted.success": "Successfully deleted supervision order \"{{name}}\"",
"workflow-item.search.result.notification.deleted.success": "Successfully deleted supervision order \"{{name}}\"",
"item.search.result.notification.deleted.failure.title": "Failed to delete supervision order \"{{name}}\"",
"workflow-item.search.result.notification.deleted.failure": "Failed to delete supervision order \"{{name}}\"",
"item.search.result.notification.deleted.failure.content": "Failed to delete supervision order",
"workflow-item.search.result.list.element.supervised-by": "Supervised by:",
"item.search.result.list.element.supervised-by": "Supervised by:",
"workflow-item.search.result.list.element.supervised.remove-tooltip": "Remove supervision group",