refactor, add detail mapping, add missing translation, optimize modal

This commit is contained in:
FrancescoMolinaro
2024-01-08 16:47:24 +01:00
parent 4d30bc7035
commit c57ad8eeb7
22 changed files with 358 additions and 338 deletions

View File

@@ -34,11 +34,27 @@ import {
path: 'inbound',
component: AdminNotifyIncomingComponent,
canActivate: [SiteAdministratorGuard],
resolve: {
breadcrumb: I18nBreadcrumbResolver,
},
data: {
title: 'admin.notify.dashboard.page.title',
breadcrumbKey: 'admin.notify.dashboard',
showBreadcrumbsFluid: false
},
},
{
path: 'outbound',
component: AdminNotifyOutgoingComponent,
canActivate: [SiteAdministratorGuard],
resolve: {
breadcrumb: I18nBreadcrumbResolver,
},
data: {
title: 'admin.notify.dashboard.page.title',
breadcrumbKey: 'admin.notify.dashboard',
showBreadcrumbsFluid: false
},
}
])
],

View File

@@ -8,14 +8,13 @@ import { AdminNotifyIncomingComponent } from './admin-notify-logs/admin-notify-i
import { SharedModule } from '../../shared/shared.module';
import { SearchModule } from '../../shared/search/search.module';
import { SearchPageModule } from '../../search-page/search-page.module';
import { AdminNotifyIncomingSearchResultComponent } from './admin-notify-search-result/incoming/admin-notify-incoming-search-result.component';
import {
AdminNotifyOutgoingComponent
} from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
import { AdminNotifyDetailModalComponent } from './admin-notify-detail-modal/admin-notify-detail-modal.component';
import {
AdminNotifyOutgoingSearchResultComponent
} from "./admin-notify-search-result/outgoing/admin-notify-outgoing-search-result.component";
AdminNotifySearchResultComponent
} from "./admin-notify-search-result/admin-notify-search-result.component";
import { AdminNotifyMessagesService } from "./services/admin-notify-messages.service";
@@ -36,8 +35,7 @@ import { AdminNotifyMessagesService } from "./services/admin-notify-messages.ser
AdminNotifyMetricsComponent,
AdminNotifyIncomingComponent,
AdminNotifyOutgoingComponent,
AdminNotifyIncomingSearchResultComponent,
AdminNotifyOutgoingSearchResultComponent,
AdminNotifySearchResultComponent,
AdminNotifyDetailModalComponent
]
})

View File

@@ -1,14 +1,14 @@
<div class="modal-header">
<h4 class="modal-title">Message Detail</h4>
<h4 class="modal-title">{{'notify-message-modal.title' | translate}}</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="d-flex modal-body flex-column p-4">
<div class="container p-4">
<div *ngFor="let key of notifyMessageKeys">
<div class="d-flex w-100 justify-content-between mb-4">
<div class="font-weight-bold mr-5">{{ key }}</div>
<div class="text-nowrap text-truncate">{{ notifyMessage[key] }}</div>
<div class="row mb-4">
<div class="font-weight-bold col-sm">{{ key + '.notify-detail-modal' | translate}}</div>
<div class="text-nowrap col-sm text-right">{{ notifyMessage[key] }}</div>
</div>
</div>
</div>

View File

@@ -21,7 +21,6 @@
[showViewModes]="false"
[searchEnabled]="false"
[context]="context"
[useUniquePageId]="true"
></ds-themed-search>
</div>
</div>

View File

