[CST-12109] fixes

This commit is contained in:
Alisa Ismailati
2024-02-05 19:37:08 +01:00
parent 1b5007aae0
commit f916bd7776
20 changed files with 225 additions and 133 deletions

View File

@@ -33,7 +33,7 @@ export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderSer
*/ */
getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> { getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> {
const sourceId = key.split(':')[0]; const sourceId = key.split(':')[0];
const topicId = key.split(':')[1]; const topicId = key.split(':')[2];
if (topicId) { if (topicId) {
return this.qualityAssuranceService.getTopic(topicId).pipe( return this.qualityAssuranceService.getTopic(topicId).pipe(
@@ -41,7 +41,7 @@ export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderSer
map((topic) => { map((topic) => {
return [new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url), return [new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url),
new Breadcrumb(sourceId, `${url}${sourceId}`), new Breadcrumb(sourceId, `${url}${sourceId}`),
new Breadcrumb(topicId, undefined)]; new Breadcrumb(topicId.replace(/[!:]/g, '/'), undefined)];
}) })
); );
} else { } else {

View File

@@ -8,7 +8,7 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
import { ObjectCacheService } from '../cache/object-cache.service'; import { ObjectCacheService } from '../cache/object-cache.service';
import { IdentifiableDataService } from '../data/base/identifiable-data.service'; import { IdentifiableDataService } from '../data/base/identifiable-data.service';
import { SearchDataImpl } from '../data/base/search-data'; import { SearchDataImpl } from '../data/base/search-data';
import { CorrectionType } from './models/correction-type-mode.model'; import { CorrectionType } from './models/correctiontype.model';
import { Observable, map } from 'rxjs'; import { Observable, map } from 'rxjs';
import { RemoteData } from '../data/remote-data'; import { RemoteData } from '../data/remote-data';
import { PaginatedList } from '../data/paginated-list.model'; import { PaginatedList } from '../data/paginated-list.model';

View File

@@ -6,6 +6,10 @@ import { excludeFromEquals } from '../../utilities/equals.decorators';
import { HALLink } from '../../shared/hal-link.model'; import { HALLink } from '../../shared/hal-link.model';
@typedObject @typedObject
/**
* Represents a correction type. It extends the CacheableObject.
* The correction type represents a type of correction that can be applied to a submission.
*/
export class CorrectionType extends CacheableObject { export class CorrectionType extends CacheableObject {
static type = new ResourceType('correctiontype'); static type = new ResourceType('correctiontype');
@@ -15,20 +19,30 @@ export class CorrectionType extends CacheableObject {
@excludeFromEquals @excludeFromEquals
@autoserialize @autoserialize
type: ResourceType; type: ResourceType;
@autoserialize @autoserialize
/**
* The unique identifier for the correction type mode.
*/
id: string; id: string;
@autoserialize @autoserialize
/**
* The topic of the correction type mode.
*/
topic: string; topic: string;
@autoserialize @autoserialize
/**
* The discovery configuration for the correction type mode.
*/
discoveryConfiguration: string; discoveryConfiguration: string;
@autoserialize @autoserialize
/**
* The form used for creating a correction type.
*/
creationForm: string; creationForm: string;
@deserialize @deserialize
/**
* Represents the links associated with the correction type mode.
*/
_links: { _links: {
self: HALLink; self: HALLink;
}; };

View File

@@ -1,4 +1,4 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing';
import { ItemAlertsComponent } from './item-alerts.component'; import { ItemAlertsComponent } from './item-alerts.component';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
@@ -43,6 +43,7 @@ describe('ItemAlertsComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ItemAlertsComponent); fixture = TestBed.createComponent(ItemAlertsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.item = itemMock; component.item = itemMock;
fixture.detectChanges(); fixture.detectChanges();
@@ -108,46 +109,16 @@ describe('ItemAlertsComponent', () => {
}); });
}); });
describe('show reinstate button', () => { it('should return true when user is not an admin and there is at least one correction with topic REQUEST_REINSTATE', fakeAsync(() => {
it('should return false if user is an admin', () => { const isAdmin = false;
const isAdmin$ = of(true); const correction = [{ topic: 'REQUEST_REINSTATE' }];
authorizationService.isAuthorized.and.returnValue(isAdmin$); authorizationService.isAuthorized.and.returnValue(of(isAdmin));
const result$ = component.showReinstateButton$(); correctionTypeDataService.findByItem.and.returnValue(of(correction));
result$.subscribe((result) => {
expect(result).toBe(false);
});
});
it('should return false if no correction types are found', () => {
const isAdmin$ = of(false);
authorizationService.isAuthorized.and.returnValue(isAdmin$);
correctionTypeDataService.findByItem.and.returnValue(of([]));
const result$ = component.showReinstateButton$();
result$.subscribe((result) => {
expect(result).toBe(false);
});
});
it('should return false if no correction type with topic "REQUEST_REINSTATE" is found', () => {
const isAdmin$ = of(false);
authorizationService.isAuthorized.and.returnValue(isAdmin$);
correctionTypeDataService.findByItem.and.returnValue(of([{ topic: 'OTHER_TOPIC' }]));
const result$ = component.showReinstateButton$();
result$.subscribe((result) => {
expect(result).toBe(false);
});
});
it('should return true if user is not an admin and correction type with topic "REQUEST_REINSTATE" is found', () => {
const isAdmin$ = of(false);
authorizationService.isAuthorized.and.returnValue(isAdmin$);
correctionTypeDataService.findByItem.and.returnValue(of([{ topic: 'REQUEST_REINSTATE' }]));
const result$ = component.showReinstateButton$(); const result$ = component.showReinstateButton$();
tick();
result$.subscribe((result) => { result$.subscribe((result) => {
expect(result).toBe(true); expect(result).toBeTrue();
});
});
}); });
}));
}); });

