diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts index 209ae0722c..53aba9fa0d 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts @@ -33,7 +33,7 @@ export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderSer */ getBreadcrumbs(key: string, url: string): Observable { const sourceId = key.split(':')[0]; - const topicId = key.split(':')[1]; + const topicId = key.split(':')[2]; if (topicId) { return this.qualityAssuranceService.getTopic(topicId).pipe( @@ -41,7 +41,7 @@ export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderSer map((topic) => { return [new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url), new Breadcrumb(sourceId, `${url}${sourceId}`), - new Breadcrumb(topicId, undefined)]; + new Breadcrumb(topicId.replace(/[!:]/g, '/'), undefined)]; }) ); } else { diff --git a/src/app/core/submission/correctiontype-data.service.ts b/src/app/core/submission/correctiontype-data.service.ts index d9675894d3..8a5bbb1fb8 100644 --- a/src/app/core/submission/correctiontype-data.service.ts +++ b/src/app/core/submission/correctiontype-data.service.ts @@ -8,7 +8,7 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv import { ObjectCacheService } from '../cache/object-cache.service'; import { IdentifiableDataService } from '../data/base/identifiable-data.service'; 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 { RemoteData } from '../data/remote-data'; import { PaginatedList } from '../data/paginated-list.model'; diff --git a/src/app/core/submission/models/correction-type-mode.model.ts b/src/app/core/submission/models/correctiontype.model.ts similarity index 61% rename from src/app/core/submission/models/correction-type-mode.model.ts rename to src/app/core/submission/models/correctiontype.model.ts index 4daac53893..9329fa88d8 100644 --- a/src/app/core/submission/models/correction-type-mode.model.ts +++ b/src/app/core/submission/models/correctiontype.model.ts @@ -6,6 +6,10 @@ import { excludeFromEquals } from '../../utilities/equals.decorators'; import { HALLink } from '../../shared/hal-link.model'; @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 { static type = new ResourceType('correctiontype'); @@ -15,20 +19,30 @@ export class CorrectionType extends CacheableObject { @excludeFromEquals @autoserialize type: ResourceType; - @autoserialize + /** + * The unique identifier for the correction type mode. + */ id: string; - @autoserialize + /** + * The topic of the correction type mode. + */ topic: string; - @autoserialize + /** + * The discovery configuration for the correction type mode. + */ discoveryConfiguration: string; - @autoserialize + /** + * The form used for creating a correction type. + */ creationForm: string; - @deserialize + /** + * Represents the links associated with the correction type mode. + */ _links: { self: HALLink; }; diff --git a/src/app/item-page/alerts/item-alerts.component.spec.ts b/src/app/item-page/alerts/item-alerts.component.spec.ts index c55bac4180..3ba8801784 100644 --- a/src/app/item-page/alerts/item-alerts.component.spec.ts +++ b/src/app/item-page/alerts/item-alerts.component.spec.ts @@ -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 { TranslateModule } from '@ngx-translate/core'; import { NO_ERRORS_SCHEMA } from '@angular/core'; @@ -24,7 +24,7 @@ describe('ItemAlertsComponent', () => { beforeEach(waitForAsync(() => { authorizationService = jasmine.createSpyObj('authorizationService', ['isAuthorized']); - dsoWithdrawnReinstateModalService = jasmine.createSpyObj('dsoWithdrawnReinstateModalService',['openCreateWithdrawnReinstateModal']); + dsoWithdrawnReinstateModalService = jasmine.createSpyObj('dsoWithdrawnReinstateModalService', ['openCreateWithdrawnReinstateModal']); correctionTypeDataService = jasmine.createSpyObj('correctionTypeDataService', { findByItem: of({}) }); @@ -43,6 +43,7 @@ describe('ItemAlertsComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ItemAlertsComponent); + component = fixture.componentInstance; component.item = itemMock; fixture.detectChanges(); @@ -108,46 +109,16 @@ describe('ItemAlertsComponent', () => { }); }); - describe('show reinstate button', () => { - it('should return false if user is an admin', () => { - const isAdmin$ = of(true); - authorizationService.isAuthorized.and.returnValue(isAdmin$); - const result$ = component.showReinstateButton$(); - result$.subscribe((result) => { - expect(result).toBe(false); - }); + it('should return true when user is not an admin and there is at least one correction with topic REQUEST_REINSTATE', fakeAsync(() => { + const isAdmin = false; + const correction = [{ topic: 'REQUEST_REINSTATE' }]; + authorizationService.isAuthorized.and.returnValue(of(isAdmin)); + correctionTypeDataService.findByItem.and.returnValue(of(correction)); + + const result$ = component.showReinstateButton$(); + tick(); + result$.subscribe((result) => { + expect(result).toBeTrue(); }); - - 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$(); - - result$.subscribe((result) => { - expect(result).toBe(true); - }); - }); - }); + })); }); diff --git a/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.html b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.html index 4f6fa90474..7a85eda574 100644 --- a/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.html +++ b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.html @@ -4,12 +4,14 @@ class="alert alert-info d-flex flex-row" *ngIf="source.totalEvents > 0" > +
+
{{ "mydspace.qa-event-notification.check.notification-info" | translate : { num: source.totalEvents } }} diff --git a/src/app/notifications/notifications.module.ts b/src/app/notifications/notifications.module.ts index 26ad81cb9c..7b833e12bb 100644 --- a/src/app/notifications/notifications.module.ts +++ b/src/app/notifications/notifications.module.ts @@ -26,7 +26,7 @@ import { QualityAssuranceSourceService } from './qa/source/quality-assurance-sou import { QualityAssuranceSourceDataService } 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 = [ CommonModule, @@ -41,7 +41,8 @@ const MODULES = [ const COMPONENTS = [ QualityAssuranceTopicsComponent, QualityAssuranceEventsComponent, - QualityAssuranceSourceComponent + QualityAssuranceSourceComponent, + EPersonDataComponent, ]; const DIRECTIVES = [ ]; @@ -60,7 +61,6 @@ const PROVIDERS = [ ]; const PIPES = [ - GetEPersonDataPipe ]; @NgModule({ diff --git a/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.html b/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.html new file mode 100644 index 0000000000..058457fd40 --- /dev/null +++ b/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.html @@ -0,0 +1,10 @@ + + + + + {{ ePersonData[property] }} + +
+
+
+
diff --git a/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.scss b/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.spec.ts b/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.spec.ts new file mode 100644 index 0000000000..6fad8dbc92 --- /dev/null +++ b/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.spec.ts @@ -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; + 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); + }); +}); diff --git a/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.ts b/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.ts new file mode 100644 index 0000000000..f1a9c8c592 --- /dev/null +++ b/src/app/notifications/qa/events/ePerson-data/ePerson-data.component.ts @@ -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 { + if (this.ePersonId) { + return this.ePersonDataService.findById(this.ePersonId, true).pipe( + getFirstCompletedRemoteData(), + getRemoteDataPayload() + ); + } + } +} diff --git a/src/app/notifications/qa/events/get-ePerson-data.pipe.ts b/src/app/notifications/qa/events/get-ePerson-data.pipe.ts deleted file mode 100644 index 58084d4a42..0000000000 --- a/src/app/notifications/qa/events/get-ePerson-data.pipe.ts +++ /dev/null @@ -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 { - return this.ePersonDataService.findById(personId, true).pipe( - getFirstCompletedRemoteData(), - getRemoteDataPayload() - ); - } -} diff --git a/src/app/notifications/qa/events/quality-assurance-events.component.html b/src/app/notifications/qa/events/quality-assurance-events.component.html index 5c1e10bc05..9d9cd2b58c 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/notifications/qa/events/quality-assurance-events.component.html @@ -85,16 +85,14 @@

- {{eventElement.event.message.reason}}
+ {{eventElement.event.message.reason}}

- - {{ (eventElement.event.originalId | dsGetEPersonData | async)?.email }} - +

@@ -200,7 +198,7 @@
- + {{'quality-assurance.events.back' | translate}} diff --git a/src/app/notifications/qa/events/quality-assurance-events.component.ts b/src/app/notifications/qa/events/quality-assurance-events.component.ts index 24369c00fa..7dcccae2de 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.ts @@ -34,7 +34,6 @@ import { AuthorizationDataService } from '../../../core/data/feature-authorizati import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; import { NoContent } from '../../../core/shared/NoContent.model'; import {environment} from '../../../../environments/environment'; -import { getEntityPageRoute } from 'src/app/item-page/item-page-routing-paths'; /** * Component to display the Quality Assurance event list. @@ -80,6 +79,11 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * @type {string} */ public topic: string; + /** + * The sourceId of the Quality Assurance events. + * @type {string} + */ + sourceId: string; /** * The rejected/ignore reason. * @type {string} @@ -144,9 +148,11 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { 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')]; + this.sourceId = params.get('sourceId'); }), map((params) => params.get('topicId')), take(1), @@ -459,8 +465,4 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { delete(qaEvent: QualityAssuranceEventData): Observable> { return this.qualityAssuranceEventRestService.deleteQAEvent(qaEvent); } - - getEntityPageRoute(itemId: string): string { - return getEntityPageRoute('person', itemId); - } } diff --git a/src/app/notifications/qa/source/quality-assurance-source.component.html b/src/app/notifications/qa/source/quality-assurance-source.component.html index 841c70b6a7..543304aacc 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.component.html +++ b/src/app/notifications/qa/source/quality-assurance-source.component.html @@ -34,12 +34,12 @@ {{sourceElement.id}} - {{formatDate(sourceElement.lastEvent)}} + {{sourceElement.lastEvent | date: 'dd/MM/yyyy hh:mm' }}
+
diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.ts b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts index ecc7e66898..96a613d26c 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.component.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core'; import { Observable, Subscription } from 'rxjs'; 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 { getItemPageRoute } from '../../../item-page/item-page-routing-paths'; import { getNotificatioQualityAssuranceRoute } from '../../../admin/admin-routing-paths'; -import { format } from 'date-fns'; /** * Component to display the Quality Assurance topic list. @@ -30,7 +29,7 @@ import { format } from 'date-fns'; templateUrl: './quality-assurance-topics.component.html', 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. * @type {PaginationComponentOptions} @@ -138,7 +137,7 @@ export class QualityAssuranceTopicsComponent implements OnInit { * Dispatch the Quality Assurance topics retrival. */ 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(), ).subscribe((options: PaginationComponentOptions) => { this.notificationsStateService.dispatchRetrieveQualityAssuranceTopics( @@ -147,7 +146,7 @@ export class QualityAssuranceTopicsComponent implements OnInit { source, target ); - }); + })); } /** @@ -202,20 +201,6 @@ export class QualityAssuranceTopicsComponent implements OnInit { 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. */ diff --git a/src/app/shared/correction-suggestion/withdrawn-reinstate-modal.component.ts b/src/app/shared/correction-suggestion/withdrawn-reinstate-modal.component.ts index f843bec75d..de842eb1e5 100644 --- a/src/app/shared/correction-suggestion/withdrawn-reinstate-modal.component.ts +++ b/src/app/shared/correction-suggestion/withdrawn-reinstate-modal.component.ts @@ -9,13 +9,29 @@ import { AuthorizationDataService } from '../../core/data/feature-authorization/ templateUrl: './item-withdrawn-reinstate-modal.component.html', 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 { + /** + * The reason for withdrawing or reinstating a suggestion. + */ reason: string; - + /** + * Indicates whether the item can be withdrawn. + */ canWithdraw: boolean; + /** + * BehaviorSubject that represents the submitted state. + * Emits a boolean value indicating whether the form has been submitted or not. + */ submitted$: BehaviorSubject = new BehaviorSubject(false); - + /** + * Event emitter for creating a QA event. + * @event createQAEvent + */ @Output() createQAEvent: EventEmitter = new EventEmitter(); constructor( @@ -23,22 +39,36 @@ export class ItemWithdrawnReinstateModalComponent implements ModalBeforeDismiss protected authorizationService: AuthorizationDataService, ) {} + /** + * Closes the modal. + */ onModalClose() { this.activeModal.close(); } + /** + * Determines whether the modal can be dismissed. + * @returns {boolean} True if the modal can be dismissed, false otherwise. + */ beforeDismiss(): boolean { // prevent the modal from being dismissed after version creation is initiated return !this.submitted$.getValue(); } + /** + * Handles the submission of the modal form. + * Emits the reason for withdrawal or reinstatement through the createQAEvent output. + */ onModalSubmit() { this.submitted$.next(true); this.createQAEvent.emit(this.reason); } + /** + * Sets the withdrawal state of the component. + * @param state The new withdrawal state. + */ public setWithdraw(state: boolean) { this.canWithdraw = state; } - } diff --git a/src/app/shared/dso-page/dso-withdrawn-reinstate-service/dso-withdrawn-reinstate-modal.service.ts b/src/app/shared/dso-page/dso-withdrawn-reinstate-service/dso-withdrawn-reinstate-modal.service.ts index bb96c693aa..d5f47ed57b 100644 --- a/src/app/shared/dso-page/dso-withdrawn-reinstate-service/dso-withdrawn-reinstate-modal.service.ts +++ b/src/app/shared/dso-page/dso-withdrawn-reinstate-service/dso-withdrawn-reinstate-modal.service.ts @@ -23,6 +23,9 @@ export const REQUEST_REINSTATE = 'REQUEST/REINSTATE'; @Injectable({ providedIn: 'root' }) +/** + * Service for managing the withdrawn/reinstate modal for a DSO. + */ export class DsoWithdrawnReinstateModalService { constructor( diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index bbfc4f6e4f..9b03d04d79 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -518,7 +518,7 @@ "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.", @@ -2480,9 +2480,9 @@ "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", @@ -3190,7 +3190,9 @@ "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.", @@ -3256,6 +3258,8 @@ "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.more": "Show more",