@@ -16,7 +16,7 @@ import { SearchConfigurationService } from "../../../../core/shared/search/searc
]
})
export class AdminNotifyIncomingComponent {
protected readonly context = Context.CoarNotifyIncoming;
protected readonly context = Context.CoarNotify;
constructor(@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {
}
}

View File

@@ -21,7 +21,6 @@
[showViewModes]="false"
[searchEnabled]="false"
[context]="context"
[useUniquePageId]="true"
></ds-themed-search>
</div>
</div>

View File

@@ -16,7 +16,7 @@ import { SearchConfigurationService } from "../../../../core/shared/search/searc
]
})
export class AdminNotifyOutgoingComponent {
protected readonly context = Context.CoarNotifyOutgoing;
protected readonly context = Context.CoarNotify;
constructor(@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {
}

View File

@@ -0,0 +1,43 @@
<div class="table-responsive mt-2">
<table class="table table-striped table-hover">
<thead>
<tr class="text-nowrap">
<th scope="col">{{ 'notify-message-result.timestamp' | translate}}</th>
<th scope="col">{{'notify-message-result.repositoryItem' | translate}}</th>
<th scope="col">{{ 'notify-message-result.ldnService' | translate}}</th>
<th scope="col">{{ 'notify-message-result.type' | translate }}</th>
<th scope="col">{{ 'notify-message-result.status' | translate }}</th>
<th scope="col">{{ 'notify-message-result.action' | translate }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let message of (messagesSubject$ | async)">
<td>
<div>{{message.queueTimeout}}</div>
</td>
<td>
<div *ngIf="isInbound">{{message.context}}</div>
<div *ngIf="!isInbound">{{message.object}}</div>
</td>
<td>
<div *ngIf="isInbound">{{message.origin}}</div>
<div *ngIf="!isInbound">{{message.target}}</div>
</td>
<td>
<div>{{message.coarNotifyType}}</div>
</td>
<td>
<div>{{message.queueStatusLabel}}</div>
</td>
<td>
<div class="d-flex flex-column">
<button class="btn mb-2 btn-dark" (click)="openDetailModal(message)">{{ 'notify-message-result.detail' | translate }}</button>
<button *ngIf="message.queueStatusLabel === reprocessStatus" (click)="reprocessMessage(message)" class="btn btn-warning">
{{ 'notify-message-result.reprocess' | translate }}
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>

View File

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

View File

@@ -0,0 +1,122 @@
import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from '@angular/core';
import { AdminNotifySearchResult } from '../models/admin-notify-message-search-result.model';
import { ViewMode } from '../../../core/shared/view-mode.model';
import { Context } from '../../../core/shared/context.model';
import { AdminNotifyMessage, QueueStatusMap } from '../models/admin-notify-message.model';
import {
tabulatableObjectsComponent
} from '../../../shared/object-collection/shared/tabulatable-objects/tabulatable-objects.decorator';
import {
TabulatableResultListElementsComponent
} from '../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AdminNotifyDetailModalComponent } from '../admin-notify-detail-modal/admin-notify-detail-modal.component';
import { LdnServicesService } from "../../admin-ldn-services/ldn-services-data/ldn-services-data.service";
import { BehaviorSubject, from, Observable, of, scan, Subscription, switchMap } from "rxjs";
import { combineLatest, filter, map, mergeMap, tap } from "rxjs/operators";
import { getAllSucceededRemoteDataPayload } from "../../../core/shared/operators";
import { ItemDataService } from "../../../core/data/item-data.service";
import { AdminNotifyMessagesService } from "../services/admin-notify-messages.service";
import { SearchConfigurationService } from "../../../core/shared/search/search-configuration.service";
import { SEARCH_CONFIG_SERVICE } from "../../../my-dspace-page/my-dspace-page.component";
@tabulatableObjectsComponent(PaginatedList<AdminNotifySearchResult>, ViewMode.Table, Context.CoarNotify)
@Component({
selector: 'ds-admin-notify-search-result',
templateUrl: './admin-notify-search-result.component.html',
styleUrls: ['./admin-notify-search-result.component.scss'],
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
})
export class AdminNotifySearchResultComponent extends TabulatableResultListElementsComponent<PaginatedList<AdminNotifySearchResult>, AdminNotifySearchResult> implements OnInit, OnDestroy{
public messagesSubject$: BehaviorSubject<AdminNotifyMessage[]> = new BehaviorSubject([]);
public reprocessStatus = QueueStatusMap.QUEUE_STATUS_QUEUED_FOR_RETRY;
//we check on one type of config to render specific table headers
public isInbound: boolean;
/**
* Array to track all subscriptions and unsubscribe them onDestroy
* @type {Array}
*/
private subs: Subscription[] = [];
constructor(private modalService: NgbModal,
private adminNotifyMessagesService: AdminNotifyMessagesService,
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {
super();
}
/**
* Map messages on init for readable representation
*/
ngOnInit() {
this.mapDetailsToMessages()
this.subs.push(this.searchConfigService.getCurrentConfiguration('')
.subscribe(configuration => {
this.isInbound = configuration === 'NOTIFY.incoming';
})
);
}
ngOnDestroy() {
this.subs.forEach(sub => sub.unsubscribe());
}
/**
* Open modal for details visualization
* @param message the message to be displayed
*/
openDetailModal(message: AdminNotifyMessage) {
const modalRef = this.modalService.open(AdminNotifyDetailModalComponent);
const messageToOpen = {...message};
// we delete not necessary or not readable keys
if (this.isInbound) {
delete messageToOpen.target;
delete messageToOpen.object;
} else {
delete messageToOpen.context;
delete messageToOpen.origin;
}
delete messageToOpen._links;
delete messageToOpen.metadata;
delete messageToOpen.thumbnail;
delete messageToOpen.item;
delete messageToOpen.accessStatus;
delete messageToOpen.queueStatus;
const messageKeys = Object.keys(messageToOpen);
modalRef.componentInstance.notifyMessage = messageToOpen;
modalRef.componentInstance.notifyMessageKeys = messageKeys;
}
/**
* Reprocess message in status QUEUE_STATUS_QUEUED_FOR_RETRY and update results
* @param message the message to be reprocessed
*/
reprocessMessage(message: AdminNotifyMessage) {
this.subs.push(
this.adminNotifyMessagesService.reprocessMessage(message, this.messagesSubject$)
.subscribe(response => {
this.messagesSubject$.next(response)
}
)
)
}
/**
* Map readable results to messages
* @private
*/
private mapDetailsToMessages() {
this.subs.push(this.adminNotifyMessagesService.getDetailedMessages(this.objects?.page.map(pageResult => pageResult.indexableObject))
.subscribe(response => {
this.messagesSubject$.next(response)
}))
}
}

View File

@@ -1,40 +0,0 @@
<div class="table-responsive mt-2">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Timestamp</th>
<th scope="col">LDN Service</th>
<th scope="col">Repository Item</th>
<th scope="col">Type</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let message of (notifyMessages$ | async)">
<td>
<div>{{message.queueTimeout}}</div>
</td>
<td>
<div>{{message.origin}}</div>
</td>
<td>
<div>{{message.context}}</div>
</td>
<td>
<div>{{message.coarNotifyType}}</div>
</td>
<td>
<div>{{message.queueStatusLabel}}</div>
</td>
<td>
<div class="d-flex flex-column">
<button class="btn mb-2 btn-dark" (click)="openDetailModal(message)">Detail</button>
<button *ngIf="message.queueStatusLabel === reprocessStatus" (click)="reprocessMessage(message)" class="btn btn-warning">Reprocess</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>

View File

@@ -1,22 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyIncomingSearchResultComponent } from './admin-notify-incoming-search-result.component';
describe('AdminNotifySearchResultComponent', () => {
let component: AdminNotifyIncomingSearchResultComponent;
let fixture: ComponentFixture<AdminNotifyIncomingSearchResultComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminNotifyIncomingSearchResultComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(AdminNotifyIncomingSearchResultComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,97 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { AdminNotifySearchResult } from '../../models/admin-notify-message-search-result.model';
import { ViewMode } from '../../../../core/shared/view-mode.model';
import { Context } from '../../../../core/shared/context.model';
import { AdminNotifyMessage, QueueStatusMap } from '../../models/admin-notify-message.model';
import {
tabulatableObjectsComponent
} from '../../../../shared/object-collection/shared/tabulatable-objects/tabulatable-objects.decorator';
import {
TabulatableResultListElementsComponent
} from '../../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component';
import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AdminNotifyDetailModalComponent } from '../../admin-notify-detail-modal/admin-notify-detail-modal.component';
import { LdnServicesService } from "../../../admin-ldn-services/ldn-services-data/ldn-services-data.service";
import { BehaviorSubject, concatMap, from, Observable, of, scan, switchMap } from "rxjs";
import { RemoteData } from "../../../../core/data/remote-data";
import { LdnService } from "../../../admin-ldn-services/ldn-services-model/ldn-services.model";
import { filter, map, mergeMap, take, tap, toArray } from "rxjs/operators";
import { getAllSucceededRemoteDataPayload } from "../../../../core/shared/operators";
import { ItemDataService } from "../../../../core/data/item-data.service";
import { AdminNotifyMessagesService } from "../../services/admin-notify-messages.service";
@tabulatableObjectsComponent(PaginatedList<AdminNotifySearchResult>, ViewMode.Table, Context.CoarNotifyIncoming)
@Component({
selector: 'ds-admin-notify-search-result',
templateUrl: './admin-notify-incoming-search-result.component.html',
styleUrls: ['./admin-notify-incoming-search-result.component.scss']
})
export class AdminNotifyIncomingSearchResultComponent extends TabulatableResultListElementsComponent<PaginatedList<AdminNotifySearchResult>, AdminNotifySearchResult> implements OnInit{
public notifyMessages: AdminNotifyMessage[];
public notifyMessages$: Observable<AdminNotifyMessage[]>;
public reprocessStatus = QueueStatusMap.QUEUE_STATUS_QUEUED_FOR_RETRY;
constructor(private modalService: NgbModal,
private ldnServicesService: LdnServicesService,
private itemDataService: ItemDataService,
private adminNotifyMessagesService: AdminNotifyMessagesService) {
super();
}
/**
* Map messages on init for readable representation
*/
ngOnInit() {
this.notifyMessages = this.objects?.page.map(object => {
const indexableObject = object.indexableObject;
indexableObject.coarNotifyType = indexableObject.coarNotifyType.split(':')[1];
indexableObject.queueStatusLabel = QueueStatusMap[indexableObject.queueStatusLabel];
return indexableObject;
});
this.notifyMessages$ = from(this.notifyMessages).pipe(
mergeMap(message => of(message)),
mergeMap(message =>
message.origin ? this.ldnServicesService.findById(message.origin.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, origin: detail.name}))
) : of(message),
),
mergeMap(message =>
message.context ? this.itemDataService.findById(message.context.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, context: detail.name}))
) : of(message),
),
scan((acc: any, value: any) => [...acc, value], []),
)
}
/**
* Open modal for details visualization
* @param message the message to be displayed
*/
openDetailModal(message: AdminNotifyMessage) {
const modalRef = this.modalService.open(AdminNotifyDetailModalComponent);
const messageKeys = Object.keys(message);
const keysToRead = [];
messageKeys.forEach((key) => {
if (typeof message[key] !== 'object') {
keysToRead.push(key);
}
});
modalRef.componentInstance.notifyMessage = message;
modalRef.componentInstance.notifyMessageKeys = keysToRead;
}
/**
* Reprocess message in status QUEUE_STATUS_QUEUED_FOR_RETRY and update results
* @param message
*/
reprocessMessage(message: AdminNotifyMessage) {
// TODO implement reprocess
}
}

