[CST-12709] partial implementation with mock data

This commit is contained in:
Alisa Ismailati
2023-11-21 18:38:49 +01:00
parent 596cd6f7e3
commit 442426bb2e
15 changed files with 434 additions and 4 deletions

View File

@@ -195,6 +195,9 @@ import {
CoarNotifyConfigDataService
} from '../submission/sections/section-coar-notify/coar-notify-config-data.service';
import { SubmissionCoarNotifyConfig } from '../submission/sections/section-coar-notify/submission-coar-notify.config';
import { NotifyRequestsStatus } from '../item-page/simple/notify-requests-status/notify-requests-status.model';
import { NotifyRequestsStatusDataService } from './data/notify-services-status-data.service';
/**
* When not in production, endpoint responses can be mocked for testing purposes
@@ -320,7 +323,8 @@ const PROVIDERS = [
SupervisionOrderDataService,
LdnServicesService,
LdnItemfiltersService,
CoarNotifyConfigDataService
CoarNotifyConfigDataService,
NotifyRequestsStatusDataService
];
/**
@@ -404,8 +408,8 @@ export const models =
SuggestionSource,
LdnService,
Itemfilter,
SubmissionCoarNotifyConfig
SubmissionCoarNotifyConfig,
NotifyRequestsStatus,
];
@NgModule({

View File

@@ -0,0 +1,49 @@
import { Injectable } from '@angular/core';
import { RequestService } from './request.service';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../cache/object-cache.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { IdentifiableDataService } from './base/identifiable-data.service';
import { dataService } from './base/data-service.decorator';
import { NotifyRequestsStatus } from '../../item-page/simple/notify-requests-status/notify-requests-status.model';
import { NOTIFYREQUEST} from '../../item-page/simple/notify-requests-status/notify-requests-status.resource-type';
import { Observable, map, take, tap } from 'rxjs';
import { RemoteData } from './remote-data';
import { GetRequest } from './request.models';
@Injectable()
@dataService(NOTIFYREQUEST)
export class NotifyRequestsStatusDataService extends IdentifiableDataService<NotifyRequestsStatus> {
private notifyRequestLink = 'notifyrequests';
constructor(
protected requestService: RequestService,
protected rdbService: RemoteDataBuildService,
protected objectCache: ObjectCacheService,
protected halService: HALEndpointService,
protected rdb: RemoteDataBuildService,
) {
super('ldn', requestService, rdbService, objectCache, halService);
}
/**
* Retrieves the status of notify requests for a specific item.
* @param itemUuid The UUID of the item.
* @returns An Observable that emits the remote data containing the notify requests status.
*/
getNotifyRequestsStatus(itemUuid: string): Observable<RemoteData<NotifyRequestsStatus>> {
const href$ = this.halService.getEndpoint(this.notifyRequestLink).pipe(
tap((url: string) => console.log('url', url) ),
map((url: string) => url + '/' + itemUuid),
);
href$.pipe(take(1)).subscribe((url: string) => {
const request = new GetRequest(this.requestService.generateRequestId(), url);
this.requestService.send(request, true);
});
return this.rdb.buildFromHref(href$);
}
}

View File