View File

@@ -4,12 +4,14 @@
class="alert alert-info d-flex flex-row" class="alert alert-info d-flex flex-row"
*ngIf="source.totalEvents > 0" *ngIf="source.totalEvents > 0"
> >
<div class="col-2">
<img <img
class="source-logo" class="source-logo"
src="assets/images/qa-{{ source.id }}-logo.png" src="assets/images/qa-{{ source.id }}-logo.png"
onerror="this.src='assets/images/dspace-logo.svg'" onerror="this.src='assets/images/dspace-logo.svg'"
alt="{{ source.id }} logo" alt="{{ source.id }} logo"
/> />
</div>
<div class="w-100 d-flex justify-content-between"> <div class="w-100 d-flex justify-content-between">
<div class="pl-4 align-self-center"> <div class="pl-4 align-self-center">
{{ "mydspace.qa-event-notification.check.notification-info" | translate : { num: source.totalEvents } }} {{ "mydspace.qa-event-notification.check.notification-info" | translate : { num: source.totalEvents } }}

View File

@@ -26,7 +26,7 @@ import { QualityAssuranceSourceService } from './qa/source/quality-assurance-sou
import { import {
QualityAssuranceSourceDataService QualityAssuranceSourceDataService
} from '../core/notifications/qa/source/quality-assurance-source-data.service'; } from '../core/notifications/qa/source/quality-assurance-source-data.service';
import { GetEPersonDataPipe } from './qa/events/get-ePerson-data.pipe'; import { EPersonDataComponent } from './qa/events/ePerson-data/ePerson-data.component';
const MODULES = [ const MODULES = [
CommonModule, CommonModule,
@@ -41,7 +41,8 @@ const MODULES = [
const COMPONENTS = [ const COMPONENTS = [
QualityAssuranceTopicsComponent, QualityAssuranceTopicsComponent,
QualityAssuranceEventsComponent, QualityAssuranceEventsComponent,
QualityAssuranceSourceComponent QualityAssuranceSourceComponent,
EPersonDataComponent,
]; ];
const DIRECTIVES = [ ]; const DIRECTIVES = [ ];
@@ -60,7 +61,6 @@ const PROVIDERS = [
]; ];
const PIPES = [ const PIPES = [
GetEPersonDataPipe
]; ];
@NgModule({ @NgModule({

View File

@@ -0,0 +1,10 @@
<ng-container *ngIf="ePersonId">
<ng-container *ngIf="getEPersonData$() | async as ePersonData">
<ng-container *ngFor="let property of properties">
<span *ngIf="ePersonData[property]">
{{ ePersonData[property] }}
</span>
<br>
</ng-container>
</ng-container>
</ng-container>

View File

@@ -0,0 +1,58 @@
/* tslint:disable:no-unused-variable */
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { EPersonDataComponent } from './ePerson-data.component';
import { EPersonDataService } from './../../../../core/eperson/eperson-data.service';
import { EPerson } from 'src/app/core/eperson/models/eperson.model';
import { createSuccessfulRemoteDataObject$ } from 'src/app/shared/remote-data.utils';
describe('EPersonDataComponent', () => {
let component: EPersonDataComponent;
let fixture: ComponentFixture<EPersonDataComponent>;
let ePersonDataService = jasmine.createSpyObj('EPersonDataService', ['findById']);
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ EPersonDataComponent ],
providers: [ {
provide: EPersonDataService,
useValue: ePersonDataService
} ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EPersonDataComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should retrieve EPerson data when ePersonId is provided', () => {
const ePersonId = '123';
const ePersonData = Object.assign(new EPerson(), {
id: ePersonId,
email: 'john.doe@domain.com',
metadata: [
{
key: 'eperson.firstname',
value: 'John'
},
{
key: 'eperson.lastname',
value: 'Doe'
}
]
});
const ePersonDataRD$ = createSuccessfulRemoteDataObject$(ePersonData);
ePersonDataService.findById.and.returnValue(ePersonDataRD$);
component.ePersonId = ePersonId;
component.getEPersonData$();
fixture.detectChanges();
expect(ePersonDataService.findById).toHaveBeenCalledWith(ePersonId, true);
});
});

View File

@@ -0,0 +1,45 @@
import { Component, Input } from '@angular/core';
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../../../../core/shared/operators';
import { Observable } from 'rxjs';
import { EPerson } from '../../../../core/eperson/models/eperson.model';
@Component({
selector: 'ds-eperson-data',
templateUrl: './ePerson-data.component.html',
styleUrls: ['./ePerson-data.component.scss']
})
/**
* Represents the component for displaying ePerson data.
*/
export class EPersonDataComponent {
/**
* The ID of the ePerson.
*/
@Input() ePersonId: string;
/**
* The properties of the ePerson to display.
*/
@Input() properties: string[];
/**
* Creates an instance of the EPersonDataComponent.
* @param ePersonDataService The service for retrieving ePerson data.
*/
constructor(private ePersonDataService: EPersonDataService) { }
/**
* Retrieves the EPerson data based on the provided ePersonId.
* @returns An Observable that emits the EPerson data.
*/
getEPersonData$(): Observable<EPerson> {
if (this.ePersonId) {
return this.ePersonDataService.findById(this.ePersonId, true).pipe(
getFirstCompletedRemoteData(),
getRemoteDataPayload()
);
}
}
}

View File

@@ -1,24 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Observable, tap } from 'rxjs';
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
import { EPerson } from '../../../core/eperson/models/eperson.model';
import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../../../core/shared/operators';
@Pipe({
name: 'dsGetEPersonData'
})
export class GetEPersonDataPipe implements PipeTransform {
constructor(private ePersonDataService: EPersonDataService) { }
/**
* Transforms the personId into an Observable of EPerson.
* @param personId The ID of the person.
* @returns An Observable of EPerson.
*/
transform(personId: string): Observable<EPerson> {
return this.ePersonDataService.findById(personId, true).pipe(
getFirstCompletedRemoteData(),
getRemoteDataPayload()
);
}
}

View File

@@ -85,16 +85,14 @@
<td> <td>
<p> <p>
<span *ngIf="eventElement.event.message"> <span *ngIf="eventElement.event.message">
<span class="badge badge-info">{{eventElement.event.message.reason}}</span><br> <span>{{eventElement.event.message.reason}}</span><br>
</span> </span>
</p> </p>
</td> </td>
<td> <td>
<p> <p>
<span *ngIf="eventElement.event.originalId"> <span *ngIf="eventElement.event.originalId">
<span class="badge badge-info"> <ds-eperson-data [ePersonId]="eventElement.event.originalId" [properties]="['email']"></ds-eperson-data>
{{ (eventElement.event.originalId | dsGetEPersonData | async)?.email }}
</span>
</span> </span>
</p> </p>
</td> </td>
@@ -200,7 +198,7 @@
</div> </div>
<div class="row text-right"> <div class="row text-right">
<div class="col-md-12"> <div class="col-md-12">
<a class="btn btn-outline-secondary" [routerLink]="['/notifications/quality-assurance']"> <a class="btn btn-outline-secondary" [routerLink]="['/notifications/quality-assurance', sourceId]">
<i class="fas fa-angle-double-left"></i> <i class="fas fa-angle-double-left"></i>
{{'quality-assurance.events.back' | translate}} {{'quality-assurance.events.back' | translate}}
</a> </a>

View File

@@ -34,7 +34,6 @@ import { AuthorizationDataService } from '../../../core/data/feature-authorizati
import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { NoContent } from '../../../core/shared/NoContent.model'; import { NoContent } from '../../../core/shared/NoContent.model';
import {environment} from '../../../../environments/environment'; import {environment} from '../../../../environments/environment';
import { getEntityPageRoute } from 'src/app/item-page/item-page-routing-paths';
/** /**
* Component to display the Quality Assurance event list. * Component to display the Quality Assurance event list.
@@ -80,6 +79,11 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
* @type {string} * @type {string}
*/ */
public topic: string; public topic: string;
/**
* The sourceId of the Quality Assurance events.
* @type {string}
*/
sourceId: string;
/** /**
* The rejected/ignore reason. * The rejected/ignore reason.
* @type {string} * @type {string}
@@ -144,9 +148,11 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
this.isEventPageLoading.next(true); this.isEventPageLoading.next(true);
this.isAdmin$ = this.authorizationService.isAuthorized(FeatureID.AdministratorOf); this.isAdmin$ = this.authorizationService.isAuthorized(FeatureID.AdministratorOf);
// this.sourceId = this.activatedRoute.snapshot.params.sourceId;
this.activatedRoute.paramMap.pipe( this.activatedRoute.paramMap.pipe(
tap((params) => { tap((params) => {
this.sourceUrlForProjectSearch = environment.qualityAssuranceConfig.sourceUrlMapForProjectSearch[params.get('sourceId')]; this.sourceUrlForProjectSearch = environment.qualityAssuranceConfig.sourceUrlMapForProjectSearch[params.get('sourceId')];
this.sourceId = params.get('sourceId');
}), }),
map((params) => params.get('topicId')), map((params) => params.get('topicId')),
take(1), take(1),
@@ -459,8 +465,4 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
delete(qaEvent: QualityAssuranceEventData): Observable<RemoteData<NoContent>> { delete(qaEvent: QualityAssuranceEventData): Observable<RemoteData<NoContent>> {
return this.qualityAssuranceEventRestService.deleteQAEvent(qaEvent); return this.qualityAssuranceEventRestService.deleteQAEvent(qaEvent);
} }
getEntityPageRoute(itemId: string): string {
return getEntityPageRoute('person', itemId);
}
} }

View File

@@ -34,12 +34,12 @@
<tbody> <tbody>
<tr *ngFor="let sourceElement of (sources$ | async); let i = index"> <tr *ngFor="let sourceElement of (sources$ | async); let i = index">
<td>{{sourceElement.id}}</td> <td>{{sourceElement.id}}</td>
<td>{{formatDate(sourceElement.lastEvent)}}</td> <td>{{sourceElement.lastEvent | date: 'dd/MM/yyyy hh:mm' }}</td>
<td> <td>
<div class="btn-group edit-field"> <div class="btn-group edit-field">
<button <button
class="btn btn-outline-primary btn-sm" class="btn btn-outline-primary btn-sm"
title="{{'quality-assurance.button.detail' | translate }}" title="{{'quality-assurance.source-list.button.detail' | translate : { param: sourceElement.id } }}"
[routerLink]="[sourceElement.id]"> [routerLink]="[sourceElement.id]">
<span class="badge badge-info">{{sourceElement.totalEvents}}</span> <span class="badge badge-info">{{sourceElement.totalEvents}}</span>
<i class="fas fa-info fa-fw"></i> <i class="fas fa-info fa-fw"></i>

View File

@@ -8,7 +8,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
import { NotificationsStateService } from '../../notifications-state.service'; import { NotificationsStateService } from '../../notifications-state.service';
import { AdminQualityAssuranceSourcePageParams } from '../../../admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service'; import { AdminQualityAssuranceSourcePageParams } from '../../../admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
import { format } from 'date-fns';
/** /**
* Component to display the Quality Assurance source list. * Component to display the Quality Assurance source list.
*/ */
@@ -65,20 +65,6 @@ export class QualityAssuranceSourceComponent implements OnInit {
this.totalElements$ = this.notificationsStateService.getQualityAssuranceSourceTotals(); this.totalElements$ = this.notificationsStateService.getQualityAssuranceSourceTotals();
} }
/**
* Formats the given date string into the format 'yyyy-MM-dd HH:mm:ss'.
* If the date is falsy, an empty string is returned.
*
* @param date - The date string to be formatted.
* @returns The formatted date string.
*/
formatDate(date: string): string {
if (!date) {
return '';
}
return format(new Date(date), 'yyyy-MM-dd HH:mm:ss');
}
/** /**
* First Quality Assurance source loading after view initialization. * First Quality Assurance source loading after view initialization.
*/ */

View File

@@ -38,12 +38,12 @@
<tbody> <tbody>
<tr *ngFor="let topicElement of (topics$ | async); let i = index"> <tr *ngFor="let topicElement of (topics$ | async); let i = index">
<td>{{topicElement.name}}</td> <td>{{topicElement.name}}</td>
<td>{{formatDate(topicElement.lastEvent)}}</td> <td>{{topicElement.lastEvent | date: 'dd/MM/yyyy hh:mm' }}</td>
<td> <td>
<div class="btn-group edit-field"> <div class="btn-group edit-field">
<button <button
class="btn btn-outline-primary btn-sm" class="btn btn-outline-primary btn-sm"
title="{{'quality-assurance.button.detail' | translate }}" title="{{'quality-assurance.topics-list.button.detail' | translate : { param: topicElement.name } }}"
[routerLink]="[topicElement.id]"> [routerLink]="[topicElement.id]">
<span class="badge badge-info">{{topicElement.totalEvents}}</span> <span class="badge badge-info">{{topicElement.totalEvents}}</span>
<i class="fas fa-info fa-fw"></i> <i class="fas fa-info fa-fw"></i>
@@ -58,4 +58,12 @@
</ds-pagination> </ds-pagination>
</div> </div>
</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> </div>

View File

@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'; import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
import { distinctUntilChanged, map, take, tap } from 'rxjs/operators'; import { distinctUntilChanged, map, take, tap } from 'rxjs/operators';
@@ -20,7 +20,6 @@ import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../../../core
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { getItemPageRoute } from '../../../item-page/item-page-routing-paths'; import { getItemPageRoute } from '../../../item-page/item-page-routing-paths';
import { getNotificatioQualityAssuranceRoute } from '../../../admin/admin-routing-paths'; import { getNotificatioQualityAssuranceRoute } from '../../../admin/admin-routing-paths';
import { format } from 'date-fns';
/** /**
* Component to display the Quality Assurance topic list. * Component to display the Quality Assurance topic list.
@@ -30,7 +29,7 @@ import { format } from 'date-fns';
templateUrl: './quality-assurance-topics.component.html', templateUrl: './quality-assurance-topics.component.html',
styleUrls: ['./quality-assurance-topics.component.scss'], styleUrls: ['./quality-assurance-topics.component.scss'],
}) })
export class QualityAssuranceTopicsComponent implements OnInit { export class QualityAssuranceTopicsComponent implements OnInit, OnDestroy, AfterViewInit {
/** /**
* The pagination system configuration for HTML listing. * The pagination system configuration for HTML listing.
* @type {PaginationComponentOptions} * @type {PaginationComponentOptions}
@@ -138,7 +137,7 @@ export class QualityAssuranceTopicsComponent implements OnInit {
* Dispatch the Quality Assurance topics retrival. * Dispatch the Quality Assurance topics retrival.
*/ */
public getQualityAssuranceTopics(source: string, target?: string): void { public getQualityAssuranceTopics(source: string, target?: string): void {
this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe( this.subs.push(this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe(
distinctUntilChanged(), distinctUntilChanged(),
).subscribe((options: PaginationComponentOptions) => { ).subscribe((options: PaginationComponentOptions) => {
this.notificationsStateService.dispatchRetrieveQualityAssuranceTopics( this.notificationsStateService.dispatchRetrieveQualityAssuranceTopics(
@@ -147,7 +146,7 @@ export class QualityAssuranceTopicsComponent implements OnInit {
source, source,
target target
); );
}); }));
} }
/** /**
@@ -202,20 +201,6 @@ export class QualityAssuranceTopicsComponent implements OnInit {
return getNotificatioQualityAssuranceRoute(); return getNotificatioQualityAssuranceRoute();
} }
/**
* Formats the given date string into the format 'yyyy-MM-dd HH:mm:ss'.
* If the date is falsy, an empty string is returned.
*
* @param date - The date string to format.
* @returns The formatted date string.
*/
formatDate(date: string): string {
if (!date) {
return '';
}
return format(new Date(date), 'yyyy-MM-dd HH:mm:ss');
}
/** /**
* Unsubscribe from all subscriptions. * Unsubscribe from all subscriptions.
*/ */

View File

@@ -9,13 +9,29 @@ import { AuthorizationDataService } from '../../core/data/feature-authorization/
templateUrl: './item-withdrawn-reinstate-modal.component.html', templateUrl: './item-withdrawn-reinstate-modal.component.html',
styleUrls: ['./item-withdrawn-reinstate-modal.component.scss'] styleUrls: ['./item-withdrawn-reinstate-modal.component.scss']
}) })
/**
* Represents a modal component for withdrawing or reinstating an item.
* Implements the ModalBeforeDismiss interface.
*/
export class ItemWithdrawnReinstateModalComponent implements ModalBeforeDismiss { export class ItemWithdrawnReinstateModalComponent implements ModalBeforeDismiss {
/**
* The reason for withdrawing or reinstating a suggestion.
*/
reason: string; reason: string;
/**
* Indicates whether the item can be withdrawn.
*/
canWithdraw: boolean; canWithdraw: boolean;
/**
* BehaviorSubject that represents the submitted state.
* Emits a boolean value indicating whether the form has been submitted or not.
*/
submitted$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); submitted$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
/**
* Event emitter for creating a QA event.
* @event createQAEvent
*/
@Output() createQAEvent: EventEmitter<string> = new EventEmitter<string>(); @Output() createQAEvent: EventEmitter<string> = new EventEmitter<string>();
constructor( constructor(
@@ -23,22 +39,36 @@ export class ItemWithdrawnReinstateModalComponent implements ModalBeforeDismiss
protected authorizationService: AuthorizationDataService, protected authorizationService: AuthorizationDataService,
) {} ) {}
/**
* Closes the modal.
*/
onModalClose() { onModalClose() {
this.activeModal.close(); this.activeModal.close();
} }
/**
* Determines whether the modal can be dismissed.
* @returns {boolean} True if the modal can be dismissed, false otherwise.
*/
beforeDismiss(): boolean { beforeDismiss(): boolean {
// prevent the modal from being dismissed after version creation is initiated // prevent the modal from being dismissed after version creation is initiated
return !this.submitted$.getValue(); return !this.submitted$.getValue();
} }
/**
* Handles the submission of the modal form.
* Emits the reason for withdrawal or reinstatement through the createQAEvent output.
*/
onModalSubmit() { onModalSubmit() {
this.submitted$.next(true); this.submitted$.next(true);
this.createQAEvent.emit(this.reason); this.createQAEvent.emit(this.reason);
} }
/**
* Sets the withdrawal state of the component.
* @param state The new withdrawal state.
*/
public setWithdraw(state: boolean) { public setWithdraw(state: boolean) {
this.canWithdraw = state; this.canWithdraw = state;
} }
} }