View File

@@ -1,39 +0,0 @@
<div class="table-responsive mt-2">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Timestamp</th>
<th scope="col">Repository Item</th>
<th scope="col">LDN Service</th>
<th scope="col">Type</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let message of (notifyMessages$ | async)">
<td>
<div>{{message.queueTimeout}}</div>
</td>
<td>
<div>{{message.object}}</div>
</td>
<td>
<div>{{message.target}}</div>
</td>
<td>
<div>{{message.coarNotifyType}}</div>
</td>
<td>
<div>{{message.queueStatusLabel}}</div>
</td>
<td>
<div class="d-flex flex-column">
<button class="btn mb-2 btn-dark" (click)="openDetailModal(message)">Detail</button>
<button *ngIf="message.queueStatusLabel === reprocessStatus" (click)="reprocessMessage(message)" class="btn btn-warning">Reprocess</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>

View File

@@ -1,22 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyOutgoingSearchResultComponent } from './admin-notify-outgoing-search-result.component';
describe('AdminNotifySearchResultComponent', () => {
let component: AdminNotifyOutgoingSearchResultComponent;
let fixture: ComponentFixture<AdminNotifyOutgoingSearchResultComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AdminNotifyOutgoingSearchResultComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(AdminNotifyOutgoingSearchResultComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,98 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { AdminNotifySearchResult } from '../../models/admin-notify-message-search-result.model';
import { ViewMode } from '../../../../core/shared/view-mode.model';
import { Context } from '../../../../core/shared/context.model';
import { AdminNotifyMessage, QueueStatusMap } from '../../models/admin-notify-message.model';
import {
tabulatableObjectsComponent
} from '../../../../shared/object-collection/shared/tabulatable-objects/tabulatable-objects.decorator';
import {
TabulatableResultListElementsComponent
} from '../../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component';
import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AdminNotifyDetailModalComponent } from '../../admin-notify-detail-modal/admin-notify-detail-modal.component';
import { LdnServicesService } from "../../../admin-ldn-services/ldn-services-data/ldn-services-data.service";
import { from, Observable, of, scan, switchMap } from "rxjs";
import { combineLatest, filter, map, mergeMap } from "rxjs/operators";
import { getAllSucceededRemoteDataPayload } from "../../../../core/shared/operators";
import { ItemDataService } from "../../../../core/data/item-data.service";
import { AdminNotifyMessagesService } from "../../services/admin-notify-messages.service";
@tabulatableObjectsComponent(PaginatedList<AdminNotifySearchResult>, ViewMode.Table, Context.CoarNotifyOutgoing)
@Component({
selector: 'ds-admin-notify-search-result',
templateUrl: './admin-notify-outgoing-search-result.component.html',
styleUrls: ['./admin-notify-outgoing-search-result.component.scss']
})
export class AdminNotifyOutgoingSearchResultComponent extends TabulatableResultListElementsComponent<PaginatedList<AdminNotifySearchResult>, AdminNotifySearchResult> implements OnInit{
public notifyMessages: AdminNotifyMessage[];
public notifyMessages$: Observable<AdminNotifyMessage[]>;
public reprocessStatus = QueueStatusMap.QUEUE_STATUS_QUEUED_FOR_RETRY;
constructor(private modalService: NgbModal,
private ldnServicesService: LdnServicesService,
private itemDataService: ItemDataService,
private adminNotifyMessagesService: AdminNotifyMessagesService) {
super();
}
/**
* Map messages on init for readable representation
*/
ngOnInit() {
this.mapDetailsToMessages()
}
/**
* Open modal for details visualization
* @param message the message to be displayed
*/
openDetailModal(message: AdminNotifyMessage) {
const modalRef = this.modalService.open(AdminNotifyDetailModalComponent);
const messageKeys = Object.keys(message);
modalRef.componentInstance.notifyMessage = message;
modalRef.componentInstance.notifyMessageKeys = messageKeys;
}
/**
* Reprocess message in status QUEUE_STATUS_QUEUED_FOR_RETRY and update results
* @param message
*/
reprocessMessage(message: AdminNotifyMessage) {
this.adminNotifyMessagesService.findById(message.id).pipe(getAllSucceededRemoteDataPayload()).subscribe(response => {
console.log(response);
})
}
/**
* Map readable results to messages
* @private
*/
private mapDetailsToMessages() {
this.notifyMessages = this.objects?.page.map(object => {
const indexableObject = object.indexableObject;
indexableObject.coarNotifyType = indexableObject.coarNotifyType.split(':')[1];
indexableObject.queueStatusLabel = QueueStatusMap[indexableObject.queueStatusLabel];
return indexableObject;
});
this.notifyMessages$ = from(this.notifyMessages).pipe(
mergeMap(message => of(message)),
mergeMap(message =>
message.target ? this.ldnServicesService.findById(message.target.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, target: detail.name}))
) : of(message),
),
mergeMap(message =>
message.object ? this.itemDataService.findById(message.object.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, object: detail.name}))
) : of(message),
),
scan((acc: any, value: any) => [...acc, value], []),
)
}
}