@@ -61,6 +61,8 @@ import {
ThemedFullFileSectionComponent
} from './full/field-components/file-section/themed-full-file-section.component';
import { QaEventNotificationComponent } from './simple/qa-event-notification/qa-event-notification.component';
import { NotifyRequestsStatusComponent } from './simple/notify-requests-status/notify-requests-status-component/notify-requests-status.component';
import { RequestStatusAlertBoxComponent } from './simple/notify-requests-status/request-status-alert-box/request-status-alert-box.component';
const ENTRY_COMPONENTS = [
// put only entry components that use custom decorator
@@ -104,7 +106,9 @@ const DECLARATIONS = [
ItemAlertsComponent,
ThemedItemAlertsComponent,
BitstreamRequestACopyPageComponent,
QaEventNotificationComponent
QaEventNotificationComponent,
NotifyRequestsStatusComponent,
RequestStatusAlertBoxComponent
];
@NgModule({

View File

@@ -3,6 +3,7 @@
<div *ngIf="itemRD?.payload as item">
<ds-themed-item-alerts [item]="item"></ds-themed-item-alerts>
<ds-qa-event-notification [item]="item"></ds-qa-event-notification>
<ds-notify-requests-status [itemUuid]="item.uuid"></ds-notify-requests-status>
<ds-item-versions-notice [item]="item"></ds-item-versions-notice>
<ds-view-tracker [object]="item"></ds-view-tracker>
<ds-listable-object-component-loader *ngIf="!item.isWithdrawn || (isAdmin$|async)" [object]="item" [viewMode]="viewMode"></ds-listable-object-component-loader>

View File

@@ -0,0 +1,5 @@
<ng-container *ngIf="statusMap.size > 0">
<ng-container *ngFor="let entry of statusMap | keyvalue ">
<ds-request-status-alert-box [status]="entry.key" [data]="entry.value"></ds-request-status-alert-box>
</ng-container>
</ng-container>

View File

@@ -0,0 +1,108 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { Observable, of } from 'rxjs';
import { NotifyRequestsStatus, NotifyStatuses } from '../notify-requests-status.model';
import { NotifyRequestsStatusDataService } from 'src/app/core/data/notify-services-status-data.service';
import { RequestStatusEnum } from '../notify-status.enum';
@Component({
selector: 'ds-notify-requests-status',
templateUrl: './notify-requests-status.component.html',
styleUrls: ['./notify-requests-status.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NotifyRequestsStatusComponent {
/**
* The UUID of the item.
*/
@Input() itemUuid: string;
/**
* Map that stores the status of requests and their corresponding notify statuses.
* The keys of the map are instances of the RequestStatusEnum enum,
* and the values are arrays of NotifyStatuses objects.
*/
statusMap: Map<RequestStatusEnum, NotifyStatuses[]> = new Map();
notifyRequestStatus$: Observable<NotifyRequestsStatus> = of( Object.assign(new NotifyRequestsStatus(), {
notifyStatuses: [
{
serviceName: 'test',
serviceUrl: 'test',
status: RequestStatusEnum.ACCEPTED,
},
{
serviceName: 'test1',
serviceUrl: 'test',
status: RequestStatusEnum.ACCEPTED,
},
{
serviceName: 'Review Platform',
serviceUrl: 'test',
status: RequestStatusEnum.ACCEPTED,
},
{
serviceName: 'Demo Environment',
serviceUrl: 'test',
status: RequestStatusEnum.ACCEPTED,
},
{
serviceName: 'Additional Information',
serviceUrl: 'test',
status: RequestStatusEnum.ACCEPTED,
},
{
serviceName: 'Notification Service',
serviceUrl: 'test',
status: RequestStatusEnum.ACCEPTED,
},
{
serviceName: 'test2',
serviceUrl: 'test',
status: RequestStatusEnum.REJECTED,
},
{
serviceName: 'test3',
serviceUrl: 'test',
status: RequestStatusEnum.REQUESTED,
},
{
serviceName: 'test4',
serviceUrl: 'test',
status: RequestStatusEnum.REQUESTED,
}
],
itemUuid: '8d5fda2d-f380-467e-a86b-0436ac699dab',
}));
constructor(
private notifyInfoService: NotifyRequestsStatusDataService,
) { }
ngOnInit(): void {
this.notifyInfoService.getNotifyRequestsStatus(this.itemUuid).subscribe((data) => {
console.log(data, 'asdasdsa');
});
this.notifyRequestStatus$.subscribe((data) => {
this.groupDataByStatus(data);
console.log(this.statusMap);
});
}
/**
* Groups the notify requests status data by status.
* @param notifyRequestsStatus The notify requests status data.
*/
private groupDataByStatus(notifyRequestsStatus: NotifyRequestsStatus): void {
notifyRequestsStatus.notifyStatuses.forEach((notifyStatus: NotifyStatuses) => {
const status = notifyStatus.status;
if (!this.statusMap.has(status)) {
this.statusMap.set(status, []);
}
this.statusMap.get(status)?.push(notifyStatus);
});
}
}

View File

@@ -0,0 +1,68 @@
// eslint-disable-next-line max-classes-per-file
import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
import { typedObject } from '../../../core/cache/builders/build-decorators';
import { CacheableObject } from '../../../core/cache/cacheable-object.model';
import { ResourceType } from '../../../core/shared/resource-type';
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
import { NOTIFYREQUEST } from './notify-requests-status.resource-type';
import { HALLink } from '../../../core/shared/hal-link.model';
import { RequestStatusEnum } from './notify-status.enum';
/**
* Represents the status of notify requests for an item.
*/
@typedObject
@inheritSerialization(CacheableObject)
export class NotifyRequestsStatus implements CacheableObject {
static type = NOTIFYREQUEST;
/**
* The object type.
*/
@excludeFromEquals
@autoserialize
type: ResourceType;
/**
* The notify statuses.
*/
@autoserialize
notifyStatuses: NotifyStatuses[];
/**
* The UUID of the item.
*/
@autoserialize
itemUuid: string;
/**
* The links associated with the notify requests status.
*/
@deserialize
_links: {
self: HALLink;
[k: string]: HALLink | HALLink[];
};
}
/**
* Represents the status of a notification request.
*/
export class NotifyStatuses {
/**
* The name of the service.
*/
serviceName: string;
/**
* The URL of the service.
*/
serviceUrl: string;
/**
* The status of the notification request.
*/
status: RequestStatusEnum;
}

View File

@@ -0,0 +1,8 @@
import {ResourceType} from '../../../core/shared/resource-type';
/**
* The resource type for the root endpoint
*
* Needs to be in a separate file to prevent circular
* dependencies in webpack.
*/
export const NOTIFYREQUEST = new ResourceType('notifyrequest');

View File

@@ -0,0 +1,5 @@
export enum RequestStatusEnum {
ACCEPTED = 'ACCEPTED',
REJECTED = 'REJECTED',
REQUESTED = 'REQUESTED',
}

View File

@@ -0,0 +1,32 @@
<ng-container *ngIf="data?.length > 0 && displayOptions">
<div
[ngClass]="{'align-items-center': data.length == 1}"
class="alert d-flex flex-row sections-gap {{
displayOptions.alertType
}}"
>
<img
class="source-logo"
src="assets/images/qa-coar-notify-logo.png"
alt="notify logo"
/>
<ds-truncatable [id]="status">
<ds-truncatable-part [id]="status" [minLines]="1">
<div class="w-100 d-flex flex-column">
<ng-container *ngFor="let request of data">
<div
[innerHTML]="
displayOptions.text
| translate
: {
serviceName: request.serviceName,
serviceUrl: request.serviceUrl
}
"
></div>
</ng-container>
</div>
</ds-truncatable-part>
</ds-truncatable>
</div>
</ng-container>

View File

@@ -0,0 +1,7 @@
.source-logo {
max-height: var(--ds-header-logo-height);
}
.sections-gap {
gap: 1rem;
}

View File

@@ -0,0 +1,51 @@
import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing';
import { RequestStatusAlertBoxComponent } from './request-status-alert-box.component';
import { TranslateModule } from '@ngx-translate/core';
import { RequestStatusEnum } from '../notify-status.enum';
describe('RequestStatusAlertBoxComponent', () => {
let component: RequestStatusAlertBoxComponent;
let componentAsAny: any;
let fixture: ComponentFixture<RequestStatusAlertBoxComponent>;
const mockData = [
{
serviceName: 'test',
serviceUrl: 'test',
status: RequestStatusEnum.ACCEPTED,
},
{
serviceName: 'test1',
serviceUrl: 'test',
status: RequestStatusEnum.REJECTED,
},
];
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [RequestStatusAlertBoxComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(RequestStatusAlertBoxComponent);
component = fixture.componentInstance;
component.data = mockData;
component.displayOptions = {
alertType: 'alert-danger',
text: 'request-status-alert-box.rejected',
};
componentAsAny = component;
fixture.detectChanges();
});
it('should create the component', () => {
expect(component).toBeTruthy();
});
it('should display the alert box when data is available', fakeAsync(() => {
const alertBoxElement = fixture.nativeElement.querySelector('.alert');
expect(alertBoxElement).toBeTruthy();
}));
});

View File

@@ -0,0 +1,82 @@
import {
ChangeDetectionStrategy,
Component,
Input,
type OnInit,
} from '@angular/core';
import { NotifyStatuses } from '../notify-requests-status.model';
import { RequestStatusEnum } from '../notify-status.enum';
@Component({
selector: 'ds-request-status-alert-box',
templateUrl: './request-status-alert-box.component.html',
styleUrls: ['./request-status-alert-box.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
/**
* Represents a component that displays the status of a request.
*/
export class RequestStatusAlertBoxComponent implements OnInit {
/**
* The status of the request.
*/
@Input() status: RequestStatusEnum;
/**
* The input data for the request status alert box component.
* @type {NotifyStatuses[]}
*/
@Input() data: NotifyStatuses[] = [];
/**
* The display options for the request status alert box.
*/
displayOptions: NotifyRequestDisplayOptions;
ngOnInit(): void {
this.prepareDataToDisplay();
}
/**
* Prepares the data to be displayed based on the current status.
*/
private prepareDataToDisplay() {
switch (this.status) {
case RequestStatusEnum.ACCEPTED:
this.displayOptions = {
alertType: 'alert-info',
text: 'request-status-alert-box.accepted',
};
break;
case RequestStatusEnum.REJECTED:
this.displayOptions = {
alertType: 'alert-danger',
text: 'request-status-alert-box.rejected',
};
break;
case RequestStatusEnum.REQUESTED:
this.displayOptions = {
alertType: 'alert-warning',
text: 'request-status-alert-box.requested',
};
break;
}
}
}
/**
* Represents the display options for a notification request.
*/
export interface NotifyRequestDisplayOptions {
/**
* The type of alert to display.
* Possible values are 'alert-danger', 'alert-warning', or 'alert-info'.
*/
alertType: 'alert-danger' | 'alert-warning' | 'alert-info';
/**
* The text to display in the notification.
*/
text: string;
}

View File

@@ -5697,4 +5697,10 @@
"access-control-option-end-date-note": "Select the date until which the related access condition is applied",
"request-status-alert-box.accepted": "The request for <a href='{{serviceUrl}}' target='_blank'> {{ serviceName }} </a> has been taken in charge.",
"request-status-alert-box.rejected": "The request for <a href='{{serviceUrl}}' target='_blank'> {{ serviceName }} </a> has been rejected.",
"request-status-alert-box.requested": "The request for <a href='{{serviceUrl}}' target='_blank'> {{ serviceName }} </a> is pending.",
}