View File

@@ -23,6 +23,9 @@ export const REQUEST_REINSTATE = 'REQUEST/REINSTATE';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
/**
* Service for managing the withdrawn/reinstate modal for a DSO.
*/
export class DsoWithdrawnReinstateModalService { export class DsoWithdrawnReinstateModalService {
constructor( constructor(

View File

@@ -518,7 +518,7 @@
"admin.quality-assurance.page.title": "Quality Assurance", "admin.quality-assurance.page.title": "Quality Assurance",
"admin.notifications.source.breadcrumbs": "Quality Assurance Source", "admin.notifications.source.breadcrumbs": "Quality Assurance",
"admin.access-control.groups.form.tooltip.editGroupPage": "On this page, you can modify the properties and members of a group. In the top section, you can edit the group name and description, unless this is an admin group for a collection or community, in which case the group name and description are auto-generated and cannot be edited. In the following sections, you can edit group membership. See [the wiki](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group) for more details.", "admin.access-control.groups.form.tooltip.editGroupPage": "On this page, you can modify the properties and members of a group. In the top section, you can edit the group name and description, unless this is an admin group for a collection or community, in which case the group name and description are auto-generated and cannot be edited. In the following sections, you can edit group membership. See [the wiki](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group) for more details.",
@@ -2480,9 +2480,9 @@
"item.page.version.create": "Create new version", "item.page.version.create": "Create new version",
"item.page.withdrawn": "Withdraw this Item", "item.page.withdrawn": "Request a withdrawal for this item",
"item.page.reinstate": "Reinstate this Item", "item.page.reinstate": "Request reinstatement",
"item.page.version.hasDraft": "A new version cannot be created because there is an inprogress submission in the version history", "item.page.version.hasDraft": "A new version cannot be created because there is an inprogress submission in the version history",
@@ -3190,7 +3190,9 @@
"quality-assurance.table.actions": "Actions", "quality-assurance.table.actions": "Actions",
"quality-assurance.button.detail": "Show details", "quality-assurance.source-list.button.detail": "Show topics for {{param}}",
"quality-assurance.topics-list.button.detail": "Show suggestions for {{param}}",
"quality-assurance.noTopics": "No topics found.", "quality-assurance.noTopics": "No topics found.",
@@ -3256,6 +3258,8 @@
"quality-assurance.events.back": "Back to topics", "quality-assurance.events.back": "Back to topics",
"quality-assurance.events.back-to-sources": "Back to sources",
"quality-assurance.event.table.less": "Show less", "quality-assurance.event.table.less": "Show less",
"quality-assurance.event.table.more": "Show more", "quality-assurance.event.table.more": "Show more",