View File

@@ -1,10 +1,11 @@
import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
import { autoserialize, autoserializeAs, deserialize, inheritSerialization } from 'cerialize';
import { typedObject } from '../../../core/cache/builders/build-decorators';
import { ADMIN_NOTIFY_MESSAGE } from './admin-notify-message.resource-type';
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
import { GenericConstructor } from '../../../core/shared/generic-constructor';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { Observable } from "rxjs";
export enum QueueStatusMap {
QUEUE_STATUS_PROCESSED = 'Processed',
@@ -107,6 +108,25 @@ export class AdminNotifyMessage extends DSpaceObject {
@autoserialize
queueStatus: number;
/**
* Thumbnail link used when browsing items with showThumbs config enabled.
*/
@autoserialize
thumbnail: string;
/**
* The observable pointing to the item itself
*/
@autoserialize
item: Observable<AdminNotifyMessage>;
/**
* The observable pointing to the access status of the item
*/
@autoserialize
accessStatus: Observable<AdminNotifyMessage>;
@deserialize
_links: {

View File

@@ -10,7 +10,7 @@ import {HALEndpointService} from '../../../core/shared/hal-endpoint.service';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import {FindListOptions} from '../../../core/data/find-list-options.model';
import {FollowLinkConfig} from '../../../shared/utils/follow-link-config.model';
import {Observable} from 'rxjs';
import { BehaviorSubject, from, Observable, of, scan } from 'rxjs';
import {RemoteData} from '../../../core/data/remote-data';
import {PaginatedList} from '../../../core/data/paginated-list.model';
import {NoContent} from '../../../core/shared/NoContent.model';
@@ -21,7 +21,13 @@ import {RestRequestMethod} from '../../../core/data/rest-request-method';
import {CreateData, CreateDataImpl} from '../../../core/data/base/create-data';
import {SearchDataImpl} from '../../../core/data/base/search-data';
import { ADMIN_NOTIFY_MESSAGE } from "../models/admin-notify-message.resource-type";
import { AdminNotifyMessage } from "../models/admin-notify-message.model";
import { AdminNotifyMessage, QueueStatusMap } from "../models/admin-notify-message.model";
import { SearchResult } from "../../../shared/search/models/search-result.model";
import { map, mergeMap } from "rxjs/operators";
import { getAllSucceededRemoteDataPayload } from "../../../core/shared/operators";
import { AdminNotifySearchResult } from "../models/admin-notify-message-search-result.model";
import { LdnServicesService } from "../../admin-ldn-services/ldn-services-data/ldn-services-data.service";
import { ItemDataService } from "../../../core/data/item-data.service";
/**
* Injectable service responsible for fetching/sending data from/to the REST API on the messages endpoint.
@@ -39,7 +45,77 @@ export class AdminNotifyMessagesService extends IdentifiableDataService<AdminNot
protected objectCache: ObjectCacheService,
protected halService: HALEndpointService,
protected notificationsService: NotificationsService,
private ldnServicesService: LdnServicesService,
private itemDataService: ItemDataService,
) {
super('messages', requestService, rdbService, objectCache, halService);
}
/**
* Map labels to readable info for user
* @param message the message to which map the labels
*/
public formatMessageLabels(message: AdminNotifyMessage) : AdminNotifyMessage {
message.coarNotifyType = message.coarNotifyType?.split(':')[1];
message.queueStatusLabel = QueueStatusMap[message.queueStatusLabel];
return message;
}
/**
* Add detailed information to each message
* @param messages the messages to which add detailded info
*/
public getDetailedMessages(messages: AdminNotifyMessage[]) : Observable<AdminNotifyMessage[]> {
return from(messages.map(message => this.formatMessageLabels(message))).pipe(
mergeMap(message =>
message.target ? this.ldnServicesService.findById(message.target.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, target: detail.name}))
) : of(message),
),
mergeMap(message =>
message.object ? this.itemDataService.findById(message.object.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, object: detail.name}))
) : of(message),
),
mergeMap(message =>
message.origin ? this.ldnServicesService.findById(message.origin.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, origin: detail.name}))
) : of(message),
),
mergeMap(message =>
message.context ? this.itemDataService.findById(message.context.toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, context: detail.name}))
) : of(message),
),
scan((acc: any, value: any) => [...acc, value], []),
)
}
/**
* Reprocess message in status QUEUE_STATUS_QUEUED_FOR_RETRY and update results
* @param message the message to reprocess
* @param messageSubject the current visualised messages source
*/
public reprocessMessage(message: AdminNotifyMessage, messageSubject: BehaviorSubject<AdminNotifyMessage[]>) : Observable<AdminNotifyMessage[]> {
return this.findById(message.id).pipe(
getAllSucceededRemoteDataPayload(),
map(reprocessedMessage => this.formatMessageLabels(reprocessedMessage)),
mergeMap((newMessage) => messageSubject.pipe(
map(messages => {
const messageToUpdate = messages.find(currentMessage => currentMessage.id === message.id);
const indexOfMessageToUpdate = messages.indexOf(messageToUpdate);
newMessage.target = messageToUpdate.target;
newMessage.object = messageToUpdate.object;
newMessage.origin = messageToUpdate.origin;
newMessage.context = messageToUpdate.context;
messages[indexOfMessageToUpdate] = newMessage;
return messages
})
)),
)
}
}

