mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-10 11:33:04 +00:00
[CST-12109] qa-event notification box fixes
This commit is contained in:
@@ -56,6 +56,21 @@ import {
|
||||
showBreadcrumbsFluid: false
|
||||
}
|
||||
},
|
||||
{
|
||||
canActivate: [ AuthenticatedGuard ],
|
||||
path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId/target/:targetId`,
|
||||
component: AdminQualityAssuranceTopicsPageComponent,
|
||||
pathMatch: 'full',
|
||||
resolve: {
|
||||
breadcrumb: I18nBreadcrumbResolver,
|
||||
openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver
|
||||
},
|
||||
data: {
|
||||
title: 'admin.quality-assurance.page.title',
|
||||
breadcrumbKey: 'admin.quality-assurance',
|
||||
showBreadcrumbsFluid: false
|
||||
}
|
||||
},
|
||||
{
|
||||
canActivate: [ SiteAdministratorGuard ],
|
||||
path: `${QUALITY_ASSURANCE_EDIT_PATH}`,
|
||||
|
@@ -2,9 +2,21 @@
|
||||
<ng-container *ngFor="let source of sources">
|
||||
<div class="alert alert-info d-flex flex-row" *ngIf="source.totalEvents > 0">
|
||||
<div class="w-100 d-flex justify-content-between">
|
||||
<div class="pl-4 align-self-center">{{ this.item.isArchived ? ('qa-event-notification.check.notification-withdrawn' | translate)
|
||||
: ('qa-event-notification.check.notification-reinstate' | translate) }} </div>
|
||||
<button [routerLink]="[ getQualityAssuranceRoute(), (source.id | dsSplit: ':')[0]]"
|
||||
<div class="pl-4 align-self-center">
|
||||
<ng-container *ngIf="this.item.isArchived; else reinstate">
|
||||
<span>
|
||||
{{
|
||||
(isAdmin$ | async) ? ('qa-event-notification.check.notification-withdrawn.admin' | translate : { source: (source.id | dsSplit: ':')[0], num: source.totalEvents })
|
||||
: ('qa-event-notification.check.notification-withdrawn.user' | translate : { num: source.totalEvents })
|
||||
}}
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-template #reinstate>
|
||||
{{ 'qa-event-notification.check.notification-reinstate' | translate: { num: source.totalEvents } }}
|
||||
</ng-template>
|
||||
</div>
|
||||
<button [routerLink]="[ getQualityAssuranceRoute(), (source.id | dsSplit: ':')[0], 'target', item.id]"
|
||||
[queryParams]="{ forward: true }"
|
||||
class="btn btn-primary align-self-center">{{ this.item.isArchived ? ('qa-event-notification-undo-withdrawn.check.button' | translate)
|
||||
: ('qa-event-notification-undo-reinstate.check.button' | translate) }}</button>
|
||||
</div>
|
||||
|
@@ -1,35 +1,55 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { QaEventNotificationComponent } from './qa-event-notification.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from 'src/app/shared/remote-data.utils';
|
||||
import { createPaginatedList } from 'src/app/shared/testing/utils.test';
|
||||
import { QualityAssuranceSourceObject } from 'src/app/core/notifications/qa/models/quality-assurance-source.model';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { createPaginatedList } from '../../../shared/testing/utils.test';
|
||||
import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { QualityAssuranceSourceDataService } from 'src/app/core/notifications/qa/source/quality-assurance-source-data.service';
|
||||
import { RequestService } from 'src/app/core/data/request.service';
|
||||
import { NotificationsService } from 'src/app/shared/notifications/notifications.service';
|
||||
import { ObjectCacheService } from 'src/app/core/cache/object-cache.service';
|
||||
import { RemoteDataBuildService } from 'src/app/core/cache/builders/remote-data-build.service';
|
||||
import { QualityAssuranceSourceDataService } from '../../../core/notifications/qa/source/quality-assurance-source-data.service';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
||||
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { HALEndpointService } from 'src/app/core/shared/hal-endpoint.service';
|
||||
import { HALEndpointServiceStub } from 'src/app/shared/testing/hal-endpoint-service.stub';
|
||||
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
||||
import { HALEndpointServiceStub } from '../../../shared/testing/hal-endpoint-service.stub';
|
||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||
import { of } from 'rxjs';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { SplitPipe } from 'src/app/shared/utils/split.pipe';
|
||||
|
||||
describe('QaEventNotificationComponent', () => {
|
||||
let component: QaEventNotificationComponent;
|
||||
let fixture: ComponentFixture<QaEventNotificationComponent>;
|
||||
let qualityAssuranceSourceDataServiceStub: any;
|
||||
let authorizationService: AuthorizationDataService;
|
||||
|
||||
const obj = createSuccessfulRemoteDataObject$(createPaginatedList([new QualityAssuranceSourceObject()]));
|
||||
const obj = Object.assign(new QualityAssuranceSourceObject(), {
|
||||
id: 'sourceName:target',
|
||||
source: 'sourceName',
|
||||
target: 'target',
|
||||
totalEvents: 1
|
||||
});
|
||||
|
||||
const objPL = createSuccessfulRemoteDataObject$(createPaginatedList([obj]));
|
||||
const item = Object.assign({ uuid: '1234' });
|
||||
beforeEach(async () => {
|
||||
authorizationService = jasmine.createSpyObj('authorizationService', {
|
||||
isAuthorized: of(true)
|
||||
});
|
||||
|
||||
qualityAssuranceSourceDataServiceStub = {
|
||||
getSourcesByTarget: () => objPL
|
||||
};
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CommonModule, TranslateModule.forRoot()],
|
||||
declarations: [ QaEventNotificationComponent ],
|
||||
declarations: [QaEventNotificationComponent, SplitPipe],
|
||||
providers: [
|
||||
{ provide: QualityAssuranceSourceDataService, useValue: qualityAssuranceSourceDataServiceStub },
|
||||
{ provide: RequestService, useValue: {} },
|
||||
{ provide: NotificationsService, useValue: {} },
|
||||
{ provide: HALEndpointService, useValue: new HALEndpointServiceStub('test')},
|
||||
{ provide: HALEndpointService, useValue: new HALEndpointServiceStub('test') },
|
||||
{ provide: AuthorizationDataService, useValue: authorizationService },
|
||||
ObjectCacheService,
|
||||
RemoteDataBuildService,
|
||||
provideMockStore({})
|
||||
@@ -39,9 +59,21 @@ describe('QaEventNotificationComponent', () => {
|
||||
fixture = TestBed.createComponent(QaEventNotificationComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.item = item;
|
||||
component.sources$ = of([obj]);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should display sources if present', () => {
|
||||
const alertElements = fixture.debugElement.queryAll(By.css('.alert'));
|
||||
expect(alertElements.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should return the quality assurance route when getQualityAssuranceRoute is called', () => {
|
||||
const route = component.getQualityAssuranceRoute();
|
||||
expect(route).toBe('/notifications/quality-assurance');
|
||||
});
|
||||
});
|
||||
|
@@ -6,10 +6,12 @@ import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||
import { RequestParam } from '../../../core/cache/models/request-param.model';
|
||||
import { QualityAssuranceSourceDataService } from '../../../core/notifications/qa/source/quality-assurance-source-data.service';
|
||||
import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { getNotificatioQualityAssuranceRoute } from '../../../admin/admin-routing-paths';
|
||||
import { PaginatedList } from 'src/app/core/data/paginated-list.model';
|
||||
import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service';
|
||||
import { FeatureID } from 'src/app/core/data/feature-authorization/feature-id';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-qa-event-notification',
|
||||
@@ -32,11 +34,16 @@ export class QaEventNotificationComponent implements OnChanges {
|
||||
*/
|
||||
sources$: Observable<QualityAssuranceSourceObject[]>;
|
||||
/**
|
||||
* The type of alert to display for the notification.
|
||||
* An observable that emits a boolean representing whether the current user is an admin.
|
||||
*/
|
||||
isAdmin$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private qualityAssuranceSourceDataService: QualityAssuranceSourceDataService,
|
||||
) { }
|
||||
private authService: AuthorizationDataService,
|
||||
) {
|
||||
this.isAdmin$ = this.authService.isAuthorized(FeatureID.AdministratorOf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect changes to the item input and update the sources$ observable.
|
||||
@@ -63,7 +70,8 @@ export class QaEventNotificationComponent implements OnChanges {
|
||||
return data.payload.page;
|
||||
}
|
||||
return [];
|
||||
})
|
||||
}),
|
||||
catchError(() => [])
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -196,14 +196,6 @@
|
||||
</ds-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-right">
|
||||
<div class="col-md-12">
|
||||
<a class="btn btn-outline-secondary" [routerLink]="['/notifications/quality-assurance', sourceId]">
|
||||
<i class="fas fa-angle-double-left"></i>
|
||||
{{'quality-assurance.events.back' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #acceptModal let-modal>
|
||||
|
@@ -33,7 +33,7 @@ import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
|
||||
import { NoContent } from '../../../core/shared/NoContent.model';
|
||||
import {environment} from '../../../../environments/environment';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
/**
|
||||
* Component to display the Quality Assurance event list.
|
||||
@@ -119,6 +119,9 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
|
||||
/**
|
||||
* Observable that emits a boolean value indicating whether the user is an admin.
|
||||
*/
|
||||
isAdmin$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
@@ -146,9 +149,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.isEventPageLoading.next(true);
|
||||
|
||||
this.isAdmin$ = this.authorizationService.isAuthorized(FeatureID.AdministratorOf);
|
||||
// this.sourceId = this.activatedRoute.snapshot.params.sourceId;
|
||||
this.activatedRoute.paramMap.pipe(
|
||||
tap((params) => {
|
||||
this.sourceUrlForProjectSearch = environment.qualityAssuranceConfig.sourceUrlMapForProjectSearch[params.get('sourceId')];
|
||||
@@ -462,6 +463,11 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a quality assurance event.
|
||||
* @param qaEvent The quality assurance event to delete.
|
||||
* @returns An Observable of RemoteData containing NoContent.
|
||||
*/
|
||||
delete(qaEvent: QualityAssuranceEventData): Observable<RemoteData<NoContent>> {
|
||||
return this.qualityAssuranceEventRestService.deleteQAEvent(qaEvent);
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@
|
||||
<button
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
title="{{'quality-assurance.topics-list.button.detail' | translate : { param: topicElement.name } }}"
|
||||
[routerLink]="[topicElement.id]">
|
||||
[routerLink]="[getQualityAssuranceRoute(), sourceId, topicElement.id]">
|
||||
<span class="badge badge-info">{{topicElement.totalEvents}}</span>
|
||||
<i class="fas fa-info fa-fw"></i>
|
||||
</button>
|
||||
@@ -58,12 +58,4 @@
|
||||
</ds-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-right">
|
||||
<div class="col-md-12">
|
||||
<a class="btn btn-outline-secondary" [routerLink]="['/notifications/quality-assurance']">
|
||||
<i class="fas fa-angle-double-left"></i>
|
||||
{{'quality-assurance.events.back-to-sources' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -14,7 +14,7 @@ import {
|
||||
AdminQualityAssuranceTopicsPageParams
|
||||
} from '../../../admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service';
|
||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ItemDataService } from '../../../core/data/item-data.service';
|
||||
import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../../../core/shared/operators';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
@@ -87,6 +87,7 @@ export class QualityAssuranceTopicsComponent implements OnInit, OnDestroy, After
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private itemService: ItemDataService,
|
||||
private notificationsStateService: NotificationsStateService,
|
||||
private router: Router,
|
||||
) {
|
||||
this.sourceId = this.activatedRoute.snapshot.params.sourceId;
|
||||
this.targetId = this.activatedRoute.snapshot.params.targetId;
|
||||
@@ -96,7 +97,15 @@ export class QualityAssuranceTopicsComponent implements OnInit, OnDestroy, After
|
||||
* Component initialization.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.topics$ = this.notificationsStateService.getQualityAssuranceTopics();
|
||||
this.topics$ = this.notificationsStateService.getQualityAssuranceTopics().pipe(
|
||||
tap((topics: QualityAssuranceTopicObject[]) => {
|
||||
const forward = this.activatedRoute.snapshot.queryParams?.forward === 'true';
|
||||
if (topics.length === 1 && forward) {
|
||||
// If there is only one topic, navigate to the first topic automatically
|
||||
this.router.navigate([this.getQualityAssuranceRoute(), this.sourceId, topics[0].id]);
|
||||
}
|
||||
})
|
||||
);
|
||||
this.totalElements$ = this.notificationsStateService.getQualityAssuranceTopicsTotals();
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,10 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
/**
|
||||
* Custom pipe to split a string into an array of substrings based on a specified separator.
|
||||
* @param value - The string to be split.
|
||||
* @param separator - The separator used to split the string.
|
||||
* @returns An array of substrings.
|
||||
*/
|
||||
@Pipe({
|
||||
name: 'dsSplit'
|
||||
})
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { of, forkJoin, Observable } from 'rxjs';
|
||||
import { catchError, map, mergeMap, take } from 'rxjs/operators';
|
||||
import { catchError, map, mergeMap, take, tap } from 'rxjs/operators';
|
||||
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
@@ -12,8 +12,9 @@ import { ResearcherProfile } from '../core/profile/model/researcher-profile.mode
|
||||
import {
|
||||
getAllSucceededRemoteDataPayload,
|
||||
getFinishedRemoteData,
|
||||
getFirstCompletedRemoteData,
|
||||
getFirstSucceededRemoteDataPayload,
|
||||
getFirstSucceededRemoteListPayload
|
||||
getFirstSucceededRemoteListPayload,
|
||||
} from '../core/shared/operators';
|
||||
import { Suggestion } from '../core/suggestion-notifications/models/suggestion.model';
|
||||
import { WorkspaceitemDataService } from '../core/submission/workspaceitem-data.service';
|
||||
@@ -155,10 +156,10 @@ export class SuggestionsService {
|
||||
*/
|
||||
public retrieveCurrentUserSuggestions(userUuid: string): Observable<SuggestionTarget[]> {
|
||||
return this.researcherProfileService.findById(userUuid, true).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
mergeMap((profile: ResearcherProfile) => {
|
||||
if (isNotEmpty(profile)) {
|
||||
return this.researcherProfileService.findRelatedItemId(profile).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
mergeMap((profile: RemoteData<ResearcherProfile> ) => {
|
||||
if (isNotEmpty(profile) && profile.hasSucceeded && isNotEmpty(profile.payload)) {
|
||||
return this.researcherProfileService.findRelatedItemId(profile.payload).pipe(
|
||||
mergeMap((itemId: string) => {
|
||||
return this.suggestionsDataService.getTargetsByUser(itemId).pipe(
|
||||
getFirstSucceededRemoteListPayload()
|
||||
@@ -169,7 +170,7 @@ export class SuggestionsService {
|
||||
return of([]);
|
||||
}
|
||||
}),
|
||||
take(1)
|
||||
catchError(() => of([]))
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -2708,13 +2708,15 @@
|
||||
|
||||
"correction-type.manage-relation.action.notification.withdrawn": "Withdraw request sent.",
|
||||
|
||||
"qa-event-notification.check.notification-withdrawn": "You have requested to withdraw this item.",
|
||||
"qa-event-notification.check.notification-withdrawn.user": "There are {{num}} items pending review(s) to check.",
|
||||
|
||||
"qa-event-notification.check.notification-reinstate": "You have requested to reinstate this item.",
|
||||
"qa-event-notification.check.notification-withdrawn.admin": "There are {{num}} {{source}} feedback(s) pending.",
|
||||
|
||||
"qa-event-notification-undo-withdrawn.check.button": "Undo request withdrawal",
|
||||
"qa-event-notification.check.notification-reinstate": "There are {{num}} pending reinstatement(s) pending for this item.",
|
||||
|
||||
"qa-event-notification-undo-reinstate.check.button": "Undo request reinstatment",
|
||||
"qa-event-notification-undo-withdrawn.check.button": "Check",
|
||||
|
||||
"qa-event-notification-undo-reinstate.check.button": "Check",
|
||||
|
||||
"item.version.create.modal.submitted.text": "The new version is being created. This may take some time if the item has a lot of relationships.",
|
||||
|
||||
@@ -3246,6 +3248,8 @@
|
||||
|
||||
"quality-assurance.topics.description": "Below you can see all the topics received from the subscriptions to {{source}}.",
|
||||
|
||||
"quality-assurance.topics.description-with-target": "Below you can see all the topics received from the subscriptions to {{source}} in regards to the",
|
||||
|
||||
"quality-assurance.source.description": "Below you can see all the notification's sources.",
|
||||
|
||||
"quality-assurance.topics": "Current Topics",
|
||||
|
Reference in New Issue
Block a user