View File

@@ -40,6 +40,5 @@ export enum Context {
Bitstream = 'bitstream',
CoarNotifyIncoming = 'coarNotifyIncoming',
CoarNotifyOutgoing = 'coarNotifyOutgoing',
CoarNotify = 'coarNotify',
}

View File

@@ -3529,7 +3529,51 @@
"sorting.queue_attempts.ASC": "Queue attempted Ascending",
"orgunit.listelement.badge": "Organizational Unit",
"type.notify-detail-modal": "Type",
"id.notify-detail-modal": "Id",
"coarNotifyType.notify-detail-modal": "Coar Notify type",
"activityStreamType.notify-detail-modal": "Activity stream type",
"inReplyTo.notify-detail-modal": "In reply to",
"object.notify-detail-modal": "Repository Item",
"context.notify-detail-modal": "Repository Item",
"queueAttempts.notify-detail-modal": "Queue attempts",
"queueLastStartTime.notify-detail-modal": "Queue last started",
"origin.notify-detail-modal": "LDN Service",
"target.notify-detail-modal": "LDN Service",
"queueStatusLabel.notify-detail-modal": "Queue status",
"queueTimeout.notify-detail-modal": "Queue timeout",
"notify-message-modal.title": "Message Detail",
"notify-message-result.timestamp": "Timestamp",
"notify-message-result.repositoryItem": "Repository Item",
"notify-message-result.ldnService": "LDN Service",
"notify-message-result.type": "Type",
"notify-message-result.status": "Status",
"notify-message-result.action": "Action",
"notify-message-result.detail": "Detail",
"notify-message-result.reprocess": "Reprocess",
"orgunit.listelement.badge": "Repository Item",
"orgunit.listelement.no-title": "Untitled",