From b8e9f620b6da41b4bcdd31f565096b58f1779675 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Fri, 18 Feb 2022 16:40:45 +0100 Subject: [PATCH 001/196] [CST-5249] Migration of OPENAIRE correction service --- ...ations-openaire-events-page.component.html | 1 + ...ons-openaire-events-page.component.spec.ts | 26 + ...ications-openaire-events-page.component.ts | 9 + ...fications-openaire-events-page.resolver.ts | 32 + ...s-openaire-topics-page-resolver.service.ts | 32 + ...ations-openaire-topics-page.component.html | 1 + ...ons-openaire-topics-page.component.spec.ts | 26 + ...ications-openaire-topics-page.component.ts | 9 + .../admin-notifications-routing-paths.ts | 8 + .../admin-notifications-routing.module.ts | 60 + .../admin-notifications.module.ts | 29 + src/app/admin/admin-routing-paths.ts | 5 + src/app/admin/admin-routing.module.ts | 7 +- .../admin-sidebar/admin-sidebar.component.ts | 39 +- src/app/core/core.module.ts | 4 + src/app/core/data/data.service.ts | 49 +- ...openaire-broker-event-rest.service.spec.ts | 246 +++ .../openaire-broker-event-rest.service.ts | 185 ++ ...naire-broker-event-object.resource-type.ts | 9 + .../models/openaire-broker-event.model.ts | 157 ++ ...naire-broker-topic-object.resource-type.ts | 9 + .../models/openaire-broker-topic.model.ts | 58 + ...openaire-broker-topic-rest.service.spec.ts | 127 ++ .../openaire-broker-topic-rest.service.ts | 133 ++ .../openaire-broker-events.component.html | 207 ++ .../openaire-broker-events.component.spec.ts | 332 +++ .../openaire-broker-events.component.ts | 464 +++++ .../openaire-broker-events.scomponent.scss | 21 + .../project-entry-import-modal.component.html | 70 + .../project-entry-import-modal.component.scss | 3 + ...oject-entry-import-modal.component.spec.ts | 210 ++ .../project-entry-import-modal.component.ts | 274 +++ .../topics/openaire-broker-topics.actions.ts | 99 + .../openaire-broker-topics.component.html | 57 + .../openaire-broker-topics.component.scss | 0 .../openaire-broker-topics.component.spec.ts | 152 ++ .../openaire-broker-topics.component.ts | 142 ++ .../topics/openaire-broker-topics.effects.ts | 87 + .../openaire-broker-topics.reducer.spec.ts | 68 + .../topics/openaire-broker-topics.reducer.ts | 72 + .../openaire-broker-topics.service.spec.ts | 67 + .../topics/openaire-broker-topics.service.ts | 55 + .../openaire/openaire-state.service.spec.ts | 275 +++ src/app/openaire/openaire-state.service.ts | 116 ++ src/app/openaire/openaire.effects.ts | 5 + src/app/openaire/openaire.module.ts | 74 + src/app/openaire/openaire.reducer.ts | 16 + src/app/openaire/selectors.ts | 79 + src/app/shared/mocks/openaire.mock.ts | 1796 +++++++++++++++++ .../pagination/pagination.component.html | 6 +- .../shared/pagination/pagination.component.ts | 5 + src/app/shared/selector.util.ts | 27 + src/assets/i18n/en.json5 | 137 ++ 53 files changed, 6165 insertions(+), 12 deletions(-) create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-routing-paths.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-routing.module.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications.module.ts create mode 100644 src/app/core/openaire/broker/events/openaire-broker-event-rest.service.spec.ts create mode 100644 src/app/core/openaire/broker/events/openaire-broker-event-rest.service.ts create mode 100644 src/app/core/openaire/broker/models/openaire-broker-event-object.resource-type.ts create mode 100644 src/app/core/openaire/broker/models/openaire-broker-event.model.ts create mode 100644 src/app/core/openaire/broker/models/openaire-broker-topic-object.resource-type.ts create mode 100644 src/app/core/openaire/broker/models/openaire-broker-topic.model.ts create mode 100644 src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts create mode 100644 src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.ts create mode 100644 src/app/openaire/broker/events/openaire-broker-events.component.html create mode 100644 src/app/openaire/broker/events/openaire-broker-events.component.spec.ts create mode 100644 src/app/openaire/broker/events/openaire-broker-events.component.ts create mode 100644 src/app/openaire/broker/events/openaire-broker-events.scomponent.scss create mode 100644 src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.html create mode 100644 src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.scss create mode 100644 src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts create mode 100644 src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.actions.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.component.html create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.component.scss create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.component.spec.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.component.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.effects.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.reducer.spec.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.reducer.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.service.spec.ts create mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.service.ts create mode 100644 src/app/openaire/openaire-state.service.spec.ts create mode 100644 src/app/openaire/openaire-state.service.ts create mode 100644 src/app/openaire/openaire.effects.ts create mode 100644 src/app/openaire/openaire.module.ts create mode 100644 src/app/openaire/openaire.reducer.ts create mode 100644 src/app/openaire/selectors.ts create mode 100644 src/app/shared/mocks/openaire.mock.ts create mode 100644 src/app/shared/selector.util.ts diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html new file mode 100644 index 00000000000..5c8f8820a00 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html @@ -0,0 +1 @@ + diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts new file mode 100644 index 00000000000..ab7a08a695e --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts @@ -0,0 +1,26 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AdminNotificationsOpenaireEventsPageComponent } from './admin-notifications-openaire-events-page.component'; + +describe('AdminNotificationsOpenaireEventsPageComponent', () => { + let component: AdminNotificationsOpenaireEventsPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AdminNotificationsOpenaireEventsPageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminNotificationsOpenaireEventsPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create AdminNotificationsOpenaireEventsPageComponent', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts new file mode 100644 index 00000000000..df7b21dbdab --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-notification-openaire-events-page', + templateUrl: './admin-notifications-openaire-events-page.component.html' +}) +export class AdminNotificationsOpenaireEventsPageComponent { + +} diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts new file mode 100644 index 00000000000..b215013e11c --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; + +/** + * Interface for the route parameters. + */ +export interface AdminNotificationsOpenaireEventsPageParams { + pageId?: string; + pageSize?: number; + currentPage?: number; +} + +/** + * This class represents a resolver that retrieve the route data before the route is activated. + */ +@Injectable() +export class AdminNotificationsOpenaireEventsPageResolver implements Resolve { + + /** + * Method for resolving the parameters in the current route. + * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot + * @param {RouterStateSnapshot} state The current RouterStateSnapshot + * @returns AdminNotificationsOpenaireEventsPageParams Emits the route parameters + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsOpenaireEventsPageParams { + return { + pageId: route.queryParams.pageId, + pageSize: parseInt(route.queryParams.pageSize, 10), + currentPage: parseInt(route.queryParams.page, 10) + }; + } +} diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts new file mode 100644 index 00000000000..f8e02cabbfe --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; + +/** + * Interface for the route parameters. + */ +export interface AdminNotificationsOpenaireTopicsPageParams { + pageId?: string; + pageSize?: number; + currentPage?: number; +} + +/** + * This class represents a resolver that retrieve the route data before the route is activated. + */ +@Injectable() +export class AdminNotificationsOpenaireTopicsPageResolver implements Resolve { + + /** + * Method for resolving the parameters in the current route. + * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot + * @param {RouterStateSnapshot} state The current RouterStateSnapshot + * @returns AdminNotificationsOpenaireTopicsPageParams Emits the route parameters + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsOpenaireTopicsPageParams { + return { + pageId: route.queryParams.pageId, + pageSize: parseInt(route.queryParams.pageSize, 10), + currentPage: parseInt(route.queryParams.page, 10) + }; + } +} diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html new file mode 100644 index 00000000000..b1616cfe781 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html @@ -0,0 +1 @@ + diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts new file mode 100644 index 00000000000..712c7ba2c3d --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts @@ -0,0 +1,26 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AdminNotificationsOpenaireTopicsPageComponent } from './admin-notifications-openaire-topics-page.component'; + +describe('AdminNotificationsOpenaireTopicsPageComponent', () => { + let component: AdminNotificationsOpenaireTopicsPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AdminNotificationsOpenaireTopicsPageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminNotificationsOpenaireTopicsPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create AdminNotificationsOpenaireTopicsPageComponent', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts new file mode 100644 index 00000000000..5bf1832c595 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-notification-openairebroker-page', + templateUrl: './admin-notifications-openaire-topics-page.component.html' +}) +export class AdminNotificationsOpenaireTopicsPageComponent { + +} diff --git a/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts new file mode 100644 index 00000000000..ea7242adcb8 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts @@ -0,0 +1,8 @@ +import { URLCombiner } from '../../core/url-combiner/url-combiner'; +import { getNotificationsModuleRoute } from '../admin-routing-paths'; + +export const NOTIFICATIONS_EDIT_PATH = 'openaire-broker'; + +export function getNotificationsOpenairebrokerRoute(id: string) { + return new URLCombiner(getNotificationsModuleRoute(), NOTIFICATIONS_EDIT_PATH, id).toString(); +} diff --git a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts new file mode 100644 index 00000000000..2dfa938c4f7 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -0,0 +1,60 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AuthenticatedGuard } from '../../core/auth/authenticated.guard'; +import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver'; +import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service'; +import { NOTIFICATIONS_EDIT_PATH } from './admin-notifications-routing-paths'; +import { AdminNotificationsOpenaireTopicsPageComponent } from './admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component'; +import { AdminNotificationsOpenaireEventsPageComponent } from './admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component'; +import { AdminNotificationsOpenaireTopicsPageResolver } from './admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service'; +import { AdminNotificationsOpenaireEventsPageResolver } from './admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver'; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { + canActivate: [ AuthenticatedGuard ], + path: `${NOTIFICATIONS_EDIT_PATH}`, + component: AdminNotificationsOpenaireTopicsPageComponent, + pathMatch: 'full', + resolve: { + breadcrumb: I18nBreadcrumbResolver, + openaireBrokerTopicsParams: AdminNotificationsOpenaireTopicsPageResolver + }, + data: { + title: 'admin.notifications.openairebroker.page.title', + breadcrumbKey: 'admin.notifications.openairebroker', + showBreadcrumbsFluid: false + } + }, + { + canActivate: [ AuthenticatedGuard ], + path: `${NOTIFICATIONS_EDIT_PATH}/:id`, + component: AdminNotificationsOpenaireEventsPageComponent, + pathMatch: 'full', + resolve: { + breadcrumb: I18nBreadcrumbResolver, + openaireBrokerEventsParams: AdminNotificationsOpenaireEventsPageResolver + }, + data: { + title: 'admin.notifications.openaireevent.page.title', + breadcrumbKey: 'admin.notifications.openaireevent', + showBreadcrumbsFluid: false + } + } + ]) + ], + providers: [ + I18nBreadcrumbResolver, + I18nBreadcrumbsService, + AdminNotificationsOpenaireTopicsPageResolver, + AdminNotificationsOpenaireEventsPageResolver + ] +}) +/** + * Routing module for the Notifications section of the admin sidebar + */ +export class AdminNotificationsRoutingModule { + +} diff --git a/src/app/admin/admin-notifications/admin-notifications.module.ts b/src/app/admin/admin-notifications/admin-notifications.module.ts new file mode 100644 index 00000000000..9894dac2335 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications.module.ts @@ -0,0 +1,29 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { CoreModule } from '../../core/core.module'; +import { SharedModule } from '../../shared/shared.module'; +import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module'; +import { AdminNotificationsOpenaireTopicsPageComponent } from './admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component'; +import { AdminNotificationsOpenaireEventsPageComponent } from './admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component'; +import { OpenaireModule } from '../../openaire/openaire.module'; + +@NgModule({ + imports: [ + CommonModule, + SharedModule, + CoreModule.forRoot(), + AdminNotificationsRoutingModule, + OpenaireModule + ], + declarations: [ + AdminNotificationsOpenaireTopicsPageComponent, + AdminNotificationsOpenaireEventsPageComponent + ], + entryComponents: [] +}) +/** + * This module handles all components related to the notifications pages + */ +export class AdminNotificationsModule { + +} diff --git a/src/app/admin/admin-routing-paths.ts b/src/app/admin/admin-routing-paths.ts index 3168ea93c92..30f801cecb7 100644 --- a/src/app/admin/admin-routing-paths.ts +++ b/src/app/admin/admin-routing-paths.ts @@ -2,7 +2,12 @@ import { URLCombiner } from '../core/url-combiner/url-combiner'; import { getAdminModuleRoute } from '../app-routing-paths'; export const REGISTRIES_MODULE_PATH = 'registries'; +export const NOTIFICATIONS_MODULE_PATH = 'notifications'; export function getRegistriesModuleRoute() { return new URLCombiner(getAdminModuleRoute(), REGISTRIES_MODULE_PATH).toString(); } + +export function getNotificationsModuleRoute() { + return new URLCombiner(getAdminModuleRoute(), NOTIFICATIONS_MODULE_PATH).toString(); +} diff --git a/src/app/admin/admin-routing.module.ts b/src/app/admin/admin-routing.module.ts index ee5cb8737bc..782a7faa380 100644 --- a/src/app/admin/admin-routing.module.ts +++ b/src/app/admin/admin-routing.module.ts @@ -6,11 +6,16 @@ import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.reso import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component'; import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service'; import { AdminCurationTasksComponent } from './admin-curation-tasks/admin-curation-tasks.component'; -import { REGISTRIES_MODULE_PATH } from './admin-routing-paths'; +import { REGISTRIES_MODULE_PATH, NOTIFICATIONS_MODULE_PATH } from './admin-routing-paths'; @NgModule({ imports: [ RouterModule.forChild([ + { + path: NOTIFICATIONS_MODULE_PATH, + loadChildren: () => import('./admin-notifications/admin-notifications.module') + .then((m) => m.AdminNotificationsModule), + }, { path: REGISTRIES_MODULE_PATH, loadChildren: () => import('./admin-registries/admin-registries.module') diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.ts index c81b2e6e93b..a2a7eb30b56 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.ts @@ -276,7 +276,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { // link: '' // } as LinkMenuItemModel, // icon: 'chart-bar', - // index: 8 + // index: 9 // }, /* Control Panel */ @@ -291,7 +291,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { // link: '' // } as LinkMenuItemModel, // icon: 'cogs', - // index: 9 + // index: 10 // }, /* Processes */ @@ -305,7 +305,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { link: '/processes' } as LinkMenuItemModel, icon: 'terminal', - index: 10 + index: 11 }, ]; menuList.forEach((menuSection) => this.menuService.addSection(this.menuID, Object.assign(menuSection, { @@ -464,6 +464,29 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { createSiteAdministratorMenuSections() { this.authorizationService.isAuthorized(FeatureID.AdministratorOf).subscribe((authorized) => { const menuList = [ + /* Notifications */ + { + id: 'notifications', + active: false, + visible: authorized, + model: { + type: MenuItemType.TEXT, + text: 'menu.section.notifications' + } as TextMenuItemModel, + icon: 'bell', + index: 4 + }, + { + id: 'notifications_openair_broker', + parentID: 'notifications', + active: false, + visible: authorized, + model: { + type: MenuItemType.LINK, + text: 'menu.section.notifications_openaire_broker', + link: '/admin/notifications/openaire-broker' + } as LinkMenuItemModel, + }, /* Admin Search */ { id: 'admin_search', @@ -475,7 +498,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { link: '/admin/search' } as LinkMenuItemModel, icon: 'search', - index: 5 + index: 6 }, /* Registries */ { @@ -487,7 +510,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { text: 'menu.section.registries' } as TextMenuItemModel, icon: 'list', - index: 6 + index: 7 }, { id: 'registries_metadata', @@ -523,7 +546,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { link: 'admin/curation-tasks' } as LinkMenuItemModel, icon: 'filter', - index: 7 + index: 8 }, /* Workflow */ @@ -537,7 +560,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { link: '/admin/workflow' } as LinkMenuItemModel, icon: 'user-check', - index: 11 + index: 12 }, ]; @@ -600,7 +623,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { text: 'menu.section.access_control' } as TextMenuItemModel, icon: 'key', - index: 4 + index: 5 }, ]; diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 8d8a614a899..928d34c48e4 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -162,6 +162,8 @@ import { SearchConfig } from './shared/search/search-filters/search-config.model import { SequenceService } from './shared/sequence.service'; import { GroupDataService } from './eperson/group-data.service'; import { SubmissionAccessesModel } from './config/models/config-submission-accesses.model'; +import { OpenaireBrokerTopicObject } from './openaire/broker/models/openaire-broker-topic.model'; +import { OpenaireBrokerEventObject } from './openaire/broker/models/openaire-broker-event.model'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -343,6 +345,8 @@ export const models = ShortLivedToken, Registration, UsageReport, + OpenaireBrokerTopicObject, + OpenaireBrokerEventObject, Root, SearchConfig, SubmissionAccessesModel diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index 6bad02e7761..0b4f3af4b45 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -38,7 +38,7 @@ import { FindListOptions, PatchRequest, PutRequest, - DeleteRequest + DeleteRequest, DeleteByIDRequest, PostRequest } from './request.models'; import { RequestService } from './request.service'; import { RestRequestMethod } from './rest-request-method'; @@ -579,6 +579,53 @@ export abstract class DataService implements UpdateDa return result$; } + /** + * Perform a post on an endpoint related item with ID. Ex.: endpoint//related?item= + * @param itemId The item id + * @param relatedItemId The related item Id + * @param body The optional POST body + * @return the RestResponse as an Observable + */ + public postOnRelated(itemId: string, relatedItemId: string, body?: any) { + const requestId = this.requestService.generateRequestId(); + const hrefObs = this.getIDHrefObs(itemId); + + hrefObs.pipe( + take(1) + ).subscribe((href: string) => { + const request = new PostRequest(requestId, href + '/related?item=' + relatedItemId, body); + if (hasValue(this.responseMsToLive)) { + request.responseMsToLive = this.responseMsToLive; + } + this.requestService.send(request); + }); + + return this.rdbService.buildFromRequestUUID(requestId); + } + + /** + * Perform a delete on an endpoint related item. Ex.: endpoint//related + * @param itemId The item id + * @return the RestResponse as an Observable + */ + public deleteOnRelated(itemId: string): Observable> { + const requestId = this.requestService.generateRequestId(); + const hrefObs = this.getIDHrefObs(itemId); + + hrefObs.pipe( + find((href: string) => hasValue(href)), + map((href: string) => { + const request = new DeleteByIDRequest(requestId, href + '/related', itemId); + if (hasValue(this.responseMsToLive)) { + request.responseMsToLive = this.responseMsToLive; + } + this.requestService.send(request); + }) + ).subscribe(); + + return this.rdbService.buildFromRequestUUID(requestId); + } + /** * Delete an existing DSpace Object on the server * @param objectId The id of the object to be removed diff --git a/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.spec.ts b/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.spec.ts new file mode 100644 index 00000000000..2d0d236330e --- /dev/null +++ b/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.spec.ts @@ -0,0 +1,246 @@ +import { HttpClient } from '@angular/common/http'; + +import { TestScheduler } from 'rxjs/testing'; +import { of as observableOf } from 'rxjs'; +import { cold, getTestScheduler } from 'jasmine-marbles'; + +import { RequestService } from '../../../data/request.service'; +import { buildPaginatedList } from '../../../data/paginated-list.model'; +import { RequestEntry } from '../../../data/request.reducer'; +import { FindListOptions } from '../../../data/request.models'; +import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../cache/object-cache.service'; +import { RestResponse } from '../../../cache/response.models'; +import { PageInfo } from '../../../shared/page-info.model'; +import { HALEndpointService } from '../../../shared/hal-endpoint.service'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; +import { OpenaireBrokerEventRestService } from './openaire-broker-event-rest.service'; +import { + openaireBrokerEventObjectMissingPid, + openaireBrokerEventObjectMissingPid2, + openaireBrokerEventObjectMissingProjectFound +} from '../../../../shared/mocks/openaire.mock'; +import { ReplaceOperation } from 'fast-json-patch'; + +describe('OpenaireBrokerEventRestService', () => { + let scheduler: TestScheduler; + let service: OpenaireBrokerEventRestService; + let serviceASAny: any; + let responseCacheEntry: RequestEntry; + let responseCacheEntryB: RequestEntry; + let responseCacheEntryC: RequestEntry; + let requestService: RequestService; + let rdbService: RemoteDataBuildService; + let objectCache: ObjectCacheService; + let halService: HALEndpointService; + let notificationsService: NotificationsService; + let http: HttpClient; + let comparator: any; + + const endpointURL = 'https://rest.api/rest/api/integration/nbtopics'; + const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; + const topic = 'ENRICH!MORE!PID'; + + const pageInfo = new PageInfo(); + const array = [ openaireBrokerEventObjectMissingPid, openaireBrokerEventObjectMissingPid2 ]; + const paginatedList = buildPaginatedList(pageInfo, array); + const brokerEventObjectRD = createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingPid); + const brokerEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingProjectFound); + const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); + + const status = 'ACCEPTED'; + const operation: ReplaceOperation[] = [ + { + path: '/status', + op: 'replace', + value: status + } + ]; + + beforeEach(() => { + scheduler = getTestScheduler(); + + responseCacheEntry = new RequestEntry(); + responseCacheEntry.request = { href: 'https://rest.api/' } as any; + responseCacheEntry.response = new RestResponse(true, 200, 'Success'); + requestService = jasmine.createSpyObj('requestService', { + generateRequestId: requestUUID, + send: true, + removeByHrefSubstring: {}, + getByHref: jasmine.createSpy('getByHref'), + getByUUID: jasmine.createSpy('getByUUID') + }); + + responseCacheEntryB = new RequestEntry(); + responseCacheEntryB.request = { href: 'https://rest.api/' } as any; + responseCacheEntryB.response = new RestResponse(true, 201, 'Created'); + + responseCacheEntryC = new RequestEntry(); + responseCacheEntryC.request = { href: 'https://rest.api/' } as any; + responseCacheEntryC.response = new RestResponse(true, 204, 'No Content'); + + rdbService = jasmine.createSpyObj('rdbService', { + buildSingle: cold('(a)', { + a: brokerEventObjectRD + }), + buildList: cold('(a)', { + a: paginatedListRD + }), + buildFromRequestUUID: jasmine.createSpy('buildFromRequestUUID') + }); + + objectCache = {} as ObjectCacheService; + halService = jasmine.createSpyObj('halService', { + getEndpoint: cold('a|', { a: endpointURL }) + }); + + notificationsService = {} as NotificationsService; + http = {} as HttpClient; + comparator = {} as any; + + service = new OpenaireBrokerEventRestService( + requestService, + rdbService, + objectCache, + halService, + notificationsService, + http, + comparator + ); + + serviceASAny = service; + + spyOn(serviceASAny.dataService, 'searchBy').and.callThrough(); + spyOn(serviceASAny.dataService, 'findById').and.callThrough(); + spyOn(serviceASAny.dataService, 'patch').and.callThrough(); + spyOn(serviceASAny.dataService, 'postOnRelated').and.callThrough(); + spyOn(serviceASAny.dataService, 'deleteOnRelated').and.callThrough(); + }); + + describe('getEventsByTopic', () => { + beforeEach(() => { + serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntry)); + serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntry)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectRD)); + }); + + it('should proxy the call to dataservice.searchBy', () => { + const options: FindListOptions = { + searchParams: [ + { + fieldName: 'topic', + fieldValue: topic + } + ] + }; + service.getEventsByTopic(topic); + expect(serviceASAny.dataService.searchBy).toHaveBeenCalledWith('findByTopic', options, true, true); + }); + + it('should return a RemoteData> for the object with the given Topic', () => { + const result = service.getEventsByTopic(topic); + const expected = cold('(a)', { + a: paginatedListRD + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getEvent', () => { + beforeEach(() => { + serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntry)); + serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntry)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectRD)); + }); + + it('should proxy the call to dataservice.findById', () => { + service.getEvent(openaireBrokerEventObjectMissingPid.id).subscribe( + (res) => { + expect(serviceASAny.dataService.findById).toHaveBeenCalledWith(openaireBrokerEventObjectMissingPid.id, true, true); + } + ); + }); + + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getEvent(openaireBrokerEventObjectMissingPid.id); + const expected = cold('(a)', { + a: brokerEventObjectRD + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('patchEvent', () => { + beforeEach(() => { + serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntry)); + serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntry)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectRD)); + }); + + it('should proxy the call to dataservice.patch', () => { + service.patchEvent(status, openaireBrokerEventObjectMissingPid).subscribe( + (res) => { + expect(serviceASAny.dataService.patch).toHaveBeenCalledWith(openaireBrokerEventObjectMissingPid, operation); + } + ); + }); + + it('should return a RemoteData with HTTP 200', () => { + const result = service.patchEvent(status, openaireBrokerEventObjectMissingPid); + const expected = cold('(a|)', { + a: createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingPid) + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('boundProject', () => { + beforeEach(() => { + serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntryB)); + serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntryB)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectMissingProjectRD)); + }); + + it('should proxy the call to dataservice.postOnRelated', () => { + service.boundProject(openaireBrokerEventObjectMissingProjectFound.id, requestUUID).subscribe( + (res) => { + expect(serviceASAny.dataService.postOnRelated).toHaveBeenCalledWith(openaireBrokerEventObjectMissingProjectFound.id, requestUUID); + } + ); + }); + + it('should return a RestResponse with HTTP 201', () => { + const result = service.boundProject(openaireBrokerEventObjectMissingProjectFound.id, requestUUID); + const expected = cold('(a|)', { + a: createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingProjectFound) + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('removeProject', () => { + beforeEach(() => { + serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntryC)); + serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntryC)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(createSuccessfulRemoteDataObject({}))); + }); + + it('should proxy the call to dataservice.deleteOnRelated', () => { + service.removeProject(openaireBrokerEventObjectMissingProjectFound.id).subscribe( + (res) => { + expect(serviceASAny.dataService.deleteOnRelated).toHaveBeenCalledWith(openaireBrokerEventObjectMissingProjectFound.id); + } + ); + }); + + it('should return a RestResponse with HTTP 204', () => { + const result = service.removeProject(openaireBrokerEventObjectMissingProjectFound.id); + const expected = cold('(a|)', { + a: createSuccessfulRemoteDataObject({}) + }); + expect(result).toBeObservable(expected); + }); + }); + +}); diff --git a/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.ts b/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.ts new file mode 100644 index 00000000000..6e944c8038c --- /dev/null +++ b/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.ts @@ -0,0 +1,185 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Store } from '@ngrx/store'; + +import { Observable } from 'rxjs'; + +import { CoreState } from '../../../core.reducers'; +import { HALEndpointService } from '../../../shared/hal-endpoint.service'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; +import { RestResponse } from '../../../cache/response.models'; +import { ObjectCacheService } from '../../../cache/object-cache.service'; +import { dataService } from '../../../cache/builders/build-decorators'; +import { RequestService } from '../../../data/request.service'; +import { FindListOptions } from '../../../data/request.models'; +import { DataService } from '../../../data/data.service'; +import { ChangeAnalyzer } from '../../../data/change-analyzer'; +import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; +import { RemoteData } from '../../../data/remote-data'; +import { OpenaireBrokerEventObject } from '../models/openaire-broker-event.model'; +import { OPENAIRE_BROKER_EVENT_OBJECT } from '../models/openaire-broker-event-object.resource-type'; +import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model'; +import { PaginatedList } from '../../../data/paginated-list.model'; +import { ReplaceOperation } from 'fast-json-patch'; +import { NoContent } from '../../../shared/NoContent.model'; + +/* tslint:disable:max-classes-per-file */ + +/** + * A private DataService implementation to delegate specific methods to. + */ +class DataServiceImpl extends DataService { + /** + * The REST endpoint. + */ + protected linkPath = 'nbevents'; + + /** + * Initialize service variables + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {Store} store + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {ChangeAnalyzer} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: ChangeAnalyzer) { + super(); + } +} + +/** + * The service handling all OpenAIRE Broker topic REST requests. + */ +@Injectable() +@dataService(OPENAIRE_BROKER_EVENT_OBJECT) +export class OpenaireBrokerEventRestService { + /** + * A private DataService implementation to delegate specific methods to. + */ + private dataService: DataServiceImpl; + + /** + * Initialize service variables + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {DefaultChangeAnalyzer} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + } + + /** + * Return the list of OpenAIRE Broker events by topic. + * + * @param topic + * The OpenAIRE Broker topic + * @param options + * Find list options object. + * @param linksToFollow + * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. + * @return Observable>> + * The list of OpenAIRE Broker events. + */ + public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { + options.searchParams = [ + { + fieldName: 'topic', + fieldValue: topic + } + ]; + return this.dataService.searchBy('findByTopic', options, true, true, ...linksToFollow); + } + + /** + * Clear findByTopic requests from cache + */ + public clearFindByTopicRequests() { + this.requestService.removeByHrefSubstring('findByTopic'); + } + + /** + * Return a single OpenAIRE Broker event. + * + * @param id + * The OpenAIRE Broker event id + * @param linksToFollow + * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + * @return Observable> + * The OpenAIRE Broker event. + */ + public getEvent(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { + return this.dataService.findById(id, true, true, ...linksToFollow); + } + + /** + * Save the new status of an OpenAIRE Broker event. + * + * @param status + * The new status + * @param dso OpenaireBrokerEventObject + * The event item + * @param reason + * The optional reason (not used for now; for future implementation) + * @return Observable + * The REST response. + */ + public patchEvent(status, dso, reason?: string): Observable> { + const operation: ReplaceOperation[] = [ + { + path: '/status', + op: 'replace', + value: status + } + ]; + return this.dataService.patch(dso, operation); + } + + /** + * Bound a project to an OpenAIRE Broker event publication. + * + * @param itemId + * The Id of the OpenAIRE Broker event + * @param projectId + * The project Id to bound + * @return Observable + * The REST response. + */ + public boundProject(itemId: string, projectId: string): Observable> { + return this.dataService.postOnRelated(itemId, projectId); + } + + /** + * Remove a project from an OpenAIRE Broker event publication. + * + * @param itemId + * The Id of the OpenAIRE Broker event + * @return Observable + * The REST response. + */ + public removeProject(itemId: string): Observable> { + return this.dataService.deleteOnRelated(itemId); + } +} diff --git a/src/app/core/openaire/broker/models/openaire-broker-event-object.resource-type.ts b/src/app/core/openaire/broker/models/openaire-broker-event-object.resource-type.ts new file mode 100644 index 00000000000..c0be0071ebc --- /dev/null +++ b/src/app/core/openaire/broker/models/openaire-broker-event-object.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../../shared/resource-type'; + +/** + * The resource type for the OpenAIRE Broker event + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const OPENAIRE_BROKER_EVENT_OBJECT = new ResourceType('nbevent'); diff --git a/src/app/core/openaire/broker/models/openaire-broker-event.model.ts b/src/app/core/openaire/broker/models/openaire-broker-event.model.ts new file mode 100644 index 00000000000..40c65412f52 --- /dev/null +++ b/src/app/core/openaire/broker/models/openaire-broker-event.model.ts @@ -0,0 +1,157 @@ +import { Observable } from 'rxjs'; +import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; +import { CacheableObject } from '../../../cache/object-cache.reducer'; +import { OPENAIRE_BROKER_EVENT_OBJECT } from './openaire-broker-event-object.resource-type'; +import { excludeFromEquals } from '../../../utilities/equals.decorators'; +import { ResourceType } from '../../../shared/resource-type'; +import { HALLink } from '../../../shared/hal-link.model'; +import { Item } from '../../../shared/item.model'; +import { ITEM } from '../../../shared/item.resource-type'; +import { link, typedObject } from '../../../cache/builders/build-decorators'; +import { RemoteData } from '../../../data/remote-data'; + +/** + * The interface representing the OpenAIRE Broker event message + */ +export interface OpenaireBrokerEventMessageObject { + /** + * The type of 'value' + */ + type: string; + + /** + * The value suggested by OpenAIRE + */ + value: string; + + /** + * The abstract suggested by OpenAIRE + */ + abstract: string; + + /** + * The project acronym suggested by OpenAIRE + */ + acronym: string; + + /** + * The project code suggested by OpenAIRE + */ + code: string; + + /** + * The project funder suggested by OpenAIRE + */ + funder: string; + + /** + * The project program suggested by OpenAIRE + */ + fundingProgram?: string; + + /** + * The project jurisdiction suggested by OpenAIRE + */ + jurisdiction: string; + + /** + * The project title suggested by OpenAIRE + */ + title: string; + + /** + * The OpenAIRE ID. + */ + openaireId: string; + +} + +/** + * The interface representing the OpenAIRE Broker event model + */ +@typedObject +export class OpenaireBrokerEventObject implements CacheableObject { + /** + * A string representing the kind of object, e.g. community, item, … + */ + static type = OPENAIRE_BROKER_EVENT_OBJECT; + + /** + * The OpenAIRE Broker event uuid inside DSpace + */ + @autoserialize + id: string; + + /** + * The universally unique identifier of this OpenAIRE Broker event + */ + @autoserializeAs(String, 'id') + uuid: string; + + /** + * The OpenAIRE Broker event original id (ex.: the source archive OAI-PMH identifier) + */ + @autoserialize + originalId: string; + + /** + * The title of the article to which the suggestion refers + */ + @autoserialize + title: string; + + /** + * Reliability of the suggestion (of the data inside 'message') + */ + @autoserialize + trust: number; + + /** + * The timestamp OpenAIRE Broker event was saved in DSpace + */ + @autoserialize + eventDate: string; + + /** + * The OpenAIRE Broker event status (ACCEPTED, REJECTED, DISCARDED, PENDING) + */ + @autoserialize + status: string; + + /** + * The suggestion data. Data may vary depending on the topic + */ + @autoserialize + message: OpenaireBrokerEventMessageObject; + + /** + * The type of this ConfigObject + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + + /** + * The links to all related resources returned by the rest api. + */ + @deserialize + _links: { + self: HALLink, + target: HALLink, + related: HALLink + }; + + /** + * The related publication DSpace item + * Will be undefined unless the {@item HALLink} has been resolved. + */ + @link(ITEM) + target?: Observable>; + + /** + * The related project for this Event + * Will be undefined unless the {@related HALLink} has been resolved. + */ + @link(ITEM) + related?: Observable>; +} diff --git a/src/app/core/openaire/broker/models/openaire-broker-topic-object.resource-type.ts b/src/app/core/openaire/broker/models/openaire-broker-topic-object.resource-type.ts new file mode 100644 index 00000000000..58ceb4e671e --- /dev/null +++ b/src/app/core/openaire/broker/models/openaire-broker-topic-object.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../../shared/resource-type'; + +/** + * The resource type for the OpenAIRE Broker topic + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const OPENAIRE_BROKER_TOPIC_OBJECT = new ResourceType('nbtopic'); diff --git a/src/app/core/openaire/broker/models/openaire-broker-topic.model.ts b/src/app/core/openaire/broker/models/openaire-broker-topic.model.ts new file mode 100644 index 00000000000..3f286e5fead --- /dev/null +++ b/src/app/core/openaire/broker/models/openaire-broker-topic.model.ts @@ -0,0 +1,58 @@ +import { autoserialize, deserialize } from 'cerialize'; + +import { CacheableObject } from '../../../cache/object-cache.reducer'; +import { OPENAIRE_BROKER_TOPIC_OBJECT } from './openaire-broker-topic-object.resource-type'; +import { excludeFromEquals } from '../../../utilities/equals.decorators'; +import { ResourceType } from '../../../shared/resource-type'; +import { HALLink } from '../../../shared/hal-link.model'; +import { typedObject } from '../../../cache/builders/build-decorators'; + +/** + * The interface representing the OpenAIRE Broker topic model + */ +@typedObject +export class OpenaireBrokerTopicObject implements CacheableObject { + /** + * A string representing the kind of object, e.g. community, item, … + */ + static type = OPENAIRE_BROKER_TOPIC_OBJECT; + + /** + * The OpenAIRE Broker topic id + */ + @autoserialize + id: string; + + /** + * The OpenAIRE Broker topic name to display + */ + @autoserialize + name: string; + + /** + * The date of the last udate from OpenAIRE + */ + @autoserialize + lastEvent: string; + + /** + * The total number of suggestions provided by OpenAIRE for this topic + */ + @autoserialize + totalEvents: number; + + /** + * The type of this ConfigObject + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + + /** + * The links to all related resources returned by the rest api. + */ + @deserialize + _links: { + self: HALLink, + }; +} diff --git a/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts b/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts new file mode 100644 index 00000000000..87aa0b42f0c --- /dev/null +++ b/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts @@ -0,0 +1,127 @@ +import { HttpClient } from '@angular/common/http'; + +import { TestScheduler } from 'rxjs/testing'; +import { of as observableOf } from 'rxjs'; +import { cold, getTestScheduler } from 'jasmine-marbles'; + +import { RequestService } from '../../../data/request.service'; +import { buildPaginatedList } from '../../../data/paginated-list.model'; +import { RequestEntry } from '../../../data/request.reducer'; +import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../cache/object-cache.service'; +import { RestResponse } from '../../../cache/response.models'; +import { PageInfo } from '../../../shared/page-info.model'; +import { HALEndpointService } from '../../../shared/hal-endpoint.service'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; +import { OpenaireBrokerTopicRestService } from './openaire-broker-topic-rest.service'; +import { + openaireBrokerTopicObjectMoreAbstract, + openaireBrokerTopicObjectMorePid +} from '../../../../shared/mocks/openaire.mock'; + +describe('OpenaireBrokerTopicRestService', () => { + let scheduler: TestScheduler; + let service: OpenaireBrokerTopicRestService; + let responseCacheEntry: RequestEntry; + let requestService: RequestService; + let rdbService: RemoteDataBuildService; + let objectCache: ObjectCacheService; + let halService: HALEndpointService; + let notificationsService: NotificationsService; + let http: HttpClient; + let comparator: any; + + const endpointURL = 'https://rest.api/rest/api/integration/nbtopics'; + const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; + + const pageInfo = new PageInfo(); + const array = [ openaireBrokerTopicObjectMorePid, openaireBrokerTopicObjectMoreAbstract ]; + const paginatedList = buildPaginatedList(pageInfo, array); + const brokerTopicObjectRD = createSuccessfulRemoteDataObject(openaireBrokerTopicObjectMorePid); + const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); + + beforeEach(() => { + scheduler = getTestScheduler(); + + responseCacheEntry = new RequestEntry(); + responseCacheEntry.response = new RestResponse(true, 200, 'Success'); + requestService = jasmine.createSpyObj('requestService', { + generateRequestId: requestUUID, + send: true, + removeByHrefSubstring: {}, + getByHref: observableOf(responseCacheEntry), + getByUUID: observableOf(responseCacheEntry), + }); + + rdbService = jasmine.createSpyObj('rdbService', { + buildSingle: cold('(a)', { + a: brokerTopicObjectRD + }), + buildList: cold('(a)', { + a: paginatedListRD + }), + }); + + objectCache = {} as ObjectCacheService; + halService = jasmine.createSpyObj('halService', { + getEndpoint: cold('a|', { a: endpointURL }) + }); + + notificationsService = {} as NotificationsService; + http = {} as HttpClient; + comparator = {} as any; + + service = new OpenaireBrokerTopicRestService( + requestService, + rdbService, + objectCache, + halService, + notificationsService, + http, + comparator + ); + + spyOn((service as any).dataService, 'findAllByHref').and.callThrough(); + spyOn((service as any).dataService, 'findByHref').and.callThrough(); + }); + + describe('getTopics', () => { + it('should proxy the call to dataservice.findAllByHref', (done) => { + service.getTopics().subscribe( + (res) => { + expect((service as any).dataService.findAllByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); + } + ); + done(); + }); + + it('should return a RemoteData> for the object with the given URL', () => { + const result = service.getTopics(); + const expected = cold('(a)', { + a: paginatedListRD + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getTopic', () => { + it('should proxy the call to dataservice.findByHref', (done) => { + service.getTopic(openaireBrokerTopicObjectMorePid.id).subscribe( + (res) => { + expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + openaireBrokerTopicObjectMorePid.id, true, true); + } + ); + done(); + }); + + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getTopic(openaireBrokerTopicObjectMorePid.id); + const expected = cold('(a)', { + a: brokerTopicObjectRD + }); + expect(result).toBeObservable(expected); + }); + }); + +}); diff --git a/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.ts b/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.ts new file mode 100644 index 00000000000..3fe39174858 --- /dev/null +++ b/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.ts @@ -0,0 +1,133 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Store } from '@ngrx/store'; + +import { Observable } from 'rxjs'; +import { mergeMap, take } from 'rxjs/operators'; + +import { CoreState } from '../../../core.reducers'; +import { HALEndpointService } from '../../../shared/hal-endpoint.service'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../cache/object-cache.service'; +import { dataService } from '../../../cache/builders/build-decorators'; +import { RequestService } from '../../../data/request.service'; +import { FindListOptions } from '../../../data/request.models'; +import { DataService } from '../../../data/data.service'; +import { ChangeAnalyzer } from '../../../data/change-analyzer'; +import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; +import { RemoteData } from '../../../data/remote-data'; +import { OpenaireBrokerTopicObject } from '../models/openaire-broker-topic.model'; +import { OPENAIRE_BROKER_TOPIC_OBJECT } from '../models/openaire-broker-topic-object.resource-type'; +import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model'; +import { PaginatedList } from '../../../data/paginated-list.model'; + +/* tslint:disable:max-classes-per-file */ + +/** + * A private DataService implementation to delegate specific methods to. + */ +class DataServiceImpl extends DataService { + /** + * The REST endpoint. + */ + protected linkPath = 'nbtopics'; + + /** + * Initialize service variables + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {Store} store + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {ChangeAnalyzer} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: ChangeAnalyzer) { + super(); + } +} + +/** + * The service handling all OpenAIRE Broker topic REST requests. + */ +@Injectable() +@dataService(OPENAIRE_BROKER_TOPIC_OBJECT) +export class OpenaireBrokerTopicRestService { + /** + * A private DataService implementation to delegate specific methods to. + */ + private dataService: DataServiceImpl; + + /** + * Initialize service variables + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {DefaultChangeAnalyzer} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + } + + /** + * Return the list of OpenAIRE Broker topics. + * + * @param options + * Find list options object. + * @param linksToFollow + * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. + * @return Observable>> + * The list of OpenAIRE Broker topics. + */ + public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { + return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( + take(1), + mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), + ); + } + + /** + * Clear FindAll topics requests from cache + */ + public clearFindAllTopicsRequests() { + this.requestService.setStaleByHrefSubstring('nbtopics'); + } + + /** + * Return a single OpenAIRE Broker topic. + * + * @param id + * The OpenAIRE Broker topic id + * @param linksToFollow + * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. + * @return Observable> + * The OpenAIRE Broker topic. + */ + public getTopic(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { + const options = {}; + return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( + take(1), + mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...linksToFollow)) + ); + } +} diff --git a/src/app/openaire/broker/events/openaire-broker-events.component.html b/src/app/openaire/broker/events/openaire-broker-events.component.html new file mode 100644 index 00000000000..05d77222911 --- /dev/null +++ b/src/app/openaire/broker/events/openaire-broker-events.component.html @@ -0,0 +1,207 @@ +
+
+
+

{{'openaire.events.title'| translate}}

+

{{'openaire.broker.events.description'| translate}}

+

+ + + {{'openaire.broker.events.back' | translate}} + +

+
+
+
+
+

+ {{'openaire.broker.events.topic' | translate}} {{this.showTopic}} +

+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
{{'openaire.broker.event.table.trust' | translate}}{{'openaire.broker.event.table.publication' | translate}}{{'openaire.broker.event.table.details' | translate}}{{'openaire.broker.event.table.project-details' | translate}}{{'openaire.broker.event.table.actions' | translate}}
{{eventElement?.event?.trust}} + {{eventElement.title}} + {{eventElement.title}} + +

{{'openaire.broker.event.table.pidtype' | translate}} {{eventElement.event.message.type}}

+

{{'openaire.broker.event.table.pidvalue' | translate}}
+ + {{eventElement.event.message.value}} + + {{eventElement.event.message.value}} +

+
+

{{'openaire.broker.event.table.subjectValue' | translate}}
{{eventElement.event.message.value}}

+
+

+ {{'openaire.broker.event.table.abstract' | translate}}
+ {{eventElement.event.message.abstract}} +

+ +
+

+ {{'openaire.broker.event.table.suggestedProject' | translate}} +

+

+ {{'openaire.broker.event.table.project' | translate}}
+ {{eventElement.event.message.title}} +

+

+ {{'openaire.broker.event.table.acronym' | translate}} {{eventElement.event.message.acronym}}
+ {{'openaire.broker.event.table.code' | translate}} {{eventElement.event.message.code}}
+ {{'openaire.broker.event.table.funder' | translate}} {{eventElement.event.message.funder}}
+ {{'openaire.broker.event.table.fundingProgram' | translate}} {{eventElement.event.message.fundingProgram}}
+ {{'openaire.broker.event.table.jurisdiction' | translate}} {{eventElement.event.message.jurisdiction}} +

+
+
+ {{(eventElement.hasProject ? 'openaire.broker.event.project.found' : 'openaire.broker.event.project.notFound') | translate}} + {{eventElement.handle}} +
+ + +
+
+
+
+ + + + +
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + diff --git a/src/app/openaire/broker/events/openaire-broker-events.component.spec.ts b/src/app/openaire/broker/events/openaire-broker-events.component.spec.ts new file mode 100644 index 00000000000..267f6a82423 --- /dev/null +++ b/src/app/openaire/broker/events/openaire-broker-events.component.spec.ts @@ -0,0 +1,332 @@ +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { CommonModule } from '@angular/common'; +import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing'; +import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { of as observableOf } from 'rxjs'; +import { OpenaireBrokerEventRestService } from '../../../core/openaire/broker/events/openaire-broker-event-rest.service'; +import { OpenaireBrokerEventsComponent } from './openaire-broker-events.component'; +import { + getMockOpenaireBrokerEventRestService, + ItemMockPid10, + ItemMockPid8, + ItemMockPid9, + openaireBrokerEventObjectMissingProjectFound, + openaireBrokerEventObjectMissingProjectNotFound, + OpenaireMockDspaceObject +} from '../../../shared/mocks/openaire.mock'; +import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { getMockTranslateService } from '../../../shared/mocks/translate.service.mock'; +import { createTestComponent } from '../../../shared/testing/utils.test'; +import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; +import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { OpenaireBrokerEventObject } from '../../../core/openaire/broker/models/openaire-broker-event.model'; +import { OpenaireBrokerEventData } from '../project-entry-import-modal/project-entry-import-modal.component'; +import { TestScheduler } from 'rxjs/testing'; +import { getTestScheduler } from 'jasmine-marbles'; +import { followLink } from '../../../shared/utils/follow-link-config.model'; +import { PageInfo } from '../../../core/shared/page-info.model'; +import { buildPaginatedList } from '../../../core/data/paginated-list.model'; +import { + createNoContentRemoteDataObject$, + createSuccessfulRemoteDataObject, + createSuccessfulRemoteDataObject$ +} from '../../../shared/remote-data.utils'; +import { FindListOptions } from '../../../core/data/request.models'; +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { PaginationService } from '../../../core/pagination/pagination.service'; +import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; + +describe('OpenaireBrokerEventsComponent test suite', () => { + let fixture: ComponentFixture; + let comp: OpenaireBrokerEventsComponent; + let compAsAny: any; + let scheduler: TestScheduler; + + const modalStub = { + open: () => ( {result: new Promise((res, rej) => 'do')} ), + close: () => null, + dismiss: () => null + }; + const openaireBrokerEventRestServiceStub: any = getMockOpenaireBrokerEventRestService(); + const activatedRouteParams = { + openaireBrokerEventsParams: { + currentPage: 0, + pageSize: 10 + } + }; + const activatedRouteParamsMap = { + id: 'ENRICH!MISSING!PROJECT' + }; + + const events: OpenaireBrokerEventObject[] = [ + openaireBrokerEventObjectMissingProjectFound, + openaireBrokerEventObjectMissingProjectNotFound + ]; + const paginationService = new PaginationServiceStub(); + + function getOpenAireBrokerEventData1(): OpenaireBrokerEventData { + return { + event: openaireBrokerEventObjectMissingProjectFound, + id: openaireBrokerEventObjectMissingProjectFound.id, + title: openaireBrokerEventObjectMissingProjectFound.title, + hasProject: true, + projectTitle: openaireBrokerEventObjectMissingProjectFound.message.title, + projectId: ItemMockPid10.id, + handle: ItemMockPid10.handle, + reason: null, + isRunning: false, + target: ItemMockPid8 + }; + } + + function getOpenAireBrokerEventData2(): OpenaireBrokerEventData { + return { + event: openaireBrokerEventObjectMissingProjectNotFound, + id: openaireBrokerEventObjectMissingProjectNotFound.id, + title: openaireBrokerEventObjectMissingProjectNotFound.title, + hasProject: false, + projectTitle: null, + projectId: null, + handle: null, + reason: null, + isRunning: false, + target: ItemMockPid9 + }; + } + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + CommonModule, + TranslateModule.forRoot(), + ], + declarations: [ + OpenaireBrokerEventsComponent, + TestComponent, + ], + providers: [ + { provide: ActivatedRoute, useValue: new ActivatedRouteStub(activatedRouteParamsMap, activatedRouteParams) }, + { provide: OpenaireBrokerEventRestService, useValue: openaireBrokerEventRestServiceStub }, + { provide: NgbModal, useValue: modalStub }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: TranslateService, useValue: getMockTranslateService() }, + { provide: PaginationService, useValue: paginationService }, + OpenaireBrokerEventsComponent + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents().then(); + scheduler = getTestScheduler(); + })); + + // First test to check the correct component creation + describe('', () => { + let testComp: TestComponent; + let testFixture: ComponentFixture; + + // synchronous beforeEach + beforeEach(() => { + const html = ` + `; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture; + testComp = testFixture.componentInstance; + }); + + afterEach(() => { + testFixture.destroy(); + }); + + it('should create OpenaireBrokerEventsComponent', inject([OpenaireBrokerEventsComponent], (app: OpenaireBrokerEventsComponent) => { + expect(app).toBeDefined(); + })); + }); + + describe('Main tests', () => { + beforeEach(() => { + fixture = TestBed.createComponent(OpenaireBrokerEventsComponent); + comp = fixture.componentInstance; + compAsAny = comp; + }); + + afterEach(() => { + fixture.destroy(); + comp = null; + compAsAny = null; + }); + + describe('setEventUpdated', () => { + it('should update events', () => { + const expected = [ + getOpenAireBrokerEventData1(), + getOpenAireBrokerEventData2() + ]; + scheduler.schedule(() => { + compAsAny.setEventUpdated(events); + }); + scheduler.flush(); + + expect(comp.eventsUpdated$.value).toEqual(expected); + }); + }); + + describe('modalChoice', () => { + beforeEach(() => { + spyOn(comp, 'executeAction'); + spyOn(comp, 'openModal'); + }); + + it('should call executeAction if a project is present', () => { + const action = 'ACCEPTED'; + comp.modalChoice(action, getOpenAireBrokerEventData1(), modalStub); + expect(comp.executeAction).toHaveBeenCalledWith(action, getOpenAireBrokerEventData1()); + }); + + it('should call openModal if a project is not present', () => { + const action = 'ACCEPTED'; + comp.modalChoice(action, getOpenAireBrokerEventData2(), modalStub); + expect(comp.openModal).toHaveBeenCalledWith(action, getOpenAireBrokerEventData2(), modalStub); + }); + }); + + describe('openModal', () => { + it('should call modalService.open', () => { + const action = 'ACCEPTED'; + comp.selectedReason = null; + spyOn(compAsAny.modalService, 'open').and.returnValue({ result: new Promise((res, rej) => 'do' ) }); + spyOn(comp, 'executeAction'); + + comp.openModal(action, getOpenAireBrokerEventData1(), modalStub); + expect(compAsAny.modalService.open).toHaveBeenCalled(); + }); + }); + + describe('openModalLookup', () => { + it('should call modalService.open', () => { + spyOn(comp, 'boundProject'); + spyOn(compAsAny.modalService, 'open').and.returnValue( + { + componentInstance: { + externalSourceEntry: null, + label: null, + importedObject: observableOf({ + indexableObject: OpenaireMockDspaceObject + }) + } + } + ); + scheduler.schedule(() => { + comp.openModalLookup(getOpenAireBrokerEventData1()); + }); + scheduler.flush(); + + expect(compAsAny.modalService.open).toHaveBeenCalled(); + expect(compAsAny.boundProject).toHaveBeenCalled(); + }); + }); + + describe('executeAction', () => { + it('should call getOpenaireBrokerEvents on 200 response from REST', () => { + const action = 'ACCEPTED'; + spyOn(compAsAny, 'getOpenaireBrokerEvents'); + openaireBrokerEventRestServiceStub.patchEvent.and.returnValue(createSuccessfulRemoteDataObject$({})); + + scheduler.schedule(() => { + comp.executeAction(action, getOpenAireBrokerEventData1()); + }); + scheduler.flush(); + + expect(compAsAny.getOpenaireBrokerEvents).toHaveBeenCalled(); + }); + }); + + describe('boundProject', () => { + it('should populate the project data inside "eventData"', () => { + const eventData = getOpenAireBrokerEventData2(); + const projectId = 'UUID-23943-34u43-38344'; + const projectName = 'Test Project'; + const projectHandle = '1000/1000'; + openaireBrokerEventRestServiceStub.boundProject.and.returnValue(createSuccessfulRemoteDataObject$({})); + + scheduler.schedule(() => { + comp.boundProject(eventData, projectId, projectName, projectHandle); + }); + scheduler.flush(); + + expect(eventData.hasProject).toEqual(true); + expect(eventData.projectId).toEqual(projectId); + expect(eventData.projectTitle).toEqual(projectName); + expect(eventData.handle).toEqual(projectHandle); + }); + }); + + describe('removeProject', () => { + it('should remove the project data inside "eventData"', () => { + const eventData = getOpenAireBrokerEventData1(); + openaireBrokerEventRestServiceStub.removeProject.and.returnValue(createNoContentRemoteDataObject$()); + + scheduler.schedule(() => { + comp.removeProject(eventData); + }); + scheduler.flush(); + + expect(eventData.hasProject).toEqual(false); + expect(eventData.projectId).toBeNull(); + expect(eventData.projectTitle).toBeNull(); + expect(eventData.handle).toBeNull(); + }); + }); + + describe('getOpenaireBrokerEvents', () => { + it('should call the "openaireBrokerEventRestService.getEventsByTopic" to take data and "setEventUpdated" to populate eventData', () => { + comp.paginationConfig = new PaginationComponentOptions(); + comp.paginationConfig.currentPage = 1; + comp.paginationConfig.pageSize = 20; + comp.paginationSortConfig = new SortOptions('trust', SortDirection.DESC); + comp.topic = activatedRouteParamsMap.id; + const options: FindListOptions = Object.assign(new FindListOptions(), { + currentPage: comp.paginationConfig.currentPage, + elementsPerPage: comp.paginationConfig.pageSize + }); + + const pageInfo = new PageInfo({ + elementsPerPage: comp.paginationConfig.pageSize, + totalElements: 0, + totalPages: 1, + currentPage: comp.paginationConfig.currentPage + }); + const array = [ + openaireBrokerEventObjectMissingProjectFound, + openaireBrokerEventObjectMissingProjectNotFound, + ]; + const paginatedList = buildPaginatedList(pageInfo, array); + const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); + openaireBrokerEventRestServiceStub.getEventsByTopic.and.returnValue(observableOf(paginatedListRD)); + spyOn(compAsAny, 'setEventUpdated'); + + scheduler.schedule(() => { + compAsAny.getOpenaireBrokerEvents(); + }); + scheduler.flush(); + + expect(compAsAny.openaireBrokerEventRestService.getEventsByTopic).toHaveBeenCalledWith( + activatedRouteParamsMap.id, + options, + followLink('target'),followLink('related') + ); + expect(compAsAny.setEventUpdated).toHaveBeenCalled(); + }); + }); + + }); +}); + +// declare a test component +@Component({ + selector: 'ds-test-cmp', + template: `` +}) +class TestComponent { + +} diff --git a/src/app/openaire/broker/events/openaire-broker-events.component.ts b/src/app/openaire/broker/events/openaire-broker-events.component.ts new file mode 100644 index 00000000000..14ad175e809 --- /dev/null +++ b/src/app/openaire/broker/events/openaire-broker-events.component.ts @@ -0,0 +1,464 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { BehaviorSubject, from, Observable, of as observableOf, Subscription } from 'rxjs'; +import { distinctUntilChanged, map, mergeMap, scan, switchMap, take } from 'rxjs/operators'; + +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { RemoteData } from '../../../core/data/remote-data'; +import { FindListOptions } from '../../../core/data/request.models'; +import { + OpenaireBrokerEventMessageObject, + OpenaireBrokerEventObject +} from '../../../core/openaire/broker/models/openaire-broker-event.model'; +import { OpenaireBrokerEventRestService } from '../../../core/openaire/broker/events/openaire-broker-event-rest.service'; +import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { Metadata } from '../../../core/shared/metadata.utils'; +import { followLink } from '../../../shared/utils/follow-link-config.model'; +import { hasValue } from '../../../shared/empty.util'; +import { ItemSearchResult } from '../../../shared/object-collection/shared/item-search-result.model'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { + OpenaireBrokerEventData, + ProjectEntryImportModalComponent +} from '../project-entry-import-modal/project-entry-import-modal.component'; +import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; +import { PaginationService } from '../../../core/pagination/pagination.service'; +import { combineLatest } from 'rxjs/internal/observable/combineLatest'; +import { Item } from '../../../core/shared/item.model'; + +/** + * Component to display the OpenAIRE Broker event list. + */ +@Component({ + selector: 'ds-openaire-broker-events', + templateUrl: './openaire-broker-events.component.html', + styleUrls: ['./openaire-broker-events.scomponent.scss'], +}) +export class OpenaireBrokerEventsComponent implements OnInit { + /** + * The pagination system configuration for HTML listing. + * @type {PaginationComponentOptions} + */ + public paginationConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { + id: 'bep', + currentPage: 1, + pageSize: 10, + pageSizeOptions: [5, 10, 20, 40, 60] + }); + /** + * The OpenAIRE Broker event list sort options. + * @type {SortOptions} + */ + public paginationSortConfig: SortOptions = new SortOptions('trust', SortDirection.DESC); + /** + * Array to save the presence of a project inside an OpenAIRE Broker event. + * @type {OpenaireBrokerEventData[]>} + */ + public eventsUpdated$: BehaviorSubject = new BehaviorSubject([]); + /** + * The total number of OpenAIRE Broker events. + * @type {Observable} + */ + public totalElements$: Observable; + /** + * The topic of the OpenAIRE Broker events; suitable for displaying. + * @type {string} + */ + public showTopic: string; + /** + * The topic of the OpenAIRE Broker events; suitable for HTTP calls. + * @type {string} + */ + public topic: string; + /** + * The rejected/ignore reason. + * @type {string} + */ + public selectedReason: string; + /** + * Contains the information about the loading status of the page. + * @type {Observable} + */ + public isEventPageLoading: BehaviorSubject = new BehaviorSubject(false); + /** + * Contains the information about the loading status of the events inside the pagination component. + * @type {Observable} + */ + public isEventLoading: BehaviorSubject = new BehaviorSubject(false); + /** + * The modal reference. + * @type {any} + */ + public modalRef: any; + /** + * Used to store the status of the 'Show more' button of the abstracts. + * @type {boolean} + */ + public showMore = false; + /** + * The FindListOptions object + */ + protected defaultConfig: FindListOptions = Object.assign(new FindListOptions(), {sort: this.paginationSortConfig}); + /** + * Array to track all the component subscriptions. Useful to unsubscribe them with 'onDestroy'. + * @type {Array} + */ + protected subs: Subscription[] = []; + + /** + * Initialize the component variables. + * @param {ActivatedRoute} activatedRoute + * @param {NgbModal} modalService + * @param {NotificationsService} notificationsService + * @param {OpenaireBrokerEventRestService} openaireBrokerEventRestService + * @param {PaginationService} paginationService + * @param {TranslateService} translateService + */ + constructor( + private activatedRoute: ActivatedRoute, + private modalService: NgbModal, + private notificationsService: NotificationsService, + private openaireBrokerEventRestService: OpenaireBrokerEventRestService, + private paginationService: PaginationService, + private translateService: TranslateService + ) { + } + + /** + * Component initialization. + */ + ngOnInit(): void { + this.isEventPageLoading.next(true); + + this.activatedRoute.paramMap.pipe( + map((params) => params.get('id')), + take(1) + ).subscribe((id: string) => { + const regEx = /!/g; + this.showTopic = id.replace(regEx, '/'); + this.topic = id; + this.isEventPageLoading.next(false); + this.getOpenaireBrokerEvents(); + }); + } + + /** + * Check if table have a detail column + */ + public hasDetailColumn(): boolean { + return (this.showTopic.indexOf('/PROJECT') !== -1 || + this.showTopic.indexOf('/PID') !== -1 || + this.showTopic.indexOf('/SUBJECT') !== -1 || + this.showTopic.indexOf('/ABSTRACT') !== -1 + ); + } + + /** + * Open a modal or run the executeAction directly based on the presence of the project. + * + * @param {string} action + * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) + * @param {OpenaireBrokerEventData} eventData + * the OpenAIRE Broker event data + * @param {any} content + * Reference to the modal + */ + public modalChoice(action: string, eventData: OpenaireBrokerEventData, content: any): void { + if (eventData.hasProject) { + this.executeAction(action, eventData); + } else { + this.openModal(action, eventData, content); + } + } + + /** + * Open the selected modal and performs the action if needed. + * + * @param {string} action + * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) + * @param {OpenaireBrokerEventData} eventData + * the OpenAIRE Broker event data + * @param {any} content + * Reference to the modal + */ + public openModal(action: string, eventData: OpenaireBrokerEventData, content: any): void { + this.modalService.open(content, { ariaLabelledBy: 'modal-basic-title' }).result.then( + (result) => { + if (result === 'do') { + eventData.reason = this.selectedReason; + this.executeAction(action, eventData); + } + this.selectedReason = null; + }, + (_reason) => { + this.selectedReason = null; + } + ); + } + + /** + * Open a modal where the user can select the project. + * + * @param {OpenaireBrokerEventData} eventData + * the OpenAIRE Broker event item data + */ + public openModalLookup(eventData: OpenaireBrokerEventData): void { + this.modalRef = this.modalService.open(ProjectEntryImportModalComponent, { + size: 'lg' + }); + const modalComp = this.modalRef.componentInstance; + modalComp.externalSourceEntry = eventData; + modalComp.label = 'project'; + this.subs.push( + modalComp.importedObject.pipe(take(1)) + .subscribe((object: ItemSearchResult) => { + const projectTitle = Metadata.first(object.indexableObject.metadata, 'dc.title'); + this.boundProject( + eventData, + object.indexableObject.id, + projectTitle.value, + object.indexableObject.handle + ); + }) + ); + } + + /** + * Performs the choosen action calling the REST service. + * + * @param {string} action + * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) + * @param {OpenaireBrokerEventData} eventData + * the OpenAIRE Broker event data + */ + public executeAction(action: string, eventData: OpenaireBrokerEventData): void { + eventData.isRunning = true; + this.subs.push( + this.openaireBrokerEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { + if (rd.isSuccess && rd.statusCode === 200) { + this.notificationsService.success( + this.translateService.instant('openaire.broker.event.action.saved') + ); + this.getOpenaireBrokerEvents(); + } else { + this.notificationsService.error( + this.translateService.instant('openaire.broker.event.action.error') + ); + } + eventData.isRunning = false; + }) + ); + } + + /** + * Bound a project to the publication described in the OpenAIRE Broker event calling the REST service. + * + * @param {OpenaireBrokerEventData} eventData + * the OpenAIRE Broker event item data + * @param {string} projectId + * the project Id to bound + * @param {string} projectTitle + * the project title + * @param {string} projectHandle + * the project handle + */ + public boundProject(eventData: OpenaireBrokerEventData, projectId: string, projectTitle: string, projectHandle: string): void { + eventData.isRunning = true; + this.subs.push( + this.openaireBrokerEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { + if (rd.isSuccess) { + this.notificationsService.success( + this.translateService.instant('openaire.broker.event.project.bounded') + ); + eventData.hasProject = true; + eventData.projectTitle = projectTitle; + eventData.handle = projectHandle; + eventData.projectId = projectId; + } else { + this.notificationsService.error( + this.translateService.instant('openaire.broker.event.project.error') + ); + } + eventData.isRunning = false; + }) + ); + } + + /** + * Remove the bounded project from the publication described in the OpenAIRE Broker event calling the REST service. + * + * @param {OpenaireBrokerEventData} eventData + * the OpenAIRE Broker event data + */ + public removeProject(eventData: OpenaireBrokerEventData): void { + eventData.isRunning = true; + this.subs.push( + this.openaireBrokerEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { + if (rd.isSuccess) { + this.notificationsService.success( + this.translateService.instant('openaire.broker.event.project.removed') + ); + eventData.hasProject = false; + eventData.projectTitle = null; + eventData.handle = null; + eventData.projectId = null; + } else { + this.notificationsService.error( + this.translateService.instant('openaire.broker.event.project.error') + ); + } + eventData.isRunning = false; + }) + ); + } + + /** + * Check if the event has a valid href. + * @param event + */ + public hasPIDHref(event: OpenaireBrokerEventMessageObject): boolean { + return this.getPIDHref(event) !== null; + } + + /** + * Get the event pid href. + * @param event + */ + public getPIDHref(event: OpenaireBrokerEventMessageObject): string { + return this.computePIDHref(event); + } + + + /** + * Dispatch the OpenAIRE Broker events retrival. + */ + public getOpenaireBrokerEvents(): void { + this.paginationService.getFindListOptions(this.paginationConfig.id, this.defaultConfig).pipe( + distinctUntilChanged(), + switchMap((options: FindListOptions) => this.openaireBrokerEventRestService.getEventsByTopic( + this.topic, + options, + followLink('target'), followLink('related') + )), + getFirstCompletedRemoteData(), + ).subscribe((rd: RemoteData>) => { + if (rd.hasSucceeded) { + this.isEventLoading.next(false); + this.totalElements$ = observableOf(rd.payload.totalElements); + this.setEventUpdated(rd.payload.page); + } else { + throw new Error('Can\'t retrieve OpenAIRE Broker events from the Broker events REST service'); + } + this.openaireBrokerEventRestService.clearFindByTopicRequests(); + }); + } + + /** + * Unsubscribe from all subscriptions. + */ + ngOnDestroy(): void { + this.subs + .filter((sub) => hasValue(sub)) + .forEach((sub) => sub.unsubscribe()); + } + + /** + * Set the project status for the OpenAIRE Broker events. + * + * @param {OpenaireBrokerEventObject[]} events + * the OpenAIRE Broker event item + */ + protected setEventUpdated(events: OpenaireBrokerEventObject[]): void { + this.subs.push( + from(events).pipe( + mergeMap((event: OpenaireBrokerEventObject) => { + const related$ = event.related.pipe( + getFirstCompletedRemoteData(), + ); + const target$ = event.target.pipe( + getFirstCompletedRemoteData() + ); + return combineLatest([related$, target$]).pipe( + map(([relatedItemRD, targetItemRD]: [RemoteData, RemoteData]) => { + const data: OpenaireBrokerEventData = { + event: event, + id: event.id, + title: event.title, + hasProject: false, + projectTitle: null, + projectId: null, + handle: null, + reason: null, + isRunning: false, + target: (targetItemRD?.hasSucceeded) ? targetItemRD.payload : null, + }; + if (relatedItemRD?.hasSucceeded && relatedItemRD?.payload?.id) { + data.hasProject = true; + data.projectTitle = event.message.title; + data.projectId = relatedItemRD?.payload?.id; + data.handle = relatedItemRD?.payload?.handle; + } + return data; + }) + ); + }), + scan((acc: any, value: any) => [...acc, value], []), + take(events.length) + ).subscribe( + (eventsReduced) => { + this.eventsUpdated$.next(eventsReduced); + } + ) + ); + } + + protected computePIDHref(event: OpenaireBrokerEventMessageObject) { + const type = event.type.toLowerCase(); + const pid = event.value; + let prefix = null; + switch (type) { + case 'arxiv': { + prefix = 'https://arxiv.org/abs/'; + break; + } + case 'handle': { + prefix = 'https://hdl.handle.net/'; + break; + } + case 'urn': { + prefix = ''; + break; + } + case 'doi': { + prefix = 'https://doi.org/'; + break; + } + case 'pmc': { + prefix = 'https://www.ncbi.nlm.nih.gov/pmc/articles/'; + break; + } + case 'pmid': { + prefix = 'https://pubmed.ncbi.nlm.nih.gov/'; + break; + } + case 'ncid': { + prefix = 'https://ci.nii.ac.jp/ncid/'; + break; + } + default: { + break; + } + } + if (prefix === null) { + return null; + } + return prefix + pid; + } +} diff --git a/src/app/openaire/broker/events/openaire-broker-events.scomponent.scss b/src/app/openaire/broker/events/openaire-broker-events.scomponent.scss new file mode 100644 index 00000000000..b38da70f376 --- /dev/null +++ b/src/app/openaire/broker/events/openaire-broker-events.scomponent.scss @@ -0,0 +1,21 @@ +.button-rows { + min-width: 200px; +} + +.button-width { + width: 100%; +} + +.abstract-container { + height: 76px; + overflow: hidden; +} + +.text-ellipsis { + text-overflow: ellipsis; +} + +.show { + overflow: visible; + height: auto; +} diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.html b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.html new file mode 100644 index 00000000000..1090fd22fcf --- /dev/null +++ b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.html @@ -0,0 +1,70 @@ + + + diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.scss b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.scss new file mode 100644 index 00000000000..7db9839e384 --- /dev/null +++ b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.scss @@ -0,0 +1,3 @@ +.modal-footer { + justify-content: space-between; +} diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts new file mode 100644 index 00000000000..e19d0a7c867 --- /dev/null +++ b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts @@ -0,0 +1,210 @@ +import { CommonModule } from '@angular/common'; +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateModule } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs'; +import { SearchService } from '../../../core/shared/search/search.service'; +import { Item } from '../../../core/shared/item.model'; +import { createTestComponent } from '../../../shared/testing/utils.test'; +import { ImportType, ProjectEntryImportModalComponent } from './project-entry-import-modal.component'; +import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service'; +import { getMockSearchService } from '../../../shared/mocks/search-service.mock'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; +import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; +import { buildPaginatedList } from '../../../core/data/paginated-list.model'; +import { PageInfo } from '../../../core/shared/page-info.model'; +import { + ItemMockPid10, + openaireBrokerEventObjectMissingProjectFound, + OpenaireMockDspaceObject +} from '../../../shared/mocks/openaire.mock'; + +const eventData = { + event: openaireBrokerEventObjectMissingProjectFound, + id: openaireBrokerEventObjectMissingProjectFound.id, + title: openaireBrokerEventObjectMissingProjectFound.title, + hasProject: true, + projectTitle: openaireBrokerEventObjectMissingProjectFound.message.title, + projectId: ItemMockPid10.id, + handle: ItemMockPid10.handle, + reason: null, + isRunning: false +}; + +const searchString = 'Test project to search'; +const pagination = Object.assign( + new PaginationComponentOptions(), { + id: 'openaire-project-bound', + pageSize: 3 + } +); +const searchOptions = Object.assign(new PaginatedSearchOptions( + { + configuration: 'funding', + query: searchString, + pagination: pagination + } +)); +const pageInfo = new PageInfo({ + elementsPerPage: 3, + totalElements: 1, + totalPages: 1, + currentPage: 1 +}); +const array = [ + OpenaireMockDspaceObject, +]; +const paginatedList = buildPaginatedList(pageInfo, array); +const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); + +describe('ProjectEntryImportModalComponent test suite', () => { + let fixture: ComponentFixture; + let comp: ProjectEntryImportModalComponent; + let compAsAny: any; + + const modalStub = jasmine.createSpyObj('modal', ['close', 'dismiss']); + const uuid = '123e4567-e89b-12d3-a456-426614174003'; + const searchServiceStub: any = getMockSearchService(); + + + beforeEach(async (() => { + TestBed.configureTestingModule({ + imports: [ + CommonModule, + TranslateModule.forRoot(), + ], + declarations: [ + ProjectEntryImportModalComponent, + TestComponent, + ], + providers: [ + { provide: NgbActiveModal, useValue: modalStub }, + { provide: SearchService, useValue: searchServiceStub }, + { provide: SelectableListService, useValue: jasmine.createSpyObj('selectableListService', ['deselect', 'select', 'deselectAll']) }, + ProjectEntryImportModalComponent + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents().then(); + })); + + // First test to check the correct component creation + describe('', () => { + let testComp: TestComponent; + let testFixture: ComponentFixture; + + // synchronous beforeEach + beforeEach(() => { + searchServiceStub.search.and.returnValue(observableOf(paginatedListRD)); + const html = ` + `; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture; + testComp = testFixture.componentInstance; + }); + + afterEach(() => { + testFixture.destroy(); + }); + + it('should create ProjectEntryImportModalComponent', inject([ProjectEntryImportModalComponent], (app: ProjectEntryImportModalComponent) => { + expect(app).toBeDefined(); + })); + }); + + describe('Main tests', () => { + beforeEach(() => { + fixture = TestBed.createComponent(ProjectEntryImportModalComponent); + comp = fixture.componentInstance; + compAsAny = comp; + + }); + + describe('close', () => { + it('should close the modal', () => { + comp.close(); + expect(modalStub.close).toHaveBeenCalled(); + }); + }); + + describe('search', () => { + it('should call SearchService.search', () => { + + (searchServiceStub as any).search.and.returnValue(observableOf(paginatedListRD)); + comp.pagination = pagination; + + comp.search(searchString); + expect(comp.searchService.search).toHaveBeenCalledWith(searchOptions); + }); + }); + + describe('bound', () => { + it('should call close, deselectAllLists and importedObject.emit', () => { + spyOn(comp, 'deselectAllLists'); + spyOn(comp, 'close'); + spyOn(comp.importedObject, 'emit'); + comp.selectedEntity = OpenaireMockDspaceObject; + comp.bound(); + + expect(comp.importedObject.emit).toHaveBeenCalled(); + expect(comp.deselectAllLists).toHaveBeenCalled(); + expect(comp.close).toHaveBeenCalled(); + }); + }); + + describe('selectEntity', () => { + const entity = Object.assign(new Item(), { uuid: uuid }); + beforeEach(() => { + comp.selectEntity(entity); + }); + + it('should set selected entity', () => { + expect(comp.selectedEntity).toBe(entity); + }); + + it('should set the import type to local entity', () => { + expect(comp.selectedImportType).toEqual(ImportType.LocalEntity); + }); + }); + + describe('deselectEntity', () => { + const entity = Object.assign(new Item(), { uuid: uuid }); + beforeEach(() => { + comp.selectedImportType = ImportType.LocalEntity; + comp.selectedEntity = entity; + comp.deselectEntity(); + }); + + it('should remove the selected entity', () => { + expect(comp.selectedEntity).toBeUndefined(); + }); + + it('should set the import type to none', () => { + expect(comp.selectedImportType).toEqual(ImportType.None); + }); + }); + + describe('deselectAllLists', () => { + it('should call SelectableListService.deselectAll', () => { + comp.deselectAllLists(); + expect(compAsAny.selectService.deselectAll).toHaveBeenCalledWith(comp.entityListId); + expect(compAsAny.selectService.deselectAll).toHaveBeenCalledWith(comp.authorityListId); + }); + }); + + afterEach(() => { + fixture.destroy(); + comp = null; + compAsAny = null; + }); + }); +}); + +// declare a test component +@Component({ + selector: 'ds-test-cmp', + template: `` +}) +class TestComponent { + eventData = eventData; +} diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.ts b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.ts new file mode 100644 index 00000000000..5d8cb20c6d2 --- /dev/null +++ b/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.ts @@ -0,0 +1,274 @@ +import { Component, EventEmitter, Input, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Observable, of as observableOf, Subscription } from 'rxjs'; +import { RemoteData } from '../../../core/data/remote-data'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { SearchResult } from '../../../shared/search/models/search-result.model'; +import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model'; +import { CollectionElementLinkType } from '../../../shared/object-collection/collection-element-link.type'; +import { Context } from '../../../core/shared/context.model'; +import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service'; +import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model'; +import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { SearchService } from '../../../core/shared/search/search.service'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { OpenaireBrokerEventObject } from '../../../core/openaire/broker/models/openaire-broker-event.model'; +import { hasValue, isNotEmpty } from '../../../shared/empty.util'; +import { Item } from '../../../core/shared/item.model'; + +/** + * The possible types of import for the external entry + */ +export enum ImportType { + None = 'None', + LocalEntity = 'LocalEntity', + LocalAuthority = 'LocalAuthority', + NewEntity = 'NewEntity', + NewAuthority = 'NewAuthority' +} + +/** + * The data type passed from the parent page + */ +export interface OpenaireBrokerEventData { + /** + * The OpenAIRE Broker event + */ + event: OpenaireBrokerEventObject; + /** + * The OpenAIRE Broker event Id (uuid) + */ + id: string; + /** + * The publication title + */ + title: string; + /** + * Contains the boolean that indicates if a project is present + */ + hasProject: boolean; + /** + * The project title, if present + */ + projectTitle: string; + /** + * The project id (uuid), if present + */ + projectId: string; + /** + * The project handle, if present + */ + handle: string; + /** + * The reject/discard reason + */ + reason: string; + /** + * Contains the boolean that indicates if there is a running operation (REST call) + */ + isRunning: boolean; + /** + * The related publication DSpace item + */ + target?: Item; +} + +@Component({ + selector: 'ds-project-entry-import-modal', + styleUrls: ['./project-entry-import-modal.component.scss'], + templateUrl: './project-entry-import-modal.component.html' +}) +/** + * Component to display a modal window for linking a project to an OpenAIRE Broker event + * Shows information about the selected project and a selectable list. + */ +export class ProjectEntryImportModalComponent implements OnInit { + /** + * The external source entry + */ + @Input() externalSourceEntry: OpenaireBrokerEventData; + /** + * The number of results per page + */ + pageSize = 3; + /** + * The prefix for every i18n key within this modal + */ + labelPrefix = 'openaire.broker.event.modal.'; + /** + * The search configuration to retrieve project + */ + configuration = 'funding'; + /** + * The label to use for all messages (added to the end of relevant i18n keys) + */ + label: string; + /** + * The project title from the parent object + */ + projectTitle: string; + /** + * The search results + */ + localEntitiesRD$: Observable>>>; + /** + * Information about the data loading status + */ + isLoading$ = observableOf(true); + /** + * Search options to use for fetching projects + */ + searchOptions: PaginatedSearchOptions; + /** + * The context we're currently in (submission) + */ + context = Context.EntitySearchModalWithNameVariants; + /** + * List ID for selecting local entities + */ + entityListId = 'openaire-project-bound'; + /** + * List ID for selecting local authorities + */ + authorityListId = 'openaire-project-bound-authority'; + /** + * ImportType enum + */ + importType = ImportType; + /** + * The type of link to render in listable elements + */ + linkTypes = CollectionElementLinkType; + /** + * The type of import the user currently has selected + */ + selectedImportType = ImportType.None; + /** + * The selected local entity + */ + selectedEntity: ListableObject; + /** + * An project has been selected, send it to the parent component + */ + importedObject: EventEmitter = new EventEmitter(); + /** + * Pagination options + */ + pagination: PaginationComponentOptions; + /** + * Array to track all the component subscriptions. Useful to unsubscribe them with 'onDestroy'. + * @type {Array} + */ + protected subs: Subscription[] = []; + + /** + * Initialize the component variables. + * @param {NgbActiveModal} modal + * @param {SearchService} searchService + * @param {SelectableListService} selectService + */ + constructor(public modal: NgbActiveModal, + public searchService: SearchService, + private selectService: SelectableListService) { } + + /** + * Component intitialization. + */ + public ngOnInit(): void { + this.pagination = Object.assign(new PaginationComponentOptions(), { id: 'openaire-project-bound', pageSize: this.pageSize }); + this.projectTitle = (this.externalSourceEntry.projectTitle !== null) ? this.externalSourceEntry.projectTitle : this.externalSourceEntry.event.message.title; + this.searchOptions = Object.assign(new PaginatedSearchOptions( + { + configuration: this.configuration, + query: this.projectTitle, + pagination: this.pagination + } + )); + this.localEntitiesRD$ = this.searchService.search(this.searchOptions); + this.subs.push( + this.localEntitiesRD$.subscribe( + () => this.isLoading$ = observableOf(false) + ) + ); + } + + /** + * Close the modal. + */ + public close(): void { + this.deselectAllLists(); + this.modal.close(); + } + + /** + * Perform a project search by title. + */ + public search(searchTitle): void { + if (isNotEmpty(searchTitle)) { + const filterRegEx = /[:]/g; + this.isLoading$ = observableOf(true); + this.searchOptions = Object.assign(new PaginatedSearchOptions( + { + configuration: this.configuration, + query: (searchTitle) ? searchTitle.replace(filterRegEx, '') : searchTitle, + pagination: this.pagination + } + )); + this.localEntitiesRD$ = this.searchService.search(this.searchOptions); + this.subs.push( + this.localEntitiesRD$.subscribe( + () => this.isLoading$ = observableOf(false) + ) + ); + } + } + + /** + * Perform the bound of the project. + */ + public bound(): void { + if (this.selectedEntity !== undefined) { + this.importedObject.emit(this.selectedEntity); + } + this.selectedImportType = ImportType.None; + this.deselectAllLists(); + this.close(); + } + + /** + * Deselected a local entity + */ + public deselectEntity(): void { + this.selectedEntity = undefined; + if (this.selectedImportType === ImportType.LocalEntity) { + this.selectedImportType = ImportType.None; + } + } + + /** + * Selected a local entity + * @param entity + */ + public selectEntity(entity): void { + this.selectedEntity = entity; + this.selectedImportType = ImportType.LocalEntity; + } + + /** + * Deselect every element from both entity and authority lists + */ + public deselectAllLists(): void { + this.selectService.deselectAll(this.entityListId); + this.selectService.deselectAll(this.authorityListId); + } + + /** + * Unsubscribe from all subscriptions. + */ + ngOnDestroy(): void { + this.deselectAllLists(); + this.subs + .filter((sub) => hasValue(sub)) + .forEach((sub) => sub.unsubscribe()); + } +} diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.actions.ts b/src/app/openaire/broker/topics/openaire-broker-topics.actions.ts new file mode 100644 index 00000000000..fd98c6acb8b --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.actions.ts @@ -0,0 +1,99 @@ +import { Action } from '@ngrx/store'; +import { type } from '../../../shared/ngrx/type'; +import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/openaire-broker-topic.model'; + +/** + * For each action type in an action group, make a simple + * enum object for all of this group's action types. + * + * The 'type' utility function coerces strings into string + * literal types and runs a simple check to guarantee all + * action types in the application are unique. + */ +export const OpenaireBrokerTopicActionTypes = { + ADD_TOPICS: type('dspace/integration/openaire/broker/topic/ADD_TOPICS'), + RETRIEVE_ALL_TOPICS: type('dspace/integration/openaire/broker/topic/RETRIEVE_ALL_TOPICS'), + RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/openaire/broker/topic/RETRIEVE_ALL_TOPICS_ERROR'), +}; + +/* tslint:disable:max-classes-per-file */ + +/** + * An ngrx action to retrieve all the OpenAIRE Broker topics. + */ +export class RetrieveAllTopicsAction implements Action { + type = OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS; + payload: { + elementsPerPage: number; + currentPage: number; + }; + + /** + * Create a new RetrieveAllTopicsAction. + * + * @param elementsPerPage + * the number of topics per page + * @param currentPage + * The page number to retrieve + */ + constructor(elementsPerPage: number, currentPage: number) { + this.payload = { + elementsPerPage, + currentPage + }; + } +} + +/** + * An ngrx action for retrieving 'all OpenAIRE Broker topics' error. + */ +export class RetrieveAllTopicsErrorAction implements Action { + type = OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR; +} + +/** + * An ngrx action to load the OpenAIRE Broker topic objects. + * Called by the ??? effect. + */ +export class AddTopicsAction implements Action { + type = OpenaireBrokerTopicActionTypes.ADD_TOPICS; + payload: { + topics: OpenaireBrokerTopicObject[]; + totalPages: number; + currentPage: number; + totalElements: number; + }; + + /** + * Create a new AddTopicsAction. + * + * @param topics + * the list of topics + * @param totalPages + * the total available pages of topics + * @param currentPage + * the current page + * @param totalElements + * the total available OpenAIRE Broker topics + */ + constructor(topics: OpenaireBrokerTopicObject[], totalPages: number, currentPage: number, totalElements: number) { + this.payload = { + topics, + totalPages, + currentPage, + totalElements + }; + } + +} + +/* tslint:enable:max-classes-per-file */ + +/** + * Export a type alias of all actions in this action group + * so that reducers can easily compose action types. + */ +export type OpenaireBrokerTopicsActions + = AddTopicsAction + |RetrieveAllTopicsAction + |RetrieveAllTopicsErrorAction; diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.html b/src/app/openaire/broker/topics/openaire-broker-topics.component.html new file mode 100644 index 00000000000..d8321bc932b --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.component.html @@ -0,0 +1,57 @@ +
+
+
+

{{'openaire.broker.title'| translate}}

+

{{'openaire.broker.topics.description'| translate}}

+
+
+
+
+

{{'openaire.broker.topics'| translate}}

+ + + + + + + +
+ + + + + + + + + + + + + + + +
{{'openaire.broker.table.topic' | translate}}{{'openaire.broker.table.last-event' | translate}}{{'openaire.broker.table.actions' | translate}}
{{topicElement.name}}{{topicElement.lastEvent}} +
+ +
+
+
+
+
+
+
+
diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.scss b/src/app/openaire/broker/topics/openaire-broker-topics.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.spec.ts b/src/app/openaire/broker/topics/openaire-broker-topics.component.spec.ts new file mode 100644 index 00000000000..00ea772ff9a --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.component.spec.ts @@ -0,0 +1,152 @@ +import { CommonModule } from '@angular/common'; +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs'; +import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing'; +import { createTestComponent } from '../../../shared/testing/utils.test'; +import { + getMockOpenaireStateService, + openaireBrokerTopicObjectMoreAbstract, + openaireBrokerTopicObjectMorePid +} from '../../../shared/mocks/openaire.mock'; +import { OpenaireBrokerTopicsComponent } from './openaire-broker-topics.component'; +import { OpenaireStateService } from '../../openaire-state.service'; +import { cold } from 'jasmine-marbles'; +import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; +import { PaginationService } from '../../../core/pagination/pagination.service'; + +describe('OpenaireBrokerTopicsComponent test suite', () => { + let fixture: ComponentFixture; + let comp: OpenaireBrokerTopicsComponent; + let compAsAny: any; + const mockOpenaireStateService = getMockOpenaireStateService(); + const activatedRouteParams = { + openaireBrokerTopicsParams: { + currentPage: 0, + pageSize: 5 + } + }; + const paginationService = new PaginationServiceStub(); + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + CommonModule, + TranslateModule.forRoot(), + ], + declarations: [ + OpenaireBrokerTopicsComponent, + TestComponent, + ], + providers: [ + { provide: OpenaireStateService, useValue: mockOpenaireStateService }, + { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), params: observableOf({}) } }, + { provide: PaginationService, useValue: paginationService }, + OpenaireBrokerTopicsComponent + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents().then(() => { + mockOpenaireStateService.getOpenaireBrokerTopics.and.returnValue(observableOf([ + openaireBrokerTopicObjectMorePid, + openaireBrokerTopicObjectMoreAbstract + ])); + mockOpenaireStateService.getOpenaireBrokerTopicsTotalPages.and.returnValue(observableOf(1)); + mockOpenaireStateService.getOpenaireBrokerTopicsCurrentPage.and.returnValue(observableOf(0)); + mockOpenaireStateService.getOpenaireBrokerTopicsTotals.and.returnValue(observableOf(2)); + mockOpenaireStateService.isOpenaireBrokerTopicsLoaded.and.returnValue(observableOf(true)); + mockOpenaireStateService.isOpenaireBrokerTopicsLoading.and.returnValue(observableOf(false)); + mockOpenaireStateService.isOpenaireBrokerTopicsProcessing.and.returnValue(observableOf(false)); + }); + })); + + // First test to check the correct component creation + describe('', () => { + let testComp: TestComponent; + let testFixture: ComponentFixture; + + // synchronous beforeEach + beforeEach(() => { + const html = ` + `; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture; + testComp = testFixture.componentInstance; + }); + + afterEach(() => { + testFixture.destroy(); + }); + + it('should create OpenaireBrokerTopicsComponent', inject([OpenaireBrokerTopicsComponent], (app: OpenaireBrokerTopicsComponent) => { + expect(app).toBeDefined(); + })); + }); + + describe('Main tests running with two topics', () => { + beforeEach(() => { + fixture = TestBed.createComponent(OpenaireBrokerTopicsComponent); + comp = fixture.componentInstance; + compAsAny = comp; + + }); + + afterEach(() => { + fixture.destroy(); + comp = null; + compAsAny = null; + }); + + it(('Should init component properly'), () => { + comp.ngOnInit(); + fixture.detectChanges(); + + expect(comp.topics$).toBeObservable(cold('(a|)', { + a: [ + openaireBrokerTopicObjectMorePid, + openaireBrokerTopicObjectMoreAbstract + ] + })); + expect(comp.totalElements$).toBeObservable(cold('(a|)', { + a: 2 + })); + }); + + it(('Should set data properly after the view init'), () => { + spyOn(compAsAny, 'getOpenaireBrokerTopics'); + + comp.ngAfterViewInit(); + fixture.detectChanges(); + + expect(compAsAny.getOpenaireBrokerTopics).toHaveBeenCalled(); + }); + + it(('isTopicsLoading should return FALSE'), () => { + expect(comp.isTopicsLoading()).toBeObservable(cold('(a|)', { + a: false + })); + }); + + it(('isTopicsProcessing should return FALSE'), () => { + expect(comp.isTopicsProcessing()).toBeObservable(cold('(a|)', { + a: false + })); + }); + + it(('getOpenaireBrokerTopics should call the service to dispatch a STATE change'), () => { + comp.ngOnInit(); + fixture.detectChanges(); + + compAsAny.openaireStateService.dispatchRetrieveOpenaireBrokerTopics(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage).and.callThrough(); + expect(compAsAny.openaireStateService.dispatchRetrieveOpenaireBrokerTopics).toHaveBeenCalledWith(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage); + }); + }); +}); + +// declare a test component +@Component({ + selector: 'ds-test-cmp', + template: `` +}) +class TestComponent { + +} diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.ts b/src/app/openaire/broker/topics/openaire-broker-topics.component.ts new file mode 100644 index 00000000000..408e21d946f --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.component.ts @@ -0,0 +1,142 @@ +import { Component, OnInit } from '@angular/core'; + +import { Observable, Subscription } from 'rxjs'; +import { distinctUntilChanged, take } from 'rxjs/operators'; + +import { SortOptions } from '../../../core/cache/models/sort-options.model'; +import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/openaire-broker-topic.model'; +import { hasValue } from '../../../shared/empty.util'; +import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { OpenaireStateService } from '../../openaire-state.service'; +import { AdminNotificationsOpenaireTopicsPageParams } from '../../../admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service'; +import { PaginationService } from '../../../core/pagination/pagination.service'; + +/** + * Component to display the OpenAIRE Broker topic list. + */ +@Component({ + selector: 'ds-openaire-broker-topic', + templateUrl: './openaire-broker-topics.component.html', + styleUrls: ['./openaire-broker-topics.component.scss'], +}) +export class OpenaireBrokerTopicsComponent implements OnInit { + /** + * The pagination system configuration for HTML listing. + * @type {PaginationComponentOptions} + */ + public paginationConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { + id: 'btp', + pageSize: 10, + pageSizeOptions: [5, 10, 20, 40, 60] + }); + /** + * The OpenAIRE Broker topic list sort options. + * @type {SortOptions} + */ + public paginationSortConfig: SortOptions; + /** + * The OpenAIRE Broker topic list. + */ + public topics$: Observable; + /** + * The total number of OpenAIRE Broker topics. + */ + public totalElements$: Observable; + /** + * Array to track all the component subscriptions. Useful to unsubscribe them with 'onDestroy'. + * @type {Array} + */ + protected subs: Subscription[] = []; + + /** + * Initialize the component variables. + * @param {PaginationService} paginationService + * @param {OpenaireStateService} openaireStateService + */ + constructor( + private paginationService: PaginationService, + private openaireStateService: OpenaireStateService, + ) { } + + /** + * Component initialization. + */ + ngOnInit(): void { + this.topics$ = this.openaireStateService.getOpenaireBrokerTopics(); + this.totalElements$ = this.openaireStateService.getOpenaireBrokerTopicsTotals(); + } + + /** + * First OpenAIRE Broker topics loading after view initialization. + */ + ngAfterViewInit(): void { + this.subs.push( + this.openaireStateService.isOpenaireBrokerTopicsLoaded().pipe( + take(1) + ).subscribe(() => { + this.getOpenaireBrokerTopics(); + }) + ); + } + + /** + * Returns the information about the loading status of the OpenAIRE Broker topics (if it's running or not). + * + * @return Observable + * 'true' if the topics are loading, 'false' otherwise. + */ + public isTopicsLoading(): Observable { + return this.openaireStateService.isOpenaireBrokerTopicsLoading(); + } + + /** + * Returns the information about the processing status of the OpenAIRE Broker topics (if it's running or not). + * + * @return Observable + * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. + */ + public isTopicsProcessing(): Observable { + return this.openaireStateService.isOpenaireBrokerTopicsProcessing(); + } + + /** + * Dispatch the OpenAIRE Broker topics retrival. + */ + public getOpenaireBrokerTopics(): void { + this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe( + distinctUntilChanged(), + ).subscribe((options: PaginationComponentOptions) => { + this.openaireStateService.dispatchRetrieveOpenaireBrokerTopics( + options.pageSize, + options.currentPage + ); + }); + } + + /** + * Update pagination Config from route params + * + * @param eventsRouteParams + */ + protected updatePaginationFromRouteParams(eventsRouteParams: AdminNotificationsOpenaireTopicsPageParams) { + if (eventsRouteParams.currentPage) { + this.paginationConfig.currentPage = eventsRouteParams.currentPage; + } + if (eventsRouteParams.pageSize) { + if (this.paginationConfig.pageSizeOptions.includes(eventsRouteParams.pageSize)) { + this.paginationConfig.pageSize = eventsRouteParams.pageSize; + } else { + this.paginationConfig.pageSize = this.paginationConfig.pageSizeOptions[0]; + } + } + } + + /** + * Unsubscribe from all subscriptions. + */ + ngOnDestroy(): void { + this.subs + .filter((sub) => hasValue(sub)) + .forEach((sub) => sub.unsubscribe()); + } +} diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.effects.ts b/src/app/openaire/broker/topics/openaire-broker-topics.effects.ts new file mode 100644 index 00000000000..b590b122f52 --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.effects.ts @@ -0,0 +1,87 @@ +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Actions, Effect, ofType } from '@ngrx/effects'; +import { TranslateService } from '@ngx-translate/core'; +import { catchError, map, switchMap, tap, withLatestFrom } from 'rxjs/operators'; +import { of as observableOf } from 'rxjs'; +import { + AddTopicsAction, + OpenaireBrokerTopicActionTypes, + RetrieveAllTopicsAction, + RetrieveAllTopicsErrorAction, +} from './openaire-broker-topics.actions'; + +import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/openaire-broker-topic.model'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { OpenaireBrokerTopicsService } from './openaire-broker-topics.service'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { OpenaireBrokerTopicRestService } from '../../../core/openaire/broker/topics/openaire-broker-topic-rest.service'; + +/** + * Provides effect methods for the OpenAIRE Broker topics actions. + */ +@Injectable() +export class OpenaireBrokerTopicsEffects { + + /** + * Retrieve all OpenAIRE Broker topics managing pagination and errors. + */ + @Effect() retrieveAllTopics$ = this.actions$.pipe( + ofType(OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS), + withLatestFrom(this.store$), + switchMap(([action, currentState]: [RetrieveAllTopicsAction, any]) => { + return this.openaireBrokerTopicService.getTopics( + action.payload.elementsPerPage, + action.payload.currentPage + ).pipe( + map((topics: PaginatedList) => + new AddTopicsAction(topics.page, topics.totalPages, topics.currentPage, topics.totalElements) + ), + catchError((error: Error) => { + if (error) { + console.error(error.message); + } + return observableOf(new RetrieveAllTopicsErrorAction()); + }) + ); + }) + ); + + /** + * Show a notification on error. + */ + @Effect({ dispatch: false }) retrieveAllTopicsErrorAction$ = this.actions$.pipe( + ofType(OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR), + tap(() => { + this.notificationsService.error(null, this.translate.get('openaire.broker.topic.error.service.retrieve')); + }) + ); + + /** + * Clear find all topics requests from cache. + */ + @Effect({ dispatch: false }) addTopicsAction$ = this.actions$.pipe( + ofType(OpenaireBrokerTopicActionTypes.ADD_TOPICS), + tap(() => { + this.openaireBrokerTopicDataService.clearFindAllTopicsRequests(); + }) + ); + + /** + * Initialize the effect class variables. + * @param {Actions} actions$ + * @param {Store} store$ + * @param {TranslateService} translate + * @param {NotificationsService} notificationsService + * @param {OpenaireBrokerTopicsService} openaireBrokerTopicService + * @param {OpenaireBrokerTopicRestService} openaireBrokerTopicDataService + */ + constructor( + private actions$: Actions, + private store$: Store, + private translate: TranslateService, + private notificationsService: NotificationsService, + private openaireBrokerTopicService: OpenaireBrokerTopicsService, + private openaireBrokerTopicDataService: OpenaireBrokerTopicRestService + ) { } +} diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.reducer.spec.ts b/src/app/openaire/broker/topics/openaire-broker-topics.reducer.spec.ts new file mode 100644 index 00000000000..b4ee60558bc --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.reducer.spec.ts @@ -0,0 +1,68 @@ +import { + AddTopicsAction, + RetrieveAllTopicsAction, + RetrieveAllTopicsErrorAction +} from './openaire-broker-topics.actions'; +import { openaireBrokerTopicsReducer, OpenaireBrokerTopicState } from './openaire-broker-topics.reducer'; +import { + openaireBrokerTopicObjectMoreAbstract, + openaireBrokerTopicObjectMorePid +} from '../../../shared/mocks/openaire.mock'; + +describe('openaireBrokerTopicsReducer test suite', () => { + let openaireBrokerTopicInitialState: OpenaireBrokerTopicState; + const elementPerPage = 3; + const currentPage = 0; + + beforeEach(() => { + openaireBrokerTopicInitialState = { + topics: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0 + }; + }); + + it('Action RETRIEVE_ALL_TOPICS should set the State property "processing" to TRUE', () => { + const expectedState = openaireBrokerTopicInitialState; + expectedState.processing = true; + + const action = new RetrieveAllTopicsAction(elementPerPage, currentPage); + const newState = openaireBrokerTopicsReducer(openaireBrokerTopicInitialState, action); + + expect(newState).toEqual(expectedState); + }); + + it('Action RETRIEVE_ALL_TOPICS_ERROR should change the State to initial State but processing, loaded, and currentPage', () => { + const expectedState = openaireBrokerTopicInitialState; + expectedState.processing = false; + expectedState.loaded = true; + expectedState.currentPage = 0; + + const action = new RetrieveAllTopicsErrorAction(); + const newState = openaireBrokerTopicsReducer(openaireBrokerTopicInitialState, action); + + expect(newState).toEqual(expectedState); + }); + + it('Action ADD_TOPICS should populate the State with OpenAIRE Broker topics', () => { + const expectedState = { + topics: [ openaireBrokerTopicObjectMorePid, openaireBrokerTopicObjectMoreAbstract ], + processing: false, + loaded: true, + totalPages: 1, + currentPage: 0, + totalElements: 2 + }; + + const action = new AddTopicsAction( + [ openaireBrokerTopicObjectMorePid, openaireBrokerTopicObjectMoreAbstract ], + 1, 0, 2 + ); + const newState = openaireBrokerTopicsReducer(openaireBrokerTopicInitialState, action); + + expect(newState).toEqual(expectedState); + }); +}); diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.reducer.ts b/src/app/openaire/broker/topics/openaire-broker-topics.reducer.ts new file mode 100644 index 00000000000..6ae596117f7 --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.reducer.ts @@ -0,0 +1,72 @@ +import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/openaire-broker-topic.model'; +import { OpenaireBrokerTopicActionTypes, OpenaireBrokerTopicsActions } from './openaire-broker-topics.actions'; + +/** + * The interface representing the OpenAIRE Broker topic state. + */ +export interface OpenaireBrokerTopicState { + topics: OpenaireBrokerTopicObject[]; + processing: boolean; + loaded: boolean; + totalPages: number; + currentPage: number; + totalElements: number; +} + +/** + * Used for the OpenAIRE Broker topic state initialization. + */ +const openaireBrokerTopicInitialState: OpenaireBrokerTopicState = { + topics: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0 +}; + +/** + * The OpenAIRE Broker Topic Reducer + * + * @param state + * the current state initialized with openaireBrokerTopicInitialState + * @param action + * the action to perform on the state + * @return OpenaireBrokerTopicState + * the new state + */ +export function openaireBrokerTopicsReducer(state = openaireBrokerTopicInitialState, action: OpenaireBrokerTopicsActions): OpenaireBrokerTopicState { + switch (action.type) { + case OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS: { + return Object.assign({}, state, { + topics: [], + processing: true + }); + } + + case OpenaireBrokerTopicActionTypes.ADD_TOPICS: { + return Object.assign({}, state, { + topics: action.payload.topics, + processing: false, + loaded: true, + totalPages: action.payload.totalPages, + currentPage: state.currentPage, + totalElements: action.payload.totalElements + }); + } + + case OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR: { + return Object.assign({}, state, { + processing: false, + loaded: true, + totalPages: 0, + currentPage: 0, + totalElements: 0 + }); + } + + default: { + return state; + } + } +} diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.service.spec.ts b/src/app/openaire/broker/topics/openaire-broker-topics.service.spec.ts new file mode 100644 index 00000000000..3daed2c3bf4 --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.service.spec.ts @@ -0,0 +1,67 @@ +import { TestBed } from '@angular/core/testing'; +import { of as observableOf } from 'rxjs'; +import { OpenaireBrokerTopicsService } from './openaire-broker-topics.service'; +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { OpenaireBrokerTopicRestService } from '../../../core/openaire/broker/topics/openaire-broker-topic-rest.service'; +import { PageInfo } from '../../../core/shared/page-info.model'; +import { FindListOptions } from '../../../core/data/request.models'; +import { + getMockOpenaireBrokerTopicRestService, + openaireBrokerTopicObjectMoreAbstract, + openaireBrokerTopicObjectMorePid +} from '../../../shared/mocks/openaire.mock'; +import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; +import { cold } from 'jasmine-marbles'; +import { buildPaginatedList } from '../../../core/data/paginated-list.model'; + +describe('OpenaireBrokerTopicsService', () => { + let service: OpenaireBrokerTopicsService; + let restService: OpenaireBrokerTopicRestService; + let serviceAsAny: any; + let restServiceAsAny: any; + + const pageInfo = new PageInfo(); + const array = [ openaireBrokerTopicObjectMorePid, openaireBrokerTopicObjectMoreAbstract ]; + const paginatedList = buildPaginatedList(pageInfo, array); + const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); + const elementsPerPage = 3; + const currentPage = 0; + + beforeEach(async () => { + TestBed.configureTestingModule({ + providers: [ + { provide: OpenaireBrokerTopicRestService, useClass: getMockOpenaireBrokerTopicRestService }, + { provide: OpenaireBrokerTopicsService, useValue: service } + ] + }).compileComponents(); + }); + + beforeEach(() => { + restService = TestBed.get(OpenaireBrokerTopicRestService); + restServiceAsAny = restService; + restServiceAsAny.getTopics.and.returnValue(observableOf(paginatedListRD)); + service = new OpenaireBrokerTopicsService(restService); + serviceAsAny = service; + }); + + describe('getTopics', () => { + it('Should proxy the call to openaireBrokerTopicRestService.getTopics', () => { + const sortOptions = new SortOptions('name', SortDirection.ASC); + const findListOptions: FindListOptions = { + elementsPerPage: elementsPerPage, + currentPage: currentPage, + sort: sortOptions + }; + const result = service.getTopics(elementsPerPage, currentPage); + expect((service as any).openaireBrokerTopicRestService.getTopics).toHaveBeenCalledWith(findListOptions); + }); + + it('Should return a paginated list of OpenAIRE Broker topics', () => { + const expected = cold('(a|)', { + a: paginatedList + }); + const result = service.getTopics(elementsPerPage, currentPage); + expect(result).toBeObservable(expected); + }); + }); +}); diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.service.ts b/src/app/openaire/broker/topics/openaire-broker-topics.service.ts new file mode 100644 index 00000000000..17f189922f1 --- /dev/null +++ b/src/app/openaire/broker/topics/openaire-broker-topics.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { find, map } from 'rxjs/operators'; +import { OpenaireBrokerTopicRestService } from '../../../core/openaire/broker/topics/openaire-broker-topic-rest.service'; +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { FindListOptions } from '../../../core/data/request.models'; +import { RemoteData } from '../../../core/data/remote-data'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/openaire-broker-topic.model'; + +/** + * The service handling all OpenAIRE Broker topic requests to the REST service. + */ +@Injectable() +export class OpenaireBrokerTopicsService { + + /** + * Initialize the service variables. + * @param {OpenaireBrokerTopicRestService} openaireBrokerTopicRestService + */ + constructor( + private openaireBrokerTopicRestService: OpenaireBrokerTopicRestService + ) { } + + /** + * Return the list of OpenAIRE Broker topics managing pagination and errors. + * + * @param elementsPerPage + * The number of the topics per page + * @param currentPage + * The page number to retrieve + * @return Observable> + * The list of OpenAIRE Broker topics. + */ + public getTopics(elementsPerPage, currentPage): Observable> { + const sortOptions = new SortOptions('name', SortDirection.ASC); + + const findListOptions: FindListOptions = { + elementsPerPage: elementsPerPage, + currentPage: currentPage, + sort: sortOptions + }; + + return this.openaireBrokerTopicRestService.getTopics(findListOptions).pipe( + find((rd: RemoteData>) => !rd.isResponsePending), + map((rd: RemoteData>) => { + if (rd.hasSucceeded) { + return rd.payload; + } else { + throw new Error('Can\'t retrieve OpenAIRE Broker topics from the Broker topics REST service'); + } + }) + ); + } +} diff --git a/src/app/openaire/openaire-state.service.spec.ts b/src/app/openaire/openaire-state.service.spec.ts new file mode 100644 index 00000000000..874d4b4e1a7 --- /dev/null +++ b/src/app/openaire/openaire-state.service.spec.ts @@ -0,0 +1,275 @@ +import { TestBed } from '@angular/core/testing'; +import { Store, StoreModule } from '@ngrx/store'; +import { provideMockStore } from '@ngrx/store/testing'; +import { cold } from 'jasmine-marbles'; +import { openaireReducers } from './openaire.reducer'; +import { OpenaireStateService } from './openaire-state.service'; +import { + openaireBrokerTopicObjectMissingPid, + openaireBrokerTopicObjectMoreAbstract, + openaireBrokerTopicObjectMorePid +} from '../shared/mocks/openaire.mock'; +import { RetrieveAllTopicsAction } from './broker/topics/openaire-broker-topics.actions'; + +describe('OpenaireStateService', () => { + let service: OpenaireStateService; + let serviceAsAny: any; + let store: any; + let initialState: any; + + function init(mode: string) { + if (mode === 'empty') { + initialState = { + openaire: { + brokerTopic: { + topics: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0, + totalLoadedPages: 0 + } + } + }; + } else { + initialState = { + openaire: { + brokerTopic: { + topics: [ + openaireBrokerTopicObjectMorePid, + openaireBrokerTopicObjectMoreAbstract, + openaireBrokerTopicObjectMissingPid + ], + processing: false, + loaded: true, + totalPages: 1, + currentPage: 1, + totalElements: 3, + totalLoadedPages: 1 + } + } + }; + } + } + + describe('Testing methods with empty topic objects', () => { + beforeEach(async () => { + init('empty'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ openaire: openaireReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: OpenaireStateService, useValue: service } + ] + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.get(Store); + service = new OpenaireStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('getOpenaireBrokerTopics', () => { + it('Should return an empty array', () => { + const result = service.getOpenaireBrokerTopics(); + const expected = cold('(a)', { + a: [] + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getOpenaireBrokerTopicsTotalPages', () => { + it('Should return zero (0)', () => { + const result = service.getOpenaireBrokerTopicsTotalPages(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getOpenaireBrokerTopicsCurrentPage', () => { + it('Should return minus one (0)', () => { + const result = service.getOpenaireBrokerTopicsCurrentPage(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getOpenaireBrokerTopicsTotals', () => { + it('Should return zero (0)', () => { + const result = service.getOpenaireBrokerTopicsTotals(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isOpenaireBrokerTopicsLoading', () => { + it('Should return TRUE', () => { + const result = service.isOpenaireBrokerTopicsLoading(); + const expected = cold('(a)', { + a: true + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isOpenaireBrokerTopicsLoaded', () => { + it('Should return FALSE', () => { + const result = service.isOpenaireBrokerTopicsLoaded(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isOpenaireBrokerTopicsProcessing', () => { + it('Should return FALSE', () => { + const result = service.isOpenaireBrokerTopicsProcessing(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + }); + + describe('Testing methods with topic objects', () => { + beforeEach(async () => { + init('full'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ openaire: openaireReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: OpenaireStateService, useValue: service } + ] + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.get(Store); + service = new OpenaireStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('getOpenaireBrokerTopics', () => { + it('Should return an array of topics', () => { + const result = service.getOpenaireBrokerTopics(); + const expected = cold('(a)', { + a: [ + openaireBrokerTopicObjectMorePid, + openaireBrokerTopicObjectMoreAbstract, + openaireBrokerTopicObjectMissingPid + ] + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getOpenaireBrokerTopicsTotalPages', () => { + it('Should return one (1)', () => { + const result = service.getOpenaireBrokerTopicsTotalPages(); + const expected = cold('(a)', { + a: 1 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getOpenaireBrokerTopicsCurrentPage', () => { + it('Should return minus zero (1)', () => { + const result = service.getOpenaireBrokerTopicsCurrentPage(); + const expected = cold('(a)', { + a: 1 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getOpenaireBrokerTopicsTotals', () => { + it('Should return three (3)', () => { + const result = service.getOpenaireBrokerTopicsTotals(); + const expected = cold('(a)', { + a: 3 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isOpenaireBrokerTopicsLoading', () => { + it('Should return FALSE', () => { + const result = service.isOpenaireBrokerTopicsLoading(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isOpenaireBrokerTopicsLoaded', () => { + it('Should return TRUE', () => { + const result = service.isOpenaireBrokerTopicsLoaded(); + const expected = cold('(a)', { + a: true + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isOpenaireBrokerTopicsProcessing', () => { + it('Should return FALSE', () => { + const result = service.isOpenaireBrokerTopicsProcessing(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + }); + + describe('Testing the topic dispatch methods', () => { + beforeEach(async () => { + init('full'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ openaire: openaireReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: OpenaireStateService, useValue: service } + ] + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.get(Store); + service = new OpenaireStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('dispatchRetrieveOpenaireBrokerTopics', () => { + it('Should call store.dispatch', () => { + const elementsPerPage = 3; + const currentPage = 1; + const action = new RetrieveAllTopicsAction(elementsPerPage, currentPage); + service.dispatchRetrieveOpenaireBrokerTopics(elementsPerPage, currentPage); + expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action); + }); + }); + }); +}); diff --git a/src/app/openaire/openaire-state.service.ts b/src/app/openaire/openaire-state.service.ts new file mode 100644 index 00000000000..10dd739ae5c --- /dev/null +++ b/src/app/openaire/openaire-state.service.ts @@ -0,0 +1,116 @@ +import { Injectable } from '@angular/core'; +import { select, Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { + getOpenaireBrokerTopicsCurrentPageSelector, + getOpenaireBrokerTopicsTotalPagesSelector, + getOpenaireBrokerTopicsTotalsSelector, + isOpenaireBrokerTopicsLoadedSelector, + openaireBrokerTopicsObjectSelector, + sOpenaireBrokerTopicsProcessingSelector +} from './selectors'; +import { OpenaireBrokerTopicObject } from '../core/openaire/broker/models/openaire-broker-topic.model'; +import { OpenaireState } from './openaire.reducer'; +import { RetrieveAllTopicsAction } from './broker/topics/openaire-broker-topics.actions'; + +/** + * The service handling the OpenAIRE State. + */ +@Injectable() +export class OpenaireStateService { + + /** + * Initialize the service variables. + * @param {Store} store + */ + constructor(private store: Store) { } + + // OpenAIRE Broker topics + // -------------------------------------------------------------------------- + + /** + * Returns the list of OpenAIRE Broker topics from the state. + * + * @return Observable + * The list of OpenAIRE Broker topics. + */ + public getOpenaireBrokerTopics(): Observable { + return this.store.pipe(select(openaireBrokerTopicsObjectSelector())); + } + + /** + * Returns the information about the loading status of the OpenAIRE Broker topics (if it's running or not). + * + * @return Observable + * 'true' if the topics are loading, 'false' otherwise. + */ + public isOpenaireBrokerTopicsLoading(): Observable { + return this.store.pipe( + select(isOpenaireBrokerTopicsLoadedSelector), + map((loaded: boolean) => !loaded) + ); + } + + /** + * Returns the information about the loading status of the OpenAIRE Broker topics (whether or not they were loaded). + * + * @return Observable + * 'true' if the topics are loaded, 'false' otherwise. + */ + public isOpenaireBrokerTopicsLoaded(): Observable { + return this.store.pipe(select(isOpenaireBrokerTopicsLoadedSelector)); + } + + /** + * Returns the information about the processing status of the OpenAIRE Broker topics (if it's running or not). + * + * @return Observable + * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. + */ + public isOpenaireBrokerTopicsProcessing(): Observable { + return this.store.pipe(select(sOpenaireBrokerTopicsProcessingSelector)); + } + + /** + * Returns, from the state, the total available pages of the OpenAIRE Broker topics. + * + * @return Observable + * The number of the OpenAIRE Broker topics pages. + */ + public getOpenaireBrokerTopicsTotalPages(): Observable { + return this.store.pipe(select(getOpenaireBrokerTopicsTotalPagesSelector)); + } + + /** + * Returns the current page of the OpenAIRE Broker topics, from the state. + * + * @return Observable + * The number of the current OpenAIRE Broker topics page. + */ + public getOpenaireBrokerTopicsCurrentPage(): Observable { + return this.store.pipe(select(getOpenaireBrokerTopicsCurrentPageSelector)); + } + + /** + * Returns the total number of the OpenAIRE Broker topics. + * + * @return Observable + * The number of the OpenAIRE Broker topics. + */ + public getOpenaireBrokerTopicsTotals(): Observable { + return this.store.pipe(select(getOpenaireBrokerTopicsTotalsSelector)); + } + + /** + * Dispatch a request to change the OpenAIRE Broker topics state, retrieving the topics from the server. + * + * @param elementsPerPage + * The number of the topics per page. + * @param currentPage + * The number of the current page. + */ + public dispatchRetrieveOpenaireBrokerTopics(elementsPerPage: number, currentPage: number): void { + this.store.dispatch(new RetrieveAllTopicsAction(elementsPerPage, currentPage)); + } +} diff --git a/src/app/openaire/openaire.effects.ts b/src/app/openaire/openaire.effects.ts new file mode 100644 index 00000000000..9861c1a921c --- /dev/null +++ b/src/app/openaire/openaire.effects.ts @@ -0,0 +1,5 @@ +import { OpenaireBrokerTopicsEffects } from './broker/topics/openaire-broker-topics.effects'; + +export const openaireEffects = [ + OpenaireBrokerTopicsEffects +]; diff --git a/src/app/openaire/openaire.module.ts b/src/app/openaire/openaire.module.ts new file mode 100644 index 00000000000..ac5d4e72872 --- /dev/null +++ b/src/app/openaire/openaire.module.ts @@ -0,0 +1,74 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Action, StoreConfig, StoreModule } from '@ngrx/store'; +import { EffectsModule } from '@ngrx/effects'; + +import { CoreModule } from '../core/core.module'; +import { SharedModule } from '../shared/shared.module'; +import { storeModuleConfig } from '../app.reducer'; +import { OpenaireBrokerTopicsComponent } from './broker/topics/openaire-broker-topics.component'; +import { OpenaireBrokerEventsComponent } from './broker/events/openaire-broker-events.component'; +import { OpenaireStateService } from './openaire-state.service'; +import { openaireReducers, OpenaireState } from './openaire.reducer'; +import { openaireEffects } from './openaire.effects'; +import { OpenaireBrokerTopicsService } from './broker/topics/openaire-broker-topics.service'; +import { OpenaireBrokerTopicRestService } from '../core/openaire/broker/topics/openaire-broker-topic-rest.service'; +import { OpenaireBrokerEventRestService } from '../core/openaire/broker/events/openaire-broker-event-rest.service'; +import { ProjectEntryImportModalComponent } from './broker/project-entry-import-modal/project-entry-import-modal.component'; +import { TranslateModule } from '@ngx-translate/core'; +import { SearchModule } from '../shared/search/search.module'; + +const MODULES = [ + CommonModule, + SharedModule, + CoreModule.forRoot(), + StoreModule.forFeature('openaire', openaireReducers, storeModuleConfig as StoreConfig), + EffectsModule.forFeature(openaireEffects), + TranslateModule +]; + +const COMPONENTS = [ + OpenaireBrokerTopicsComponent, + OpenaireBrokerEventsComponent +]; + +const DIRECTIVES = [ ]; + +const ENTRY_COMPONENTS = [ + ProjectEntryImportModalComponent +]; + +const PROVIDERS = [ + OpenaireStateService, + OpenaireBrokerTopicsService, + OpenaireBrokerTopicRestService, + OpenaireBrokerEventRestService +]; + +@NgModule({ + imports: [ + ...MODULES, + SearchModule + ], + declarations: [ + ...COMPONENTS, + ...DIRECTIVES, + ...ENTRY_COMPONENTS + ], + providers: [ + ...PROVIDERS + ], + entryComponents: [ + ...ENTRY_COMPONENTS + ], + exports: [ + ...COMPONENTS, + ...DIRECTIVES + ] +}) + +/** + * This module handles all components that are necessary for the OpenAIRE components + */ +export class OpenaireModule { +} diff --git a/src/app/openaire/openaire.reducer.ts b/src/app/openaire/openaire.reducer.ts new file mode 100644 index 00000000000..9ead098329e --- /dev/null +++ b/src/app/openaire/openaire.reducer.ts @@ -0,0 +1,16 @@ +import { ActionReducerMap, createFeatureSelector } from '@ngrx/store'; + +import { openaireBrokerTopicsReducer, OpenaireBrokerTopicState, } from './broker/topics/openaire-broker-topics.reducer'; + +/** + * The OpenAIRE State + */ +export interface OpenaireState { + 'brokerTopic': OpenaireBrokerTopicState; +} + +export const openaireReducers: ActionReducerMap = { + brokerTopic: openaireBrokerTopicsReducer, +}; + +export const openaireSelector = createFeatureSelector('openaire'); diff --git a/src/app/openaire/selectors.ts b/src/app/openaire/selectors.ts new file mode 100644 index 00000000000..fc3508eef4a --- /dev/null +++ b/src/app/openaire/selectors.ts @@ -0,0 +1,79 @@ +import { createSelector, MemoizedSelector } from '@ngrx/store'; +import { subStateSelector } from '../shared/selector.util'; +import { openaireSelector, OpenaireState } from './openaire.reducer'; +import { OpenaireBrokerTopicObject } from '../core/openaire/broker/models/openaire-broker-topic.model'; +import { OpenaireBrokerTopicState } from './broker/topics/openaire-broker-topics.reducer'; + +/** + * Returns the OpenAIRE state. + * @function _getOpenaireState + * @param {AppState} state Top level state. + * @return {OpenaireState} + */ +const _getOpenaireState = (state: any) => state.openaire; + +// OpenAIRE Broker topics +// ---------------------------------------------------------------------------- + +/** + * Returns the OpenAIRE Broker topics State. + * @function openaireBrokerTopicsStateSelector + * @return {OpenaireBrokerTopicState} + */ +export function openaireBrokerTopicsStateSelector(): MemoizedSelector { + return subStateSelector(openaireSelector, 'brokerTopic'); +} + +/** + * Returns the OpenAIRE Broker topics list. + * @function openaireBrokerTopicsObjectSelector + * @return {OpenaireBrokerTopicObject[]} + */ +export function openaireBrokerTopicsObjectSelector(): MemoizedSelector { + return subStateSelector(openaireBrokerTopicsStateSelector(), 'topics'); +} + +/** + * Returns true if the OpenAIRE Broker topics are loaded. + * @function isOpenaireBrokerTopicsLoadedSelector + * @return {boolean} + */ +export const isOpenaireBrokerTopicsLoadedSelector = createSelector(_getOpenaireState, + (state: OpenaireState) => state.brokerTopic.loaded +); + +/** + * Returns true if the deduplication sets are processing. + * @function isDeduplicationSetsProcessingSelector + * @return {boolean} + */ +export const sOpenaireBrokerTopicsProcessingSelector = createSelector(_getOpenaireState, + (state: OpenaireState) => state.brokerTopic.processing +); + +/** + * Returns the total available pages of OpenAIRE Broker topics. + * @function getOpenaireBrokerTopicsTotalPagesSelector + * @return {number} + */ +export const getOpenaireBrokerTopicsTotalPagesSelector = createSelector(_getOpenaireState, + (state: OpenaireState) => state.brokerTopic.totalPages +); + +/** + * Returns the current page of OpenAIRE Broker topics. + * @function getOpenaireBrokerTopicsCurrentPageSelector + * @return {number} + */ +export const getOpenaireBrokerTopicsCurrentPageSelector = createSelector(_getOpenaireState, + (state: OpenaireState) => state.brokerTopic.currentPage +); + +/** + * Returns the total number of OpenAIRE Broker topics. + * @function getOpenaireBrokerTopicsTotalsSelector + * @return {number} + */ +export const getOpenaireBrokerTopicsTotalsSelector = createSelector(_getOpenaireState, + (state: OpenaireState) => state.brokerTopic.totalElements +); diff --git a/src/app/shared/mocks/openaire.mock.ts b/src/app/shared/mocks/openaire.mock.ts new file mode 100644 index 00000000000..908aae1f679 --- /dev/null +++ b/src/app/shared/mocks/openaire.mock.ts @@ -0,0 +1,1796 @@ +import { of as observableOf } from 'rxjs'; +import { ResourceType } from '../../core/shared/resource-type'; +import { OpenaireBrokerTopicObject } from '../../core/openaire/broker/models/openaire-broker-topic.model'; +import { OpenaireBrokerEventObject } from '../../core/openaire/broker/models/openaire-broker-event.model'; +import { OpenaireBrokerTopicRestService } from '../../core/openaire/broker/topics/openaire-broker-topic-rest.service'; +import { OpenaireBrokerEventRestService } from '../../core/openaire/broker/events/openaire-broker-event-rest.service'; +import { DSpaceObject } from '../../core/shared/dspace-object.model'; +import { OpenaireStateService } from '../../openaire/openaire-state.service'; +import { Item } from '../../core/shared/item.model'; +import { + createNoContentRemoteDataObject$, + createSuccessfulRemoteDataObject, + createSuccessfulRemoteDataObject$ +} from '../remote-data.utils'; +import { SearchResult } from '../search/models/search-result.model'; + +// REST Mock --------------------------------------------------------------------- +// ------------------------------------------------------------------------------- + +// Items +// ------------------------------------------------------------------------------- + +const ItemMockPid1: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174001', + uuid: 'ITEM4567-e89b-12d3-a456-426614174001', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Index nominum et rerum' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +const ItemMockPid2: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174004', + uuid: 'ITEM4567-e89b-12d3-a456-426614174004', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'UNA NUOVA RILETTURA DELL\u0027 ARISTOTELE DI FRANZ BRENTANO ALLA LUCE DI ALCUNI INEDITI' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +const ItemMockPid3: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174005', + uuid: 'ITEM4567-e89b-12d3-a456-426614174005', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Sustainable development' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +const ItemMockPid4: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174006', + uuid: 'ITEM4567-e89b-12d3-a456-426614174006', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Reply to Critics' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +const ItemMockPid5: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174007', + uuid: 'ITEM4567-e89b-12d3-a456-426614174007', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'PROGETTAZIONE, SINTESI E VALUTAZIONE DELL\u0027ATTIVITA\u0027 ANTIMICOBATTERICA ED ANTIFUNGINA DI NUOVI DERIVATI ETEROCICLICI' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +const ItemMockPid6: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174008', + uuid: 'ITEM4567-e89b-12d3-a456-426614174008', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Donald Davidson' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +const ItemMockPid7: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174009', + uuid: 'ITEM4567-e89b-12d3-a456-426614174009', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Missing abstract article' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +export const ItemMockPid8: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174002', + uuid: 'ITEM4567-e89b-12d3-a456-426614174002', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Egypt, crossroad of translations and literary interweavings (3rd-6th centuries). A reconsideration of earlier Coptic literature' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +export const ItemMockPid9: Item = Object.assign( + new Item(), + { + handle: '10077/21486', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'ITEM4567-e89b-12d3-a456-426614174003', + uuid: 'ITEM4567-e89b-12d3-a456-426614174003', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Morocco, crossroad of translations and literary interweavings (3rd-6th centuries). A reconsideration of earlier Coptic literature' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +export const ItemMockPid10: Item = Object.assign( + new Item(), + { + handle: '10713/29832', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'P23e4567-e89b-12d3-a456-426614174002', + uuid: 'P23e4567-e89b-12d3-a456-426614174002', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Tracking Papyrus and Parchment Paths: An Archaeological Atlas of Coptic Literature.\nLiterary Texts in their Geographical Context: Production, Copying, Usage, Dissemination and Storage' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +export const OpenaireMockDspaceObject: SearchResult = Object.assign( + new SearchResult(), + { + handle: '10713/29832', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: true, + isWithdrawn: false, + _links:{ + self: { + href: 'https://rest.api/rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, + id: 'P23e4567-e89b-12d3-a456-426614174002', + uuid: 'P23e4567-e89b-12d3-a456-426614174002', + type: 'item', + metadata: { + 'dc.creator': [ + { + language: 'en_US', + value: 'Doe, Jane' + } + ], + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26' + } + ], + 'dc.identifier.issn': [ + { + language: 'en_US', + value: '123456789' + } + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is really just a sample abstract. If it was a real abstract it would contain useful information about this test document. Sorry though, nothing useful in this paragraph. You probably shouldn\'t have even bothered to read it!' + } + ], + 'dc.description.provenance': [ + { + language: 'en', + value: 'Made available in DSpace on 2012-06-26T19:58:25Z (GMT). No. of bitstreams: 2\r\ntest_ppt.ppt: 12707328 bytes, checksum: a353fc7d29b3c558c986f7463a41efd3 (MD5)\r\ntest_ppt.pptx: 12468572 bytes, checksum: 599305edb4ebee329667f2c35b14d1d6 (MD5)' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T09:17:34Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2013-06-13T11:04:16Z (GMT).' + }, + { + language: 'en', + value: 'Restored into DSpace on 2017-04-24T19:44:08Z (GMT).' + } + ], + 'dc.language': [ + { + language: 'en_US', + value: 'en' + } + ], + 'dc.rights': [ + { + language: 'en_US', + value: '© Jane Doe' + } + ], + 'dc.subject': [ + { + language: 'en_US', + value: 'keyword1' + }, + { + language: 'en_US', + value: 'keyword2' + }, + { + language: 'en_US', + value: 'keyword3' + } + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Tracking Papyrus and Parchment Paths: An Archaeological Atlas of Coptic Literature.\nLiterary Texts in their Geographical Context: Production, Copying, Usage, Dissemination and Storage' + } + ], + 'dc.type': [ + { + language: 'en_US', + value: 'text' + } + ] + } + } +); + +// Topics +// ------------------------------------------------------------------------------- + +export const openaireBrokerTopicObjectMorePid: OpenaireBrokerTopicObject = { + type: new ResourceType('nbtopic'), + id: 'ENRICH!MORE!PID', + name: 'ENRICH/MORE/PID', + lastEvent: '2020/10/09 10:11 UTC', + totalEvents: 33, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbtopics/ENRICH!MORE!PID' + } + } +}; + +export const openaireBrokerTopicObjectMoreAbstract: OpenaireBrokerTopicObject = { + type: new ResourceType('nbtopic'), + id: 'ENRICH!MORE!ABSTRACT', + name: 'ENRICH/MORE/ABSTRACT', + lastEvent: '2020/09/08 21:14 UTC', + totalEvents: 5, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbtopics/ENRICH!MORE!ABSTRACT' + } + } +}; + +export const openaireBrokerTopicObjectMissingPid: OpenaireBrokerTopicObject = { + type: new ResourceType('nbtopic'), + id: 'ENRICH!MISSING!PID', + name: 'ENRICH/MISSING/PID', + lastEvent: '2020/10/01 07:36 UTC', + totalEvents: 4, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbtopics/ENRICH!MISSING!PID' + } + } +}; + +export const openaireBrokerTopicObjectMissingAbstract: OpenaireBrokerTopicObject = { + type: new ResourceType('nbtopic'), + id: 'ENRICH!MISSING!ABSTRACT', + name: 'ENRICH/MISSING/ABSTRACT', + lastEvent: '2020/10/08 16:14 UTC', + totalEvents: 71, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbtopics/ENRICH!MISSING!ABSTRACT' + } + } +}; + +export const openaireBrokerTopicObjectMissingAcm: OpenaireBrokerTopicObject = { + type: new ResourceType('nbtopic'), + id: 'ENRICH!MISSING!SUBJECT!ACM', + name: 'ENRICH/MISSING/SUBJECT/ACM', + lastEvent: '2020/09/21 17:51 UTC', + totalEvents: 18, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbtopics/ENRICH!MISSING!SUBJECT!ACM' + } + } +}; + +export const openaireBrokerTopicObjectMissingProject: OpenaireBrokerTopicObject = { + type: new ResourceType('nbtopic'), + id: 'ENRICH!MISSING!PROJECT', + name: 'ENRICH/MISSING/PROJECT', + lastEvent: '2020/09/17 10:28 UTC', + totalEvents: 6, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbtopics/ENRICH!MISSING!PROJECT' + } + } +}; + +// Events +// ------------------------------------------------------------------------------- + +export const openaireBrokerEventObjectMissingPid: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174001', + uuid: '123e4567-e89b-12d3-a456-426614174001', + type: new ResourceType('nbevent'), + originalId: 'oai:www.openstarts.units.it:10077/21486', + title: 'Index nominum et rerum', + trust: 0.375, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: 'doi', + value: '10.18848/1447-9494/cgp/v15i09/45934', + abstract: null, + openaireId: null, + acronym: null, + code: null, + funder: null, + fundingProgram: null, + jurisdiction: null, + title: null + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174001', + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174001/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174001/related' + } + }, + target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid1)), + related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) +}; + +export const openaireBrokerEventObjectMissingPid2: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174004', + uuid: '123e4567-e89b-12d3-a456-426614174004', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/21486', + title: 'UNA NUOVA RILETTURA DELL\u0027 ARISTOTELE DI FRANZ BRENTANO ALLA LUCE DI ALCUNI INEDITI', + trust: 1.0, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: 'urn', + value: 'http://thesis2.sba.units.it/store/handle/item/12238', + abstract: null, + openaireId: null, + acronym: null, + code: null, + funder: null, + fundingProgram: null, + jurisdiction: null, + title: null + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174004' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174004/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174004/related' + } + }, + target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid2)), + related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) +}; + +export const openaireBrokerEventObjectMissingPid3: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174005', + uuid: '123e4567-e89b-12d3-a456-426614174005', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/554', + title: 'Sustainable development', + trust: 0.375, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: 'doi', + value: '10.4324/9780203408889', + abstract: null, + openaireId: null, + acronym: null, + code: null, + funder: null, + fundingProgram: null, + jurisdiction: null, + title: null + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174005' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174005/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174005/related' + } + }, + target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid3)), + related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) +}; + +export const openaireBrokerEventObjectMissingPid4: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174006', + uuid: '123e4567-e89b-12d3-a456-426614174006', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/10787', + title: 'Reply to Critics', + trust: 1.0, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: 'doi', + value: '10.1080/13698230.2018.1430104', + abstract: null, + openaireId: null, + acronym: null, + code: null, + funder: null, + fundingProgram: null, + jurisdiction: null, + title: null + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174006' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174006/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174006/related' + } + }, + target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid4)), + related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) +}; + +export const openaireBrokerEventObjectMissingPid5: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174007', + uuid: '123e4567-e89b-12d3-a456-426614174007', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/11339', + title: 'PROGETTAZIONE, SINTESI E VALUTAZIONE DELL\u0027ATTIVITA\u0027 ANTIMICOBATTERICA ED ANTIFUNGINA DI NUOVI DERIVATI ETEROCICLICI', + trust: 0.375, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: 'urn', + value: 'http://thesis2.sba.units.it/store/handle/item/12477', + abstract: null, + openaireId: null, + acronym: null, + code: null, + funder: null, + fundingProgram: null, + jurisdiction: null, + title: null + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174007' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174007/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174007/related' + } + }, + target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid5)), + related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) +}; + +export const openaireBrokerEventObjectMissingPid6: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174008', + uuid: '123e4567-e89b-12d3-a456-426614174008', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/29860', + title: 'Donald Davidson', + trust: 0.375, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: 'doi', + value: '10.1111/j.1475-4975.2004.00098.x', + abstract: null, + openaireId: null, + acronym: null, + code: null, + funder: null, + fundingProgram: null, + jurisdiction: null, + title: null + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174008' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174008/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174008/related' + } + }, + target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid6)), + related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) +}; + +export const openaireBrokerEventObjectMissingAbstract: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174009', + uuid: '123e4567-e89b-12d3-a456-426614174009', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/21110', + title: 'Missing abstract article', + trust: 0.751, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: null, + value: null, + abstract: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla scelerisque vestibulum tellus sed lacinia. Aenean vitae sapien a quam congue ultrices. Sed vehicula sollicitudin ligula, vitae lacinia velit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla scelerisque vestibulum tellus sed lacinia. Aenean vitae sapien a quam congue ultrices. Sed vehicula sollicitudin ligula, vitae lacinia velit.', + openaireId: null, + acronym: null, + code: null, + funder: null, + fundingProgram: null, + jurisdiction: null, + title: null + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174009' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174009/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174009/related' + } + }, + target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid7)), + related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) +}; + +export const openaireBrokerEventObjectMissingProjectFound: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174002', + uuid: '123e4567-e89b-12d3-a456-426614174002', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/21838', + title: 'Egypt, crossroad of translations and literary interweavings (3rd-6th centuries). A reconsideration of earlier Coptic literature', + trust: 1.0, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: null, + value: null, + abstract: null, + openaireId: null, + acronym: 'PAThs', + code: '687567', + funder: 'EC', + fundingProgram: 'H2020', + jurisdiction: 'EU', + title: 'Tracking Papyrus and Parchment Paths: An Archaeological Atlas of Coptic Literature.\nLiterary Texts in their Geographical Context: Production, Copying, Usage, Dissemination and Storage' + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174002' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174002/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174002/related' + } + }, + target: createSuccessfulRemoteDataObject$(ItemMockPid8), + related: createSuccessfulRemoteDataObject$(ItemMockPid10) +}; + +export const openaireBrokerEventObjectMissingProjectNotFound: OpenaireBrokerEventObject = { + id: '123e4567-e89b-12d3-a456-426614174003', + uuid: '123e4567-e89b-12d3-a456-426614174003', + type: new ResourceType('openaireBrokerEvent'), + originalId: 'oai:www.openstarts.units.it:10077/21838', + title: 'Morocco, crossroad of translations and literary interweavings (3rd-6th centuries). A reconsideration of earlier Coptic literature', + trust: 1.0, + eventDate: '2020/10/09 10:11 UTC', + status: 'PENDING', + message: { + type: null, + value: null, + abstract: null, + openaireId: null, + acronym: 'PAThs', + code: '687567B', + funder: 'EC', + fundingProgram: 'H2021', + jurisdiction: 'EU', + title: 'Tracking Unknown Papyrus and Parchment Paths: An Archaeological Atlas of Coptic Literature.\nLiterary Texts in their Geographical Context: Production, Copying, Usage, Dissemination and Storage' + }, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174003' + }, + target: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174003/target' + }, + related: { + href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174003/related' + } + }, + target: createSuccessfulRemoteDataObject$(ItemMockPid9), + related: createNoContentRemoteDataObject$() +}; + +// Classes +// ------------------------------------------------------------------------------- + +/** + * Mock for [[OpenaireStateService]] + */ +export function getMockOpenaireStateService(): any { + return jasmine.createSpyObj('OpenaireStateService', { + getOpenaireBrokerTopics: jasmine.createSpy('getOpenaireBrokerTopics'), + isOpenaireBrokerTopicsLoading: jasmine.createSpy('isOpenaireBrokerTopicsLoading'), + isOpenaireBrokerTopicsLoaded: jasmine.createSpy('isOpenaireBrokerTopicsLoaded'), + isOpenaireBrokerTopicsProcessing: jasmine.createSpy('isOpenaireBrokerTopicsProcessing'), + getOpenaireBrokerTopicsTotalPages: jasmine.createSpy('getOpenaireBrokerTopicsTotalPages'), + getOpenaireBrokerTopicsCurrentPage: jasmine.createSpy('getOpenaireBrokerTopicsCurrentPage'), + getOpenaireBrokerTopicsTotals: jasmine.createSpy('getOpenaireBrokerTopicsTotals'), + dispatchRetrieveOpenaireBrokerTopics: jasmine.createSpy('dispatchRetrieveOpenaireBrokerTopics'), + dispatchMarkUserSuggestionsAsVisitedAction: jasmine.createSpy('dispatchMarkUserSuggestionsAsVisitedAction') + }); +} + +/** + * Mock for [[OpenaireBrokerTopicRestService]] + */ +export function getMockOpenaireBrokerTopicRestService(): OpenaireBrokerTopicRestService { + return jasmine.createSpyObj('OpenaireBrokerTopicRestService', { + getTopics: jasmine.createSpy('getTopics'), + getTopic: jasmine.createSpy('getTopic'), + }); +} + +/** + * Mock for [[OpenaireBrokerEventRestService]] + */ +export function getMockOpenaireBrokerEventRestService(): OpenaireBrokerEventRestService { + return jasmine.createSpyObj('OpenaireBrokerEventRestService', { + getEventsByTopic: jasmine.createSpy('getEventsByTopic'), + getEvent: jasmine.createSpy('getEvent'), + patchEvent: jasmine.createSpy('patchEvent'), + boundProject: jasmine.createSpy('boundProject'), + removeProject: jasmine.createSpy('removeProject'), + clearFindByTopicRequests: jasmine.createSpy('.clearFindByTopicRequests') + }); +} + +/** + * Mock for [[OpenaireBrokerEventRestService]] + */ +export function getMockSuggestionsService(): any { + return jasmine.createSpyObj('SuggestionsService', { + getTargets: jasmine.createSpy('getTargets'), + getSuggestions: jasmine.createSpy('getSuggestions'), + clearSuggestionRequests: jasmine.createSpy('clearSuggestionRequests'), + deleteReviewedSuggestion: jasmine.createSpy('deleteReviewedSuggestion'), + retrieveCurrentUserSuggestions: jasmine.createSpy('retrieveCurrentUserSuggestions'), + getTargetUuid: jasmine.createSpy('getTargetUuid'), + }); +} diff --git a/src/app/shared/pagination/pagination.component.html b/src/app/shared/pagination/pagination.component.html index 2a9aa1a0624..e980e733136 100644 --- a/src/app/shared/pagination/pagination.component.html +++ b/src/app/shared/pagination/pagination.component.html @@ -11,8 +11,10 @@
- - + + + +
diff --git a/src/app/shared/pagination/pagination.component.ts b/src/app/shared/pagination/pagination.component.ts index 8f1c6bf26fe..50210c4794d 100644 --- a/src/app/shared/pagination/pagination.component.ts +++ b/src/app/shared/pagination/pagination.component.ts @@ -93,6 +93,11 @@ export class PaginationComponent implements OnDestroy, OnInit { */ @Input() public hideGear = false; + /** + * Option for hiding the gear + */ + @Input() public hideSortOptions = false; + /** * Option for hiding the pager when there is less than 2 pages */ diff --git a/src/app/shared/selector.util.ts b/src/app/shared/selector.util.ts new file mode 100644 index 00000000000..2343e12f1aa --- /dev/null +++ b/src/app/shared/selector.util.ts @@ -0,0 +1,27 @@ +import { createSelector, MemoizedSelector, Selector } from '@ngrx/store'; +import { hasValue } from './empty.util'; + +/** + * Export a function to return a subset of the state by key + */ +export function keySelector(parentSelector: Selector, subState: string, key: string): MemoizedSelector { + return createSelector(parentSelector, (state: T) => { + if (hasValue(state) && hasValue(state[subState])) { + return state[subState][key]; + } else { + return undefined; + } + }); +} +/** + * Export a function to return a subset of the state + */ +export function subStateSelector(parentSelector: Selector, subState: string): MemoizedSelector { + return createSelector(parentSelector, (state: T) => { + if (hasValue(state) && hasValue(state[subState])) { + return state[subState]; + } else { + return undefined; + } + }); +} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index f742273edbe..360e50790a3 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -479,7 +479,13 @@ "admin.access-control.groups.form.return": "Back", + "admin.notifications.openairebroker.breadcrumbs": "OpenAIRE Broker", + "admin.notifications.openairebroker.page.title": "OpenAIRE Broker", + + "admin.notifications.openaireevent.breadcrumbs": "OpenAIRE Broker Suggestions", + + "admin.notifications.openaireevent.page.title": "OpenAIRE Broker Suggestions", "admin.search.breadcrumbs": "Administrative Search", @@ -2408,6 +2414,7 @@ + "menu.header.admin": "Management", "menu.header.image.logo": "Repository logo", @@ -2510,6 +2517,8 @@ "menu.section.icon.unpin": "Unpin sidebar", + "menu.section.icon.notifications": "Notifications menu section", + "menu.section.import": "Import", @@ -2533,6 +2542,12 @@ "menu.section.new_process": "Process", + "menu.section.notifications": "Notifications", + + "menu.section.notifications_openaire_broker": "OpenAIRE Broker", + + "menu.section.notifications_reciter": "Publication Claim", + "menu.section.pin": "Pin sidebar", @@ -2698,6 +2713,126 @@ "none.listelement.badge": "Item", + "openaire.broker.title": "OpenAIRE Broker", + + "openaire.broker.topics.description": "Below you can see all the topics received from the subscriptions to OpenAIRE.", + + "openaire.broker.topics": "Current Topics", + + "openaire.broker.table.topic": "Topic", + + "openaire.broker.table.last-event": "Last Event", + + "openaire.broker.table.actions": "Actions", + + "openaire.broker.button.detail": "Show details", + + "openaire.broker.noTopics": "No topics found.", + + "openaire.broker.topic.error.service.retrieve": "An error occurred while loading the OpenAIRE Broker topics", + + "openaire.broker.loading": "Loading ...", + + "openaire.events.title": "OpenAIRE Broker Suggestions", + + "openaire.broker.events.description": "Below the list of all the suggestions, received from OpenAIRE, for the selected topic.", + + "openaire.broker.events.topic": "Topic:", + + "openaire.broker.noEvents": "No suggestions found.", + + "openaire.broker.event.table.trust": "Trust", + + "openaire.broker.event.table.publication": "Publication", + + "openaire.broker.event.table.details": "Details", + + "openaire.broker.event.table.project-details": "Project details", + + "openaire.broker.event.table.actions": "Actions", + + "openaire.broker.event.action.accept": "Accept suggestion", + + "openaire.broker.event.action.ignore": "Ignore suggestion", + + "openaire.broker.event.action.reject": "Reject suggestion", + + "openaire.broker.event.action.import": "Import project and accept suggestion", + + "openaire.broker.event.table.pidtype": "PID Type:", + + "openaire.broker.event.table.pidvalue": "PID Value:", + + "openaire.broker.event.table.subjectValue": "Subject Value:", + + "openaire.broker.event.table.abstract": "Abstract:", + + "openaire.broker.event.table.suggestedProject": "OpenAIRE Suggested Project data", + + "openaire.broker.event.table.project": "Project title:", + + "openaire.broker.event.table.acronym": "Acronym:", + + "openaire.broker.event.table.code": "Code:", + + "openaire.broker.event.table.funder": "Funder:", + + "openaire.broker.event.table.fundingProgram": "Funding program:", + + "openaire.broker.event.table.jurisdiction": "Jurisdiction:", + + "openaire.broker.events.back": "Back to topics", + + "openaire.broker.event.table.less": "Show less", + + "openaire.broker.event.table.more": "Show more", + + "openaire.broker.event.project.found": "Bound to the local record:", + + "openaire.broker.event.project.notFound": "No local record found", + + "openaire.broker.event.sure": "Are you sure?", + + "openaire.broker.event.ignore.description": "This operation can't be undone. Ignore this suggestion?", + + "openaire.broker.event.reject.description": "This operation can't be undone. Reject this suggestion?", + + "openaire.broker.event.accept.description": "No DSpace project selected. A new project will be created based on the suggestion data.", + + "openaire.broker.event.action.cancel": "Cancel", + + "openaire.broker.event.action.saved": "Your decision has been saved successfully.", + + "openaire.broker.event.action.error": "An error has occurred. Your decision has not been saved.", + + "openaire.broker.event.modal.project.title": "Choose a project to bound", + + "openaire.broker.event.modal.project.publication": "Publication:", + + "openaire.broker.event.modal.project.bountToLocal": "Bound to the local record:", + + "openaire.broker.event.modal.project.select": "Project search", + + "openaire.broker.event.modal.project.search": "Search", + + "openaire.broker.event.modal.project.clear": "Clear", + + "openaire.broker.event.modal.project.cancel": "Cancel", + + "openaire.broker.event.modal.project.bound": "Bound project", + + "openaire.broker.event.modal.project.placeholder": "Enter a project name", + + "openaire.broker.event.modal.project.notFound": "No project found.", + + "openaire.broker.event.project.bounded": "The project has been linked successfully.", + + "openaire.broker.event.project.removed": "The project has been successfully unlinked.", + + "openaire.broker.event.project.error": "An error has occurred. No operation performed.", + + "openaire.broker.event.reason": "Reason", + "orgunit.listelement.badge": "Organizational Unit", @@ -3362,7 +3497,9 @@ "search.filters.filter.submitter.label": "Search submitter", + "search.filters.filter.funding.head": "Funding", + "search.filters.filter.funding.placeholder": "Funding", "search.filters.entityType.JournalIssue": "Journal Issue", From 4ca51387d1e60b7068eeed2f13ed105922a15455 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Fri, 18 Feb 2022 19:01:30 +0100 Subject: [PATCH 002/196] [CST-5246] Correction service should support multiple providers --- ...ications-broker-events-page.component.html | 1 + ...tions-broker-events-page.component.spec.ts | 26 ++++ ...ifications-broker-events-page.component.ts | 9 ++ ...ifications-broker-events-page.resolver.ts} | 8 +- ...ns-broker-topics-page-resolver.service.ts} | 8 +- ...ications-broker-topics-page.component.html | 1 + ...tions-broker-topics-page.component.spec.ts | 26 ++++ ...ifications-broker-topics-page.component.ts | 9 ++ ...ations-openaire-events-page.component.html | 1 - ...ons-openaire-events-page.component.spec.ts | 26 ---- ...ications-openaire-events-page.component.ts | 9 -- ...ations-openaire-topics-page.component.html | 1 - ...ons-openaire-topics-page.component.spec.ts | 26 ---- ...ications-openaire-topics-page.component.ts | 9 -- .../admin-notifications-routing-paths.ts | 4 +- .../admin-notifications-routing.module.ts | 28 ++-- .../admin-notifications.module.ts | 12 +- .../admin-sidebar/admin-sidebar.component.ts | 4 +- src/app/core/core.module.ts | 8 +- ...cations-broker-event-rest.service.spec.ts} | 54 ++++---- ...otifications-broker-event-rest.service.ts} | 56 ++++---- ...ions-broker-event-object.resource-type.ts} | 4 +- .../notifications-broker-event.model.ts} | 49 ++++--- ...ions-broker-topic-object.resource-type.ts} | 4 +- .../notifications-broker-topic.model.ts} | 16 +-- ...cations-broker-topic-rest.service.spec.ts} | 28 ++-- ...otifications-broker-topic-rest.service.ts} | 38 ++--- ...otifications-broker-events.component.html} | 94 ++++++------- ...fications-broker-events.component.spec.ts} | 114 +++++++-------- .../notifications-broker-events.component.ts} | 130 +++++++++--------- ...tifications-broker-events.scomponent.scss} | 0 .../project-entry-import-modal.component.html | 0 .../project-entry-import-modal.component.scss | 0 ...oject-entry-import-modal.component.spec.ts | 20 +-- .../project-entry-import-modal.component.ts | 29 ++-- .../notifications-broker-topics.actions.ts} | 30 ++-- ...otifications-broker-topics.component.html} | 22 +-- ...otifications-broker-topics.component.scss} | 0 ...fications-broker-topics.component.spec.ts} | 66 ++++----- .../notifications-broker-topics.component.ts} | 54 ++++---- .../notifications-broker-topics.effects.ts} | 38 ++--- ...otifications-broker-topics.reducer.spec.ts | 68 +++++++++ .../notifications-broker-topics.reducer.ts | 72 ++++++++++ ...tifications-broker-topics.service.spec.ts} | 34 ++--- .../notifications-broker-topics.service.ts | 55 ++++++++ .../notifications-state.service.spec.ts} | 112 +++++++-------- .../notifications-state.service.ts | 116 ++++++++++++++++ .../notifications/notifications.effects.ts | 5 + .../notifications.module.ts} | 34 ++--- .../notifications/notifications.reducer.ts | 16 +++ src/app/notifications/selectors.ts | 79 +++++++++++ .../openaire-broker-topics.reducer.spec.ts | 68 --------- .../topics/openaire-broker-topics.reducer.ts | 72 ---------- .../topics/openaire-broker-topics.service.ts | 55 -------- src/app/openaire/openaire-state.service.ts | 116 ---------------- src/app/openaire/openaire.effects.ts | 5 - src/app/openaire/openaire.reducer.ts | 16 --- src/app/openaire/selectors.ts | 79 ----------- ...openaire.mock.ts => notifications.mock.ts} | 94 ++++++------- src/assets/i18n/en.json5 | 130 +++++++++--------- 60 files changed, 1150 insertions(+), 1138 deletions(-) create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts rename src/app/admin/admin-notifications/{admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts => admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts} (72%) rename src/app/admin/admin-notifications/{admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts => admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts} (72%) create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html delete mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html delete mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts rename src/app/core/{openaire/broker/events/openaire-broker-event-rest.service.spec.ts => notifications/broker/events/notifications-broker-event-rest.service.spec.ts} (78%) rename src/app/core/{openaire/broker/events/openaire-broker-event-rest.service.ts => notifications/broker/events/notifications-broker-event-rest.service.ts} (73%) rename src/app/core/{openaire/broker/models/openaire-broker-event-object.resource-type.ts => notifications/broker/models/notifications-broker-event-object.resource-type.ts} (53%) rename src/app/core/{openaire/broker/models/openaire-broker-event.model.ts => notifications/broker/models/notifications-broker-event.model.ts} (61%) rename src/app/core/{openaire/broker/models/openaire-broker-topic-object.resource-type.ts => notifications/broker/models/notifications-broker-topic-object.resource-type.ts} (53%) rename src/app/core/{openaire/broker/models/openaire-broker-topic.model.ts => notifications/broker/models/notifications-broker-topic.model.ts} (64%) rename src/app/core/{openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts => notifications/broker/topics/notifications-broker-topic-rest.service.spec.ts} (77%) rename src/app/core/{openaire/broker/topics/openaire-broker-topic-rest.service.ts => notifications/broker/topics/notifications-broker-topic-rest.service.ts} (75%) rename src/app/{openaire/broker/events/openaire-broker-events.component.html => notifications/broker/events/notifications-broker-events.component.html} (60%) rename src/app/{openaire/broker/events/openaire-broker-events.component.spec.ts => notifications/broker/events/notifications-broker-events.component.spec.ts} (66%) rename src/app/{openaire/broker/events/openaire-broker-events.component.ts => notifications/broker/events/notifications-broker-events.component.ts} (71%) rename src/app/{openaire/broker/events/openaire-broker-events.scomponent.scss => notifications/broker/events/notifications-broker-events.scomponent.scss} (100%) rename src/app/{openaire => notifications}/broker/project-entry-import-modal/project-entry-import-modal.component.html (100%) rename src/app/{openaire => notifications}/broker/project-entry-import-modal/project-entry-import-modal.component.scss (100%) rename src/app/{openaire => notifications}/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts (92%) rename src/app/{openaire => notifications}/broker/project-entry-import-modal/project-entry-import-modal.component.ts (89%) rename src/app/{openaire/broker/topics/openaire-broker-topics.actions.ts => notifications/broker/topics/notifications-broker-topics.actions.ts} (60%) rename src/app/{openaire/broker/topics/openaire-broker-topics.component.html => notifications/broker/topics/notifications-broker-topics.component.html} (66%) rename src/app/{openaire/broker/topics/openaire-broker-topics.component.scss => notifications/broker/topics/notifications-broker-topics.component.scss} (100%) rename src/app/{openaire/broker/topics/openaire-broker-topics.component.spec.ts => notifications/broker/topics/notifications-broker-topics.component.spec.ts} (53%) rename src/app/{openaire/broker/topics/openaire-broker-topics.component.ts => notifications/broker/topics/notifications-broker-topics.component.ts} (60%) rename src/app/{openaire/broker/topics/openaire-broker-topics.effects.ts => notifications/broker/topics/notifications-broker-topics.effects.ts} (57%) create mode 100644 src/app/notifications/broker/topics/notifications-broker-topics.reducer.spec.ts create mode 100644 src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts rename src/app/{openaire/broker/topics/openaire-broker-topics.service.spec.ts => notifications/broker/topics/notifications-broker-topics.service.spec.ts} (56%) create mode 100644 src/app/notifications/broker/topics/notifications-broker-topics.service.ts rename src/app/{openaire/openaire-state.service.spec.ts => notifications/notifications-state.service.spec.ts} (59%) create mode 100644 src/app/notifications/notifications-state.service.ts create mode 100644 src/app/notifications/notifications.effects.ts rename src/app/{openaire/openaire.module.ts => notifications/notifications.module.ts} (50%) create mode 100644 src/app/notifications/notifications.reducer.ts create mode 100644 src/app/notifications/selectors.ts delete mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.reducer.spec.ts delete mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.reducer.ts delete mode 100644 src/app/openaire/broker/topics/openaire-broker-topics.service.ts delete mode 100644 src/app/openaire/openaire-state.service.ts delete mode 100644 src/app/openaire/openaire.effects.ts delete mode 100644 src/app/openaire/openaire.reducer.ts delete mode 100644 src/app/openaire/selectors.ts rename src/app/shared/mocks/{openaire.mock.ts => notifications.mock.ts} (92%) diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html new file mode 100644 index 00000000000..89ef1bfc885 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html @@ -0,0 +1 @@ + diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts new file mode 100644 index 00000000000..57a79e017bf --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts @@ -0,0 +1,26 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AdminNotificationsBrokerEventsPageComponent } from './admin-notifications-broker-events-page.component'; + +describe('AdminNotificationsBrokerEventsPageComponent', () => { + let component: AdminNotificationsBrokerEventsPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AdminNotificationsBrokerEventsPageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminNotificationsBrokerEventsPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create AdminNotificationsBrokerEventsPageComponent', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts new file mode 100644 index 00000000000..f014b4d133e --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-notifications-broker-events-page', + templateUrl: './admin-notifications-broker-events-page.component.html' +}) +export class AdminNotificationsBrokerEventsPageComponent { + +} diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts similarity index 72% rename from src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts rename to src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts index b215013e11c..dcf530858cc 100644 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver.ts +++ b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts @@ -4,7 +4,7 @@ import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/r /** * Interface for the route parameters. */ -export interface AdminNotificationsOpenaireEventsPageParams { +export interface AdminNotificationsBrokerEventsPageParams { pageId?: string; pageSize?: number; currentPage?: number; @@ -14,15 +14,15 @@ export interface AdminNotificationsOpenaireEventsPageParams { * This class represents a resolver that retrieve the route data before the route is activated. */ @Injectable() -export class AdminNotificationsOpenaireEventsPageResolver implements Resolve { +export class AdminNotificationsBrokerEventsPageResolver implements Resolve { /** * Method for resolving the parameters in the current route. * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot * @param {RouterStateSnapshot} state The current RouterStateSnapshot - * @returns AdminNotificationsOpenaireEventsPageParams Emits the route parameters + * @returns AdminNotificationsBrokerEventsPageParams Emits the route parameters */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsOpenaireEventsPageParams { + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsBrokerEventsPageParams { return { pageId: route.queryParams.pageId, pageSize: parseInt(route.queryParams.pageSize, 10), diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts similarity index 72% rename from src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts rename to src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts index f8e02cabbfe..d4fd354d92b 100644 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service.ts +++ b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts @@ -4,7 +4,7 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/r /** * Interface for the route parameters. */ -export interface AdminNotificationsOpenaireTopicsPageParams { +export interface AdminNotificationsBrokerTopicsPageParams { pageId?: string; pageSize?: number; currentPage?: number; @@ -14,15 +14,15 @@ export interface AdminNotificationsOpenaireTopicsPageParams { * This class represents a resolver that retrieve the route data before the route is activated. */ @Injectable() -export class AdminNotificationsOpenaireTopicsPageResolver implements Resolve { +export class AdminNotificationsBrokerTopicsPageResolver implements Resolve { /** * Method for resolving the parameters in the current route. * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot * @param {RouterStateSnapshot} state The current RouterStateSnapshot - * @returns AdminNotificationsOpenaireTopicsPageParams Emits the route parameters + * @returns AdminNotificationsBrokerTopicsPageParams Emits the route parameters */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsOpenaireTopicsPageParams { + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsBrokerTopicsPageParams { return { pageId: route.queryParams.pageId, pageSize: parseInt(route.queryParams.pageSize, 10), diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html new file mode 100644 index 00000000000..dbdae2e6b9a --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html @@ -0,0 +1 @@ + diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts new file mode 100644 index 00000000000..c21e0ce73ba --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts @@ -0,0 +1,26 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AdminNotificationsBrokerTopicsPageComponent } from './admin-notifications-broker-topics-page.component'; + +describe('AdminNotificationsBrokerTopicsPageComponent', () => { + let component: AdminNotificationsBrokerTopicsPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AdminNotificationsBrokerTopicsPageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminNotificationsBrokerTopicsPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create AdminNotificationsBrokerTopicsPageComponent', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts new file mode 100644 index 00000000000..4f60ffd3fdd --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-notification-broker-page', + templateUrl: './admin-notifications-broker-topics-page.component.html' +}) +export class AdminNotificationsBrokerTopicsPageComponent { + +} diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html deleted file mode 100644 index 5c8f8820a00..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts deleted file mode 100644 index ab7a08a695e..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { AdminNotificationsOpenaireEventsPageComponent } from './admin-notifications-openaire-events-page.component'; - -describe('AdminNotificationsOpenaireEventsPageComponent', () => { - let component: AdminNotificationsOpenaireEventsPageComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AdminNotificationsOpenaireEventsPageComponent ], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AdminNotificationsOpenaireEventsPageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create AdminNotificationsOpenaireEventsPageComponent', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts deleted file mode 100644 index df7b21dbdab..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'ds-notification-openaire-events-page', - templateUrl: './admin-notifications-openaire-events-page.component.html' -}) -export class AdminNotificationsOpenaireEventsPageComponent { - -} diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html deleted file mode 100644 index b1616cfe781..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts deleted file mode 100644 index 712c7ba2c3d..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { AdminNotificationsOpenaireTopicsPageComponent } from './admin-notifications-openaire-topics-page.component'; - -describe('AdminNotificationsOpenaireTopicsPageComponent', () => { - let component: AdminNotificationsOpenaireTopicsPageComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AdminNotificationsOpenaireTopicsPageComponent ], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AdminNotificationsOpenaireTopicsPageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create AdminNotificationsOpenaireTopicsPageComponent', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts deleted file mode 100644 index 5bf1832c595..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'ds-notification-openairebroker-page', - templateUrl: './admin-notifications-openaire-topics-page.component.html' -}) -export class AdminNotificationsOpenaireTopicsPageComponent { - -} diff --git a/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts index ea7242adcb8..469cbb980ff 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts @@ -1,8 +1,8 @@ import { URLCombiner } from '../../core/url-combiner/url-combiner'; import { getNotificationsModuleRoute } from '../admin-routing-paths'; -export const NOTIFICATIONS_EDIT_PATH = 'openaire-broker'; +export const NOTIFICATIONS_EDIT_PATH = 'notifications-broker'; -export function getNotificationsOpenairebrokerRoute(id: string) { +export function getNotificationsBrokerbrokerRoute(id: string) { return new URLCombiner(getNotificationsModuleRoute(), NOTIFICATIONS_EDIT_PATH, id).toString(); } diff --git a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts index 2dfa938c4f7..f1f46ca4f1e 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -5,10 +5,10 @@ import { AuthenticatedGuard } from '../../core/auth/authenticated.guard'; import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver'; import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service'; import { NOTIFICATIONS_EDIT_PATH } from './admin-notifications-routing-paths'; -import { AdminNotificationsOpenaireTopicsPageComponent } from './admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component'; -import { AdminNotificationsOpenaireEventsPageComponent } from './admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component'; -import { AdminNotificationsOpenaireTopicsPageResolver } from './admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page-resolver.service'; -import { AdminNotificationsOpenaireEventsPageResolver } from './admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.resolver'; +import { AdminNotificationsBrokerTopicsPageComponent } from './admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component'; +import { AdminNotificationsBrokerEventsPageComponent } from './admin-notifications-broker-events-page/admin-notifications-broker-events-page.component'; +import { AdminNotificationsBrokerTopicsPageResolver } from './admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service'; +import { AdminNotificationsBrokerEventsPageResolver } from './admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver'; @NgModule({ imports: [ @@ -16,30 +16,30 @@ import { AdminNotificationsOpenaireEventsPageResolver } from './admin-notificati { canActivate: [ AuthenticatedGuard ], path: `${NOTIFICATIONS_EDIT_PATH}`, - component: AdminNotificationsOpenaireTopicsPageComponent, + component: AdminNotificationsBrokerTopicsPageComponent, pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerTopicsParams: AdminNotificationsOpenaireTopicsPageResolver + openaireBrokerTopicsParams: AdminNotificationsBrokerTopicsPageResolver }, data: { - title: 'admin.notifications.openairebroker.page.title', - breadcrumbKey: 'admin.notifications.openairebroker', + title: 'admin.notifications.broker.page.title', + breadcrumbKey: 'admin.notifications.broker', showBreadcrumbsFluid: false } }, { canActivate: [ AuthenticatedGuard ], path: `${NOTIFICATIONS_EDIT_PATH}/:id`, - component: AdminNotificationsOpenaireEventsPageComponent, + component: AdminNotificationsBrokerEventsPageComponent, pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerEventsParams: AdminNotificationsOpenaireEventsPageResolver + openaireBrokerEventsParams: AdminNotificationsBrokerEventsPageResolver }, data: { - title: 'admin.notifications.openaireevent.page.title', - breadcrumbKey: 'admin.notifications.openaireevent', + title: 'admin.notifications.event.page.title', + breadcrumbKey: 'admin.notifications.event', showBreadcrumbsFluid: false } } @@ -48,8 +48,8 @@ import { AdminNotificationsOpenaireEventsPageResolver } from './admin-notificati providers: [ I18nBreadcrumbResolver, I18nBreadcrumbsService, - AdminNotificationsOpenaireTopicsPageResolver, - AdminNotificationsOpenaireEventsPageResolver + AdminNotificationsBrokerTopicsPageResolver, + AdminNotificationsBrokerEventsPageResolver ] }) /** diff --git a/src/app/admin/admin-notifications/admin-notifications.module.ts b/src/app/admin/admin-notifications/admin-notifications.module.ts index 9894dac2335..350e9de800b 100644 --- a/src/app/admin/admin-notifications/admin-notifications.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications.module.ts @@ -3,9 +3,9 @@ import { NgModule } from '@angular/core'; import { CoreModule } from '../../core/core.module'; import { SharedModule } from '../../shared/shared.module'; import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module'; -import { AdminNotificationsOpenaireTopicsPageComponent } from './admin-notifications-openaire-topics-page/admin-notifications-openaire-topics-page.component'; -import { AdminNotificationsOpenaireEventsPageComponent } from './admin-notifications-openaire-events-page/admin-notifications-openaire-events-page.component'; -import { OpenaireModule } from '../../openaire/openaire.module'; +import { AdminNotificationsBrokerTopicsPageComponent } from './admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component'; +import { AdminNotificationsBrokerEventsPageComponent } from './admin-notifications-broker-events-page/admin-notifications-broker-events-page.component'; +import { NotificationsModule } from '../../notifications/notifications.module'; @NgModule({ imports: [ @@ -13,11 +13,11 @@ import { OpenaireModule } from '../../openaire/openaire.module'; SharedModule, CoreModule.forRoot(), AdminNotificationsRoutingModule, - OpenaireModule + NotificationsModule ], declarations: [ - AdminNotificationsOpenaireTopicsPageComponent, - AdminNotificationsOpenaireEventsPageComponent + AdminNotificationsBrokerTopicsPageComponent, + AdminNotificationsBrokerEventsPageComponent ], entryComponents: [] }) diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.ts index a2a7eb30b56..3e989f16f31 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.ts @@ -483,8 +483,8 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { visible: authorized, model: { type: MenuItemType.LINK, - text: 'menu.section.notifications_openaire_broker', - link: '/admin/notifications/openaire-broker' + text: 'menu.section.notifications_broker', + link: '/admin/notifications/notifications-broker' } as LinkMenuItemModel, }, /* Admin Search */ diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 928d34c48e4..f5a959592f3 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -162,8 +162,8 @@ import { SearchConfig } from './shared/search/search-filters/search-config.model import { SequenceService } from './shared/sequence.service'; import { GroupDataService } from './eperson/group-data.service'; import { SubmissionAccessesModel } from './config/models/config-submission-accesses.model'; -import { OpenaireBrokerTopicObject } from './openaire/broker/models/openaire-broker-topic.model'; -import { OpenaireBrokerEventObject } from './openaire/broker/models/openaire-broker-event.model'; +import { NotificationsBrokerTopicObject } from './notifications/broker/models/notifications-broker-topic.model'; +import { NotificationsBrokerEventObject } from './notifications/broker/models/notifications-broker-event.model'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -345,8 +345,8 @@ export const models = ShortLivedToken, Registration, UsageReport, - OpenaireBrokerTopicObject, - OpenaireBrokerEventObject, + NotificationsBrokerTopicObject, + NotificationsBrokerEventObject, Root, SearchConfig, SubmissionAccessesModel diff --git a/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.spec.ts b/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.spec.ts similarity index 78% rename from src/app/core/openaire/broker/events/openaire-broker-event-rest.service.spec.ts rename to src/app/core/notifications/broker/events/notifications-broker-event-rest.service.spec.ts index 2d0d236330e..16d55479ae0 100644 --- a/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.spec.ts +++ b/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.spec.ts @@ -15,17 +15,17 @@ import { PageInfo } from '../../../shared/page-info.model'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; -import { OpenaireBrokerEventRestService } from './openaire-broker-event-rest.service'; +import { NotificationsBrokerEventRestService } from './notifications-broker-event-rest.service'; import { - openaireBrokerEventObjectMissingPid, - openaireBrokerEventObjectMissingPid2, - openaireBrokerEventObjectMissingProjectFound -} from '../../../../shared/mocks/openaire.mock'; + notificationsBrokerEventObjectMissingPid, + notificationsBrokerEventObjectMissingPid2, + notificationsBrokerEventObjectMissingProjectFound +} from '../../../../shared/mocks/notifications.mock'; import { ReplaceOperation } from 'fast-json-patch'; -describe('OpenaireBrokerEventRestService', () => { +describe('NotificationsBrokerEventRestService', () => { let scheduler: TestScheduler; - let service: OpenaireBrokerEventRestService; + let service: NotificationsBrokerEventRestService; let serviceASAny: any; let responseCacheEntry: RequestEntry; let responseCacheEntryB: RequestEntry; @@ -43,10 +43,10 @@ describe('OpenaireBrokerEventRestService', () => { const topic = 'ENRICH!MORE!PID'; const pageInfo = new PageInfo(); - const array = [ openaireBrokerEventObjectMissingPid, openaireBrokerEventObjectMissingPid2 ]; + const array = [ notificationsBrokerEventObjectMissingPid, notificationsBrokerEventObjectMissingPid2 ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerEventObjectRD = createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingPid); - const brokerEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingProjectFound); + const brokerEventObjectRD = createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingPid); + const brokerEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingProjectFound); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); const status = 'ACCEPTED'; @@ -99,7 +99,7 @@ describe('OpenaireBrokerEventRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new OpenaireBrokerEventRestService( + service = new NotificationsBrokerEventRestService( requestService, rdbService, objectCache, @@ -138,7 +138,7 @@ describe('OpenaireBrokerEventRestService', () => { expect(serviceASAny.dataService.searchBy).toHaveBeenCalledWith('findByTopic', options, true, true); }); - it('should return a RemoteData> for the object with the given Topic', () => { + it('should return a RemoteData> for the object with the given Topic', () => { const result = service.getEventsByTopic(topic); const expected = cold('(a)', { a: paginatedListRD @@ -155,15 +155,15 @@ describe('OpenaireBrokerEventRestService', () => { }); it('should proxy the call to dataservice.findById', () => { - service.getEvent(openaireBrokerEventObjectMissingPid.id).subscribe( + service.getEvent(notificationsBrokerEventObjectMissingPid.id).subscribe( (res) => { - expect(serviceASAny.dataService.findById).toHaveBeenCalledWith(openaireBrokerEventObjectMissingPid.id, true, true); + expect(serviceASAny.dataService.findById).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingPid.id, true, true); } ); }); - it('should return a RemoteData for the object with the given URL', () => { - const result = service.getEvent(openaireBrokerEventObjectMissingPid.id); + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getEvent(notificationsBrokerEventObjectMissingPid.id); const expected = cold('(a)', { a: brokerEventObjectRD }); @@ -179,17 +179,17 @@ describe('OpenaireBrokerEventRestService', () => { }); it('should proxy the call to dataservice.patch', () => { - service.patchEvent(status, openaireBrokerEventObjectMissingPid).subscribe( + service.patchEvent(status, notificationsBrokerEventObjectMissingPid).subscribe( (res) => { - expect(serviceASAny.dataService.patch).toHaveBeenCalledWith(openaireBrokerEventObjectMissingPid, operation); + expect(serviceASAny.dataService.patch).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingPid, operation); } ); }); it('should return a RemoteData with HTTP 200', () => { - const result = service.patchEvent(status, openaireBrokerEventObjectMissingPid); + const result = service.patchEvent(status, notificationsBrokerEventObjectMissingPid); const expected = cold('(a|)', { - a: createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingPid) + a: createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingPid) }); expect(result).toBeObservable(expected); }); @@ -203,17 +203,17 @@ describe('OpenaireBrokerEventRestService', () => { }); it('should proxy the call to dataservice.postOnRelated', () => { - service.boundProject(openaireBrokerEventObjectMissingProjectFound.id, requestUUID).subscribe( + service.boundProject(notificationsBrokerEventObjectMissingProjectFound.id, requestUUID).subscribe( (res) => { - expect(serviceASAny.dataService.postOnRelated).toHaveBeenCalledWith(openaireBrokerEventObjectMissingProjectFound.id, requestUUID); + expect(serviceASAny.dataService.postOnRelated).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingProjectFound.id, requestUUID); } ); }); it('should return a RestResponse with HTTP 201', () => { - const result = service.boundProject(openaireBrokerEventObjectMissingProjectFound.id, requestUUID); + const result = service.boundProject(notificationsBrokerEventObjectMissingProjectFound.id, requestUUID); const expected = cold('(a|)', { - a: createSuccessfulRemoteDataObject(openaireBrokerEventObjectMissingProjectFound) + a: createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingProjectFound) }); expect(result).toBeObservable(expected); }); @@ -227,15 +227,15 @@ describe('OpenaireBrokerEventRestService', () => { }); it('should proxy the call to dataservice.deleteOnRelated', () => { - service.removeProject(openaireBrokerEventObjectMissingProjectFound.id).subscribe( + service.removeProject(notificationsBrokerEventObjectMissingProjectFound.id).subscribe( (res) => { - expect(serviceASAny.dataService.deleteOnRelated).toHaveBeenCalledWith(openaireBrokerEventObjectMissingProjectFound.id); + expect(serviceASAny.dataService.deleteOnRelated).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingProjectFound.id); } ); }); it('should return a RestResponse with HTTP 204', () => { - const result = service.removeProject(openaireBrokerEventObjectMissingProjectFound.id); + const result = service.removeProject(notificationsBrokerEventObjectMissingProjectFound.id); const expected = cold('(a|)', { a: createSuccessfulRemoteDataObject({}) }); diff --git a/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.ts b/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.ts similarity index 73% rename from src/app/core/openaire/broker/events/openaire-broker-event-rest.service.ts rename to src/app/core/notifications/broker/events/notifications-broker-event-rest.service.ts index 6e944c8038c..7f4761009d9 100644 --- a/src/app/core/openaire/broker/events/openaire-broker-event-rest.service.ts +++ b/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.ts @@ -17,8 +17,8 @@ import { DataService } from '../../../data/data.service'; import { ChangeAnalyzer } from '../../../data/change-analyzer'; import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; import { RemoteData } from '../../../data/remote-data'; -import { OpenaireBrokerEventObject } from '../models/openaire-broker-event.model'; -import { OPENAIRE_BROKER_EVENT_OBJECT } from '../models/openaire-broker-event-object.resource-type'; +import { NotificationsBrokerEventObject } from '../models/notifications-broker-event.model'; +import { NOTIFICATIONS_BROKER_EVENT_OBJECT } from '../models/notifications-broker-event-object.resource-type'; import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model'; import { PaginatedList } from '../../../data/paginated-list.model'; import { ReplaceOperation } from 'fast-json-patch'; @@ -29,7 +29,7 @@ import { NoContent } from '../../../shared/NoContent.model'; /** * A private DataService implementation to delegate specific methods to. */ -class DataServiceImpl extends DataService { +class DataServiceImpl extends DataService { /** * The REST endpoint. */ @@ -44,7 +44,7 @@ class DataServiceImpl extends DataService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer} comparator + * @param {ChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -54,17 +54,17 @@ class DataServiceImpl extends DataService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer) { + protected comparator: ChangeAnalyzer) { super(); } } /** - * The service handling all OpenAIRE Broker topic REST requests. + * The service handling all Notifications Broker topic REST requests. */ @Injectable() -@dataService(OPENAIRE_BROKER_EVENT_OBJECT) -export class OpenaireBrokerEventRestService { +@dataService(NOTIFICATIONS_BROKER_EVENT_OBJECT) +export class NotificationsBrokerEventRestService { /** * A private DataService implementation to delegate specific methods to. */ @@ -78,7 +78,7 @@ export class OpenaireBrokerEventRestService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {DefaultChangeAnalyzer} comparator + * @param {DefaultChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -87,23 +87,23 @@ export class OpenaireBrokerEventRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer) { + protected comparator: DefaultChangeAnalyzer) { this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } /** - * Return the list of OpenAIRE Broker events by topic. + * Return the list of Notifications Broker events by topic. * * @param topic - * The OpenAIRE Broker topic + * The Notifications Broker topic * @param options * Find list options object. * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable>> - * The list of OpenAIRE Broker events. + * @return Observable>> + * The list of Notifications Broker events. */ - public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { + public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { options.searchParams = [ { fieldName: 'topic', @@ -121,32 +121,32 @@ export class OpenaireBrokerEventRestService { } /** - * Return a single OpenAIRE Broker event. + * Return a single Notifications Broker event. * * @param id - * The OpenAIRE Broker event id + * The Notifications Broker event id * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved - * @return Observable> - * The OpenAIRE Broker event. + * @return Observable> + * The Notifications Broker event. */ - public getEvent(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { + public getEvent(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { return this.dataService.findById(id, true, true, ...linksToFollow); } /** - * Save the new status of an OpenAIRE Broker event. + * Save the new status of a Notifications Broker event. * * @param status * The new status - * @param dso OpenaireBrokerEventObject + * @param dso NotificationsBrokerEventObject * The event item * @param reason * The optional reason (not used for now; for future implementation) * @return Observable * The REST response. */ - public patchEvent(status, dso, reason?: string): Observable> { + public patchEvent(status, dso, reason?: string): Observable> { const operation: ReplaceOperation[] = [ { path: '/status', @@ -158,24 +158,24 @@ export class OpenaireBrokerEventRestService { } /** - * Bound a project to an OpenAIRE Broker event publication. + * Bound a project to a Notifications Broker event publication. * * @param itemId - * The Id of the OpenAIRE Broker event + * The Id of the Notifications Broker event * @param projectId * The project Id to bound * @return Observable * The REST response. */ - public boundProject(itemId: string, projectId: string): Observable> { + public boundProject(itemId: string, projectId: string): Observable> { return this.dataService.postOnRelated(itemId, projectId); } /** - * Remove a project from an OpenAIRE Broker event publication. + * Remove a project from a Notifications Broker event publication. * * @param itemId - * The Id of the OpenAIRE Broker event + * The Id of the Notifications Broker event * @return Observable * The REST response. */ diff --git a/src/app/core/openaire/broker/models/openaire-broker-event-object.resource-type.ts b/src/app/core/notifications/broker/models/notifications-broker-event-object.resource-type.ts similarity index 53% rename from src/app/core/openaire/broker/models/openaire-broker-event-object.resource-type.ts rename to src/app/core/notifications/broker/models/notifications-broker-event-object.resource-type.ts index c0be0071ebc..2493ae02d1e 100644 --- a/src/app/core/openaire/broker/models/openaire-broker-event-object.resource-type.ts +++ b/src/app/core/notifications/broker/models/notifications-broker-event-object.resource-type.ts @@ -1,9 +1,9 @@ import { ResourceType } from '../../../shared/resource-type'; /** - * The resource type for the OpenAIRE Broker event + * The resource type for the Notifications Broker event * * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const OPENAIRE_BROKER_EVENT_OBJECT = new ResourceType('nbevent'); +export const NOTIFICATIONS_BROKER_EVENT_OBJECT = new ResourceType('nbevent'); diff --git a/src/app/core/openaire/broker/models/openaire-broker-event.model.ts b/src/app/core/notifications/broker/models/notifications-broker-event.model.ts similarity index 61% rename from src/app/core/openaire/broker/models/openaire-broker-event.model.ts rename to src/app/core/notifications/broker/models/notifications-broker-event.model.ts index 40c65412f52..ed73168e6d9 100644 --- a/src/app/core/openaire/broker/models/openaire-broker-event.model.ts +++ b/src/app/core/notifications/broker/models/notifications-broker-event.model.ts @@ -1,7 +1,7 @@ import { Observable } from 'rxjs'; import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; import { CacheableObject } from '../../../cache/object-cache.reducer'; -import { OPENAIRE_BROKER_EVENT_OBJECT } from './openaire-broker-event-object.resource-type'; +import { NOTIFICATIONS_BROKER_EVENT_OBJECT } from './notifications-broker-event-object.resource-type'; import { excludeFromEquals } from '../../../utilities/equals.decorators'; import { ResourceType } from '../../../shared/resource-type'; import { HALLink } from '../../../shared/hal-link.model'; @@ -11,85 +11,92 @@ import { link, typedObject } from '../../../cache/builders/build-decorators'; import { RemoteData } from '../../../data/remote-data'; /** - * The interface representing the OpenAIRE Broker event message + * The interface representing the Notifications Broker event message */ -export interface OpenaireBrokerEventMessageObject { +export interface NotificationsBrokerEventMessageObject { + +} + +/** + * The interface representing the Notifications Broker event message + */ +export interface OpenaireBrokerEventMessageObject{ /** * The type of 'value' */ type: string; /** - * The value suggested by OpenAIRE + * The value suggested by Notifications */ value: string; /** - * The abstract suggested by OpenAIRE + * The abstract suggested by Notifications */ abstract: string; /** - * The project acronym suggested by OpenAIRE + * The project acronym suggested by Notifications */ acronym: string; /** - * The project code suggested by OpenAIRE + * The project code suggested by Notifications */ code: string; /** - * The project funder suggested by OpenAIRE + * The project funder suggested by Notifications */ funder: string; /** - * The project program suggested by OpenAIRE + * The project program suggested by Notifications */ fundingProgram?: string; /** - * The project jurisdiction suggested by OpenAIRE + * The project jurisdiction suggested by Notifications */ jurisdiction: string; /** - * The project title suggested by OpenAIRE + * The project title suggested by Notifications */ title: string; /** - * The OpenAIRE ID. + * The OPENAIRE ID. */ openaireId: string; } /** - * The interface representing the OpenAIRE Broker event model + * The interface representing the Notifications Broker event model */ @typedObject -export class OpenaireBrokerEventObject implements CacheableObject { +export class NotificationsBrokerEventObject implements CacheableObject { /** * A string representing the kind of object, e.g. community, item, … */ - static type = OPENAIRE_BROKER_EVENT_OBJECT; + static type = NOTIFICATIONS_BROKER_EVENT_OBJECT; /** - * The OpenAIRE Broker event uuid inside DSpace + * The Notifications Broker event uuid inside DSpace */ @autoserialize id: string; /** - * The universally unique identifier of this OpenAIRE Broker event + * The universally unique identifier of this Notifications Broker event */ @autoserializeAs(String, 'id') uuid: string; /** - * The OpenAIRE Broker event original id (ex.: the source archive OAI-PMH identifier) + * The Notifications Broker event original id (ex.: the source archive OAI-PMH identifier) */ @autoserialize originalId: string; @@ -107,19 +114,19 @@ export class OpenaireBrokerEventObject implements CacheableObject { trust: number; /** - * The timestamp OpenAIRE Broker event was saved in DSpace + * The timestamp Notifications Broker event was saved in DSpace */ @autoserialize eventDate: string; /** - * The OpenAIRE Broker event status (ACCEPTED, REJECTED, DISCARDED, PENDING) + * The Notifications Broker event status (ACCEPTED, REJECTED, DISCARDED, PENDING) */ @autoserialize status: string; /** - * The suggestion data. Data may vary depending on the topic + * The suggestion data. Data may vary depending on the source */ @autoserialize message: OpenaireBrokerEventMessageObject; diff --git a/src/app/core/openaire/broker/models/openaire-broker-topic-object.resource-type.ts b/src/app/core/notifications/broker/models/notifications-broker-topic-object.resource-type.ts similarity index 53% rename from src/app/core/openaire/broker/models/openaire-broker-topic-object.resource-type.ts rename to src/app/core/notifications/broker/models/notifications-broker-topic-object.resource-type.ts index 58ceb4e671e..e7012eee4fe 100644 --- a/src/app/core/openaire/broker/models/openaire-broker-topic-object.resource-type.ts +++ b/src/app/core/notifications/broker/models/notifications-broker-topic-object.resource-type.ts @@ -1,9 +1,9 @@ import { ResourceType } from '../../../shared/resource-type'; /** - * The resource type for the OpenAIRE Broker topic + * The resource type for the Notifications Broker topic * * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const OPENAIRE_BROKER_TOPIC_OBJECT = new ResourceType('nbtopic'); +export const NOTIFICATIONS_BROKER_TOPIC_OBJECT = new ResourceType('nbtopic'); diff --git a/src/app/core/openaire/broker/models/openaire-broker-topic.model.ts b/src/app/core/notifications/broker/models/notifications-broker-topic.model.ts similarity index 64% rename from src/app/core/openaire/broker/models/openaire-broker-topic.model.ts rename to src/app/core/notifications/broker/models/notifications-broker-topic.model.ts index 3f286e5fead..d1f2e6ff502 100644 --- a/src/app/core/openaire/broker/models/openaire-broker-topic.model.ts +++ b/src/app/core/notifications/broker/models/notifications-broker-topic.model.ts @@ -1,42 +1,42 @@ import { autoserialize, deserialize } from 'cerialize'; import { CacheableObject } from '../../../cache/object-cache.reducer'; -import { OPENAIRE_BROKER_TOPIC_OBJECT } from './openaire-broker-topic-object.resource-type'; +import { NOTIFICATIONS_BROKER_TOPIC_OBJECT } from './notifications-broker-topic-object.resource-type'; import { excludeFromEquals } from '../../../utilities/equals.decorators'; import { ResourceType } from '../../../shared/resource-type'; import { HALLink } from '../../../shared/hal-link.model'; import { typedObject } from '../../../cache/builders/build-decorators'; /** - * The interface representing the OpenAIRE Broker topic model + * The interface representing the Notifications Broker topic model */ @typedObject -export class OpenaireBrokerTopicObject implements CacheableObject { +export class NotificationsBrokerTopicObject implements CacheableObject { /** * A string representing the kind of object, e.g. community, item, … */ - static type = OPENAIRE_BROKER_TOPIC_OBJECT; + static type = NOTIFICATIONS_BROKER_TOPIC_OBJECT; /** - * The OpenAIRE Broker topic id + * The Notifications Broker topic id */ @autoserialize id: string; /** - * The OpenAIRE Broker topic name to display + * The Notifications Broker topic name to display */ @autoserialize name: string; /** - * The date of the last udate from OpenAIRE + * The date of the last udate from Notifications */ @autoserialize lastEvent: string; /** - * The total number of suggestions provided by OpenAIRE for this topic + * The total number of suggestions provided by Notifications for this topic */ @autoserialize totalEvents: number; diff --git a/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts b/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.spec.ts similarity index 77% rename from src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts rename to src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.spec.ts index 87aa0b42f0c..06931e2032c 100644 --- a/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.spec.ts +++ b/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.spec.ts @@ -14,15 +14,15 @@ import { PageInfo } from '../../../shared/page-info.model'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; -import { OpenaireBrokerTopicRestService } from './openaire-broker-topic-rest.service'; +import { NotificationsBrokerTopicRestService } from './notifications-broker-topic-rest.service'; import { - openaireBrokerTopicObjectMoreAbstract, - openaireBrokerTopicObjectMorePid -} from '../../../../shared/mocks/openaire.mock'; + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMorePid +} from '../../../../shared/mocks/notifications.mock'; -describe('OpenaireBrokerTopicRestService', () => { +describe('NotificationsBrokerTopicRestService', () => { let scheduler: TestScheduler; - let service: OpenaireBrokerTopicRestService; + let service: NotificationsBrokerTopicRestService; let responseCacheEntry: RequestEntry; let requestService: RequestService; let rdbService: RemoteDataBuildService; @@ -36,9 +36,9 @@ describe('OpenaireBrokerTopicRestService', () => { const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); - const array = [ openaireBrokerTopicObjectMorePid, openaireBrokerTopicObjectMoreAbstract ]; + const array = [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerTopicObjectRD = createSuccessfulRemoteDataObject(openaireBrokerTopicObjectMorePid); + const brokerTopicObjectRD = createSuccessfulRemoteDataObject(notificationsBrokerTopicObjectMorePid); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); beforeEach(() => { @@ -72,7 +72,7 @@ describe('OpenaireBrokerTopicRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new OpenaireBrokerTopicRestService( + service = new NotificationsBrokerTopicRestService( requestService, rdbService, objectCache, @@ -96,7 +96,7 @@ describe('OpenaireBrokerTopicRestService', () => { done(); }); - it('should return a RemoteData> for the object with the given URL', () => { + it('should return a RemoteData> for the object with the given URL', () => { const result = service.getTopics(); const expected = cold('(a)', { a: paginatedListRD @@ -107,16 +107,16 @@ describe('OpenaireBrokerTopicRestService', () => { describe('getTopic', () => { it('should proxy the call to dataservice.findByHref', (done) => { - service.getTopic(openaireBrokerTopicObjectMorePid.id).subscribe( + service.getTopic(notificationsBrokerTopicObjectMorePid.id).subscribe( (res) => { - expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + openaireBrokerTopicObjectMorePid.id, true, true); + expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + notificationsBrokerTopicObjectMorePid.id, true, true); } ); done(); }); - it('should return a RemoteData for the object with the given URL', () => { - const result = service.getTopic(openaireBrokerTopicObjectMorePid.id); + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getTopic(notificationsBrokerTopicObjectMorePid.id); const expected = cold('(a)', { a: brokerTopicObjectRD }); diff --git a/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.ts b/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.ts similarity index 75% rename from src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.ts rename to src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.ts index 3fe39174858..9f0b93cfb39 100644 --- a/src/app/core/openaire/broker/topics/openaire-broker-topic-rest.service.ts +++ b/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.ts @@ -17,8 +17,8 @@ import { DataService } from '../../../data/data.service'; import { ChangeAnalyzer } from '../../../data/change-analyzer'; import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; import { RemoteData } from '../../../data/remote-data'; -import { OpenaireBrokerTopicObject } from '../models/openaire-broker-topic.model'; -import { OPENAIRE_BROKER_TOPIC_OBJECT } from '../models/openaire-broker-topic-object.resource-type'; +import { NotificationsBrokerTopicObject } from '../models/notifications-broker-topic.model'; +import { NOTIFICATIONS_BROKER_TOPIC_OBJECT } from '../models/notifications-broker-topic-object.resource-type'; import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model'; import { PaginatedList } from '../../../data/paginated-list.model'; @@ -27,7 +27,7 @@ import { PaginatedList } from '../../../data/paginated-list.model'; /** * A private DataService implementation to delegate specific methods to. */ -class DataServiceImpl extends DataService { +class DataServiceImpl extends DataService { /** * The REST endpoint. */ @@ -42,7 +42,7 @@ class DataServiceImpl extends DataService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer} comparator + * @param {ChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -52,17 +52,17 @@ class DataServiceImpl extends DataService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer) { + protected comparator: ChangeAnalyzer) { super(); } } /** - * The service handling all OpenAIRE Broker topic REST requests. + * The service handling all Notifications Broker topic REST requests. */ @Injectable() -@dataService(OPENAIRE_BROKER_TOPIC_OBJECT) -export class OpenaireBrokerTopicRestService { +@dataService(NOTIFICATIONS_BROKER_TOPIC_OBJECT) +export class NotificationsBrokerTopicRestService { /** * A private DataService implementation to delegate specific methods to. */ @@ -76,7 +76,7 @@ export class OpenaireBrokerTopicRestService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {DefaultChangeAnalyzer} comparator + * @param {DefaultChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -85,21 +85,21 @@ export class OpenaireBrokerTopicRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer) { + protected comparator: DefaultChangeAnalyzer) { this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } /** - * Return the list of OpenAIRE Broker topics. + * Return the list of Notifications Broker topics. * * @param options * Find list options object. * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable>> - * The list of OpenAIRE Broker topics. + * @return Observable>> + * The list of Notifications Broker topics. */ - public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { + public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( take(1), mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), @@ -114,16 +114,16 @@ export class OpenaireBrokerTopicRestService { } /** - * Return a single OpenAIRE Broker topic. + * Return a single Notifications Broker topic. * * @param id - * The OpenAIRE Broker topic id + * The Notifications Broker topic id * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable> - * The OpenAIRE Broker topic. + * @return Observable> + * The Notifications Broker topic. */ - public getTopic(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { + public getTopic(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { const options = {}; return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( take(1), diff --git a/src/app/openaire/broker/events/openaire-broker-events.component.html b/src/app/notifications/broker/events/notifications-broker-events.component.html similarity index 60% rename from src/app/openaire/broker/events/openaire-broker-events.component.html rename to src/app/notifications/broker/events/notifications-broker-events.component.html index 05d77222911..a9f51cefd09 100644 --- a/src/app/openaire/broker/events/openaire-broker-events.component.html +++ b/src/app/notifications/broker/events/notifications-broker-events.component.html @@ -1,12 +1,12 @@
-

{{'openaire.events.title'| translate}}

-

{{'openaire.broker.events.description'| translate}}

+

{{'notifications.events.title'| translate}}

+

{{'notifications.broker.events.description'| translate}}

- + - {{'openaire.broker.events.back' | translate}} + {{'notifications.broker.events.back' | translate}}

@@ -14,31 +14,31 @@

{{'openaire.events.title'| translate}}

- {{'openaire.broker.events.topic' | translate}} {{this.showTopic}} + {{'notifications.broker.events.topic' | translate}} {{this.showTopic}}

- + + (paginationChange)="getNotificationsBrokerEvents()"> - +
- - - - - + + + + + @@ -51,8 +51,8 @@

{{eventElement.title}}

@@ -140,9 +140,9 @@

@@ -150,58 +150,58 @@

diff --git a/src/app/openaire/broker/events/openaire-broker-events.component.spec.ts b/src/app/notifications/broker/events/notifications-broker-events.component.spec.ts similarity index 66% rename from src/app/openaire/broker/events/openaire-broker-events.component.spec.ts rename to src/app/notifications/broker/events/notifications-broker-events.component.spec.ts index 267f6a82423..40be083567d 100644 --- a/src/app/openaire/broker/events/openaire-broker-events.component.spec.ts +++ b/src/app/notifications/broker/events/notifications-broker-events.component.spec.ts @@ -5,25 +5,25 @@ import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/t import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { of as observableOf } from 'rxjs'; -import { OpenaireBrokerEventRestService } from '../../../core/openaire/broker/events/openaire-broker-event-rest.service'; -import { OpenaireBrokerEventsComponent } from './openaire-broker-events.component'; +import { NotificationsBrokerEventRestService } from '../../../core/notifications/broker/events/notifications-broker-event-rest.service'; +import { NotificationsBrokerEventsComponent } from './notifications-broker-events.component'; import { - getMockOpenaireBrokerEventRestService, + getMockNotificationsBrokerEventRestService, ItemMockPid10, ItemMockPid8, ItemMockPid9, - openaireBrokerEventObjectMissingProjectFound, - openaireBrokerEventObjectMissingProjectNotFound, - OpenaireMockDspaceObject -} from '../../../shared/mocks/openaire.mock'; + notificationsBrokerEventObjectMissingProjectFound, + notificationsBrokerEventObjectMissingProjectNotFound, + NotificationsMockDspaceObject +} from '../../../shared/mocks/notifications.mock'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { getMockTranslateService } from '../../../shared/mocks/translate.service.mock'; import { createTestComponent } from '../../../shared/testing/utils.test'; import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { OpenaireBrokerEventObject } from '../../../core/openaire/broker/models/openaire-broker-event.model'; -import { OpenaireBrokerEventData } from '../project-entry-import-modal/project-entry-import-modal.component'; +import { NotificationsBrokerEventObject } from '../../../core/notifications/broker/models/notifications-broker-event.model'; +import { NotificationsBrokerEventData } from '../project-entry-import-modal/project-entry-import-modal.component'; import { TestScheduler } from 'rxjs/testing'; import { getTestScheduler } from 'jasmine-marbles'; import { followLink } from '../../../shared/utils/follow-link-config.model'; @@ -39,9 +39,9 @@ import { SortDirection, SortOptions } from '../../../core/cache/models/sort-opti import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; -describe('OpenaireBrokerEventsComponent test suite', () => { - let fixture: ComponentFixture; - let comp: OpenaireBrokerEventsComponent; +describe('NotificationsBrokerEventsComponent test suite', () => { + let fixture: ComponentFixture; + let comp: NotificationsBrokerEventsComponent; let compAsAny: any; let scheduler: TestScheduler; @@ -50,9 +50,9 @@ describe('OpenaireBrokerEventsComponent test suite', () => { close: () => null, dismiss: () => null }; - const openaireBrokerEventRestServiceStub: any = getMockOpenaireBrokerEventRestService(); + const notificationsBrokerEventRestServiceStub: any = getMockNotificationsBrokerEventRestService(); const activatedRouteParams = { - openaireBrokerEventsParams: { + notificationsBrokerEventsParams: { currentPage: 0, pageSize: 10 } @@ -61,19 +61,19 @@ describe('OpenaireBrokerEventsComponent test suite', () => { id: 'ENRICH!MISSING!PROJECT' }; - const events: OpenaireBrokerEventObject[] = [ - openaireBrokerEventObjectMissingProjectFound, - openaireBrokerEventObjectMissingProjectNotFound + const events: NotificationsBrokerEventObject[] = [ + notificationsBrokerEventObjectMissingProjectFound, + notificationsBrokerEventObjectMissingProjectNotFound ]; const paginationService = new PaginationServiceStub(); - function getOpenAireBrokerEventData1(): OpenaireBrokerEventData { + function getNotificationsBrokerEventData1(): NotificationsBrokerEventData { return { - event: openaireBrokerEventObjectMissingProjectFound, - id: openaireBrokerEventObjectMissingProjectFound.id, - title: openaireBrokerEventObjectMissingProjectFound.title, + event: notificationsBrokerEventObjectMissingProjectFound, + id: notificationsBrokerEventObjectMissingProjectFound.id, + title: notificationsBrokerEventObjectMissingProjectFound.title, hasProject: true, - projectTitle: openaireBrokerEventObjectMissingProjectFound.message.title, + projectTitle: notificationsBrokerEventObjectMissingProjectFound.message.title, projectId: ItemMockPid10.id, handle: ItemMockPid10.handle, reason: null, @@ -82,11 +82,11 @@ describe('OpenaireBrokerEventsComponent test suite', () => { }; } - function getOpenAireBrokerEventData2(): OpenaireBrokerEventData { + function getNotificationsBrokerEventData2(): NotificationsBrokerEventData { return { - event: openaireBrokerEventObjectMissingProjectNotFound, - id: openaireBrokerEventObjectMissingProjectNotFound.id, - title: openaireBrokerEventObjectMissingProjectNotFound.title, + event: notificationsBrokerEventObjectMissingProjectNotFound, + id: notificationsBrokerEventObjectMissingProjectNotFound.id, + title: notificationsBrokerEventObjectMissingProjectNotFound.title, hasProject: false, projectTitle: null, projectId: null, @@ -104,17 +104,17 @@ describe('OpenaireBrokerEventsComponent test suite', () => { TranslateModule.forRoot(), ], declarations: [ - OpenaireBrokerEventsComponent, + NotificationsBrokerEventsComponent, TestComponent, ], providers: [ { provide: ActivatedRoute, useValue: new ActivatedRouteStub(activatedRouteParamsMap, activatedRouteParams) }, - { provide: OpenaireBrokerEventRestService, useValue: openaireBrokerEventRestServiceStub }, + { provide: NotificationsBrokerEventRestService, useValue: notificationsBrokerEventRestServiceStub }, { provide: NgbModal, useValue: modalStub }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: TranslateService, useValue: getMockTranslateService() }, { provide: PaginationService, useValue: paginationService }, - OpenaireBrokerEventsComponent + NotificationsBrokerEventsComponent ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(); @@ -129,7 +129,7 @@ describe('OpenaireBrokerEventsComponent test suite', () => { // synchronous beforeEach beforeEach(() => { const html = ` - `; + `; testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; }); @@ -138,14 +138,14 @@ describe('OpenaireBrokerEventsComponent test suite', () => { testFixture.destroy(); }); - it('should create OpenaireBrokerEventsComponent', inject([OpenaireBrokerEventsComponent], (app: OpenaireBrokerEventsComponent) => { + it('should create NotificationsBrokerEventsComponent', inject([NotificationsBrokerEventsComponent], (app: NotificationsBrokerEventsComponent) => { expect(app).toBeDefined(); })); }); describe('Main tests', () => { beforeEach(() => { - fixture = TestBed.createComponent(OpenaireBrokerEventsComponent); + fixture = TestBed.createComponent(NotificationsBrokerEventsComponent); comp = fixture.componentInstance; compAsAny = comp; }); @@ -159,8 +159,8 @@ describe('OpenaireBrokerEventsComponent test suite', () => { describe('setEventUpdated', () => { it('should update events', () => { const expected = [ - getOpenAireBrokerEventData1(), - getOpenAireBrokerEventData2() + getNotificationsBrokerEventData1(), + getNotificationsBrokerEventData2() ]; scheduler.schedule(() => { compAsAny.setEventUpdated(events); @@ -179,14 +179,14 @@ describe('OpenaireBrokerEventsComponent test suite', () => { it('should call executeAction if a project is present', () => { const action = 'ACCEPTED'; - comp.modalChoice(action, getOpenAireBrokerEventData1(), modalStub); - expect(comp.executeAction).toHaveBeenCalledWith(action, getOpenAireBrokerEventData1()); + comp.modalChoice(action, getNotificationsBrokerEventData1(), modalStub); + expect(comp.executeAction).toHaveBeenCalledWith(action, getNotificationsBrokerEventData1()); }); it('should call openModal if a project is not present', () => { const action = 'ACCEPTED'; - comp.modalChoice(action, getOpenAireBrokerEventData2(), modalStub); - expect(comp.openModal).toHaveBeenCalledWith(action, getOpenAireBrokerEventData2(), modalStub); + comp.modalChoice(action, getNotificationsBrokerEventData2(), modalStub); + expect(comp.openModal).toHaveBeenCalledWith(action, getNotificationsBrokerEventData2(), modalStub); }); }); @@ -197,7 +197,7 @@ describe('OpenaireBrokerEventsComponent test suite', () => { spyOn(compAsAny.modalService, 'open').and.returnValue({ result: new Promise((res, rej) => 'do' ) }); spyOn(comp, 'executeAction'); - comp.openModal(action, getOpenAireBrokerEventData1(), modalStub); + comp.openModal(action, getNotificationsBrokerEventData1(), modalStub); expect(compAsAny.modalService.open).toHaveBeenCalled(); }); }); @@ -211,13 +211,13 @@ describe('OpenaireBrokerEventsComponent test suite', () => { externalSourceEntry: null, label: null, importedObject: observableOf({ - indexableObject: OpenaireMockDspaceObject + indexableObject: NotificationsMockDspaceObject }) } } ); scheduler.schedule(() => { - comp.openModalLookup(getOpenAireBrokerEventData1()); + comp.openModalLookup(getNotificationsBrokerEventData1()); }); scheduler.flush(); @@ -227,27 +227,27 @@ describe('OpenaireBrokerEventsComponent test suite', () => { }); describe('executeAction', () => { - it('should call getOpenaireBrokerEvents on 200 response from REST', () => { + it('should call getNotificationsBrokerEvents on 200 response from REST', () => { const action = 'ACCEPTED'; - spyOn(compAsAny, 'getOpenaireBrokerEvents'); - openaireBrokerEventRestServiceStub.patchEvent.and.returnValue(createSuccessfulRemoteDataObject$({})); + spyOn(compAsAny, 'getNotificationsBrokerEvents'); + notificationsBrokerEventRestServiceStub.patchEvent.and.returnValue(createSuccessfulRemoteDataObject$({})); scheduler.schedule(() => { - comp.executeAction(action, getOpenAireBrokerEventData1()); + comp.executeAction(action, getNotificationsBrokerEventData1()); }); scheduler.flush(); - expect(compAsAny.getOpenaireBrokerEvents).toHaveBeenCalled(); + expect(compAsAny.getNotificationsBrokerEvents).toHaveBeenCalled(); }); }); describe('boundProject', () => { it('should populate the project data inside "eventData"', () => { - const eventData = getOpenAireBrokerEventData2(); + const eventData = getNotificationsBrokerEventData2(); const projectId = 'UUID-23943-34u43-38344'; const projectName = 'Test Project'; const projectHandle = '1000/1000'; - openaireBrokerEventRestServiceStub.boundProject.and.returnValue(createSuccessfulRemoteDataObject$({})); + notificationsBrokerEventRestServiceStub.boundProject.and.returnValue(createSuccessfulRemoteDataObject$({})); scheduler.schedule(() => { comp.boundProject(eventData, projectId, projectName, projectHandle); @@ -263,8 +263,8 @@ describe('OpenaireBrokerEventsComponent test suite', () => { describe('removeProject', () => { it('should remove the project data inside "eventData"', () => { - const eventData = getOpenAireBrokerEventData1(); - openaireBrokerEventRestServiceStub.removeProject.and.returnValue(createNoContentRemoteDataObject$()); + const eventData = getNotificationsBrokerEventData1(); + notificationsBrokerEventRestServiceStub.removeProject.and.returnValue(createNoContentRemoteDataObject$()); scheduler.schedule(() => { comp.removeProject(eventData); @@ -278,8 +278,8 @@ describe('OpenaireBrokerEventsComponent test suite', () => { }); }); - describe('getOpenaireBrokerEvents', () => { - it('should call the "openaireBrokerEventRestService.getEventsByTopic" to take data and "setEventUpdated" to populate eventData', () => { + describe('getNotificationsBrokerEvents', () => { + it('should call the "notificationsBrokerEventRestService.getEventsByTopic" to take data and "setEventUpdated" to populate eventData', () => { comp.paginationConfig = new PaginationComponentOptions(); comp.paginationConfig.currentPage = 1; comp.paginationConfig.pageSize = 20; @@ -297,20 +297,20 @@ describe('OpenaireBrokerEventsComponent test suite', () => { currentPage: comp.paginationConfig.currentPage }); const array = [ - openaireBrokerEventObjectMissingProjectFound, - openaireBrokerEventObjectMissingProjectNotFound, + notificationsBrokerEventObjectMissingProjectFound, + notificationsBrokerEventObjectMissingProjectNotFound, ]; const paginatedList = buildPaginatedList(pageInfo, array); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); - openaireBrokerEventRestServiceStub.getEventsByTopic.and.returnValue(observableOf(paginatedListRD)); + notificationsBrokerEventRestServiceStub.getEventsByTopic.and.returnValue(observableOf(paginatedListRD)); spyOn(compAsAny, 'setEventUpdated'); scheduler.schedule(() => { - compAsAny.getOpenaireBrokerEvents(); + compAsAny.getNotificationsBrokerEvents(); }); scheduler.flush(); - expect(compAsAny.openaireBrokerEventRestService.getEventsByTopic).toHaveBeenCalledWith( + expect(compAsAny.notificationsBrokerEventRestService.getEventsByTopic).toHaveBeenCalledWith( activatedRouteParamsMap.id, options, followLink('target'),followLink('related') diff --git a/src/app/openaire/broker/events/openaire-broker-events.component.ts b/src/app/notifications/broker/events/notifications-broker-events.component.ts similarity index 71% rename from src/app/openaire/broker/events/openaire-broker-events.component.ts rename to src/app/notifications/broker/events/notifications-broker-events.component.ts index 14ad175e809..b416664fca5 100644 --- a/src/app/openaire/broker/events/openaire-broker-events.component.ts +++ b/src/app/notifications/broker/events/notifications-broker-events.component.ts @@ -11,10 +11,10 @@ import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; import { FindListOptions } from '../../../core/data/request.models'; import { - OpenaireBrokerEventMessageObject, - OpenaireBrokerEventObject -} from '../../../core/openaire/broker/models/openaire-broker-event.model'; -import { OpenaireBrokerEventRestService } from '../../../core/openaire/broker/events/openaire-broker-event-rest.service'; + NotificationsBrokerEventObject, + OpenaireBrokerEventMessageObject +} from '../../../core/notifications/broker/models/notifications-broker-event.model'; +import { NotificationsBrokerEventRestService } from '../../../core/notifications/broker/events/notifications-broker-event-rest.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { Metadata } from '../../../core/shared/metadata.utils'; import { followLink } from '../../../shared/utils/follow-link-config.model'; @@ -22,7 +22,7 @@ import { hasValue } from '../../../shared/empty.util'; import { ItemSearchResult } from '../../../shared/object-collection/shared/item-search-result.model'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { - OpenaireBrokerEventData, + NotificationsBrokerEventData, ProjectEntryImportModalComponent } from '../project-entry-import-modal/project-entry-import-modal.component'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; @@ -31,14 +31,14 @@ import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { Item } from '../../../core/shared/item.model'; /** - * Component to display the OpenAIRE Broker event list. + * Component to display the Notifications Broker event list. */ @Component({ - selector: 'ds-openaire-broker-events', - templateUrl: './openaire-broker-events.component.html', - styleUrls: ['./openaire-broker-events.scomponent.scss'], + selector: 'ds-notifications-broker-events', + templateUrl: './notifications-broker-events.component.html', + styleUrls: ['./notifications-broker-events.scomponent.scss'], }) -export class OpenaireBrokerEventsComponent implements OnInit { +export class NotificationsBrokerEventsComponent implements OnInit { /** * The pagination system configuration for HTML listing. * @type {PaginationComponentOptions} @@ -50,27 +50,27 @@ export class OpenaireBrokerEventsComponent implements OnInit { pageSizeOptions: [5, 10, 20, 40, 60] }); /** - * The OpenAIRE Broker event list sort options. + * The Notifications Broker event list sort options. * @type {SortOptions} */ public paginationSortConfig: SortOptions = new SortOptions('trust', SortDirection.DESC); /** - * Array to save the presence of a project inside an OpenAIRE Broker event. - * @type {OpenaireBrokerEventData[]>} + * Array to save the presence of a project inside an Notifications Broker event. + * @type {NotificationsBrokerEventData[]>} */ - public eventsUpdated$: BehaviorSubject = new BehaviorSubject([]); + public eventsUpdated$: BehaviorSubject = new BehaviorSubject([]); /** - * The total number of OpenAIRE Broker events. + * The total number of Notifications Broker events. * @type {Observable} */ public totalElements$: Observable; /** - * The topic of the OpenAIRE Broker events; suitable for displaying. + * The topic of the Notifications Broker events; suitable for displaying. * @type {string} */ public showTopic: string; /** - * The topic of the OpenAIRE Broker events; suitable for HTTP calls. + * The topic of the Notifications Broker events; suitable for HTTP calls. * @type {string} */ public topic: string; @@ -114,7 +114,7 @@ export class OpenaireBrokerEventsComponent implements OnInit { * @param {ActivatedRoute} activatedRoute * @param {NgbModal} modalService * @param {NotificationsService} notificationsService - * @param {OpenaireBrokerEventRestService} openaireBrokerEventRestService + * @param {NotificationsBrokerEventRestService} notificationsBrokerEventRestService * @param {PaginationService} paginationService * @param {TranslateService} translateService */ @@ -122,7 +122,7 @@ export class OpenaireBrokerEventsComponent implements OnInit { private activatedRoute: ActivatedRoute, private modalService: NgbModal, private notificationsService: NotificationsService, - private openaireBrokerEventRestService: OpenaireBrokerEventRestService, + private notificationsBrokerEventRestService: NotificationsBrokerEventRestService, private paginationService: PaginationService, private translateService: TranslateService ) { @@ -142,7 +142,7 @@ export class OpenaireBrokerEventsComponent implements OnInit { this.showTopic = id.replace(regEx, '/'); this.topic = id; this.isEventPageLoading.next(false); - this.getOpenaireBrokerEvents(); + this.getNotificationsBrokerEvents(); }); } @@ -162,12 +162,12 @@ export class OpenaireBrokerEventsComponent implements OnInit { * * @param {string} action * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) - * @param {OpenaireBrokerEventData} eventData - * the OpenAIRE Broker event data + * @param {NotificationsBrokerEventData} eventData + * the Notifications Broker event data * @param {any} content * Reference to the modal */ - public modalChoice(action: string, eventData: OpenaireBrokerEventData, content: any): void { + public modalChoice(action: string, eventData: NotificationsBrokerEventData, content: any): void { if (eventData.hasProject) { this.executeAction(action, eventData); } else { @@ -180,12 +180,12 @@ export class OpenaireBrokerEventsComponent implements OnInit { * * @param {string} action * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) - * @param {OpenaireBrokerEventData} eventData - * the OpenAIRE Broker event data + * @param {NotificationsBrokerEventData} eventData + * the Notifications Broker event data * @param {any} content * Reference to the modal */ - public openModal(action: string, eventData: OpenaireBrokerEventData, content: any): void { + public openModal(action: string, eventData: NotificationsBrokerEventData, content: any): void { this.modalService.open(content, { ariaLabelledBy: 'modal-basic-title' }).result.then( (result) => { if (result === 'do') { @@ -203,10 +203,10 @@ export class OpenaireBrokerEventsComponent implements OnInit { /** * Open a modal where the user can select the project. * - * @param {OpenaireBrokerEventData} eventData - * the OpenAIRE Broker event item data + * @param {NotificationsBrokerEventData} eventData + * the Notifications Broker event item data */ - public openModalLookup(eventData: OpenaireBrokerEventData): void { + public openModalLookup(eventData: NotificationsBrokerEventData): void { this.modalRef = this.modalService.open(ProjectEntryImportModalComponent, { size: 'lg' }); @@ -232,22 +232,22 @@ export class OpenaireBrokerEventsComponent implements OnInit { * * @param {string} action * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) - * @param {OpenaireBrokerEventData} eventData - * the OpenAIRE Broker event data + * @param {NotificationsBrokerEventData} eventData + * the Notifications Broker event data */ - public executeAction(action: string, eventData: OpenaireBrokerEventData): void { + public executeAction(action: string, eventData: NotificationsBrokerEventData): void { eventData.isRunning = true; this.subs.push( - this.openaireBrokerEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) - .subscribe((rd: RemoteData) => { + this.notificationsBrokerEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { if (rd.isSuccess && rd.statusCode === 200) { this.notificationsService.success( - this.translateService.instant('openaire.broker.event.action.saved') + this.translateService.instant('notifications.broker.event.action.saved') ); - this.getOpenaireBrokerEvents(); + this.getNotificationsBrokerEvents(); } else { this.notificationsService.error( - this.translateService.instant('openaire.broker.event.action.error') + this.translateService.instant('notifications.broker.event.action.error') ); } eventData.isRunning = false; @@ -256,10 +256,10 @@ export class OpenaireBrokerEventsComponent implements OnInit { } /** - * Bound a project to the publication described in the OpenAIRE Broker event calling the REST service. + * Bound a project to the publication described in the Notifications Broker event calling the REST service. * - * @param {OpenaireBrokerEventData} eventData - * the OpenAIRE Broker event item data + * @param {NotificationsBrokerEventData} eventData + * the Notifications Broker event item data * @param {string} projectId * the project Id to bound * @param {string} projectTitle @@ -267,14 +267,14 @@ export class OpenaireBrokerEventsComponent implements OnInit { * @param {string} projectHandle * the project handle */ - public boundProject(eventData: OpenaireBrokerEventData, projectId: string, projectTitle: string, projectHandle: string): void { + public boundProject(eventData: NotificationsBrokerEventData, projectId: string, projectTitle: string, projectHandle: string): void { eventData.isRunning = true; this.subs.push( - this.openaireBrokerEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) - .subscribe((rd: RemoteData) => { + this.notificationsBrokerEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { if (rd.isSuccess) { this.notificationsService.success( - this.translateService.instant('openaire.broker.event.project.bounded') + this.translateService.instant('notifications.broker.event.project.bounded') ); eventData.hasProject = true; eventData.projectTitle = projectTitle; @@ -282,7 +282,7 @@ export class OpenaireBrokerEventsComponent implements OnInit { eventData.projectId = projectId; } else { this.notificationsService.error( - this.translateService.instant('openaire.broker.event.project.error') + this.translateService.instant('notifications.broker.event.project.error') ); } eventData.isRunning = false; @@ -291,19 +291,19 @@ export class OpenaireBrokerEventsComponent implements OnInit { } /** - * Remove the bounded project from the publication described in the OpenAIRE Broker event calling the REST service. + * Remove the bounded project from the publication described in the Notifications Broker event calling the REST service. * - * @param {OpenaireBrokerEventData} eventData - * the OpenAIRE Broker event data + * @param {NotificationsBrokerEventData} eventData + * the Notifications Broker event data */ - public removeProject(eventData: OpenaireBrokerEventData): void { + public removeProject(eventData: NotificationsBrokerEventData): void { eventData.isRunning = true; this.subs.push( - this.openaireBrokerEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) - .subscribe((rd: RemoteData) => { + this.notificationsBrokerEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { if (rd.isSuccess) { this.notificationsService.success( - this.translateService.instant('openaire.broker.event.project.removed') + this.translateService.instant('notifications.broker.event.project.removed') ); eventData.hasProject = false; eventData.projectTitle = null; @@ -311,7 +311,7 @@ export class OpenaireBrokerEventsComponent implements OnInit { eventData.projectId = null; } else { this.notificationsService.error( - this.translateService.instant('openaire.broker.event.project.error') + this.translateService.instant('notifications.broker.event.project.error') ); } eventData.isRunning = false; @@ -337,26 +337,26 @@ export class OpenaireBrokerEventsComponent implements OnInit { /** - * Dispatch the OpenAIRE Broker events retrival. + * Dispatch the Notifications Broker events retrival. */ - public getOpenaireBrokerEvents(): void { + public getNotificationsBrokerEvents(): void { this.paginationService.getFindListOptions(this.paginationConfig.id, this.defaultConfig).pipe( distinctUntilChanged(), - switchMap((options: FindListOptions) => this.openaireBrokerEventRestService.getEventsByTopic( + switchMap((options: FindListOptions) => this.notificationsBrokerEventRestService.getEventsByTopic( this.topic, options, followLink('target'), followLink('related') )), getFirstCompletedRemoteData(), - ).subscribe((rd: RemoteData>) => { + ).subscribe((rd: RemoteData>) => { if (rd.hasSucceeded) { this.isEventLoading.next(false); this.totalElements$ = observableOf(rd.payload.totalElements); this.setEventUpdated(rd.payload.page); } else { - throw new Error('Can\'t retrieve OpenAIRE Broker events from the Broker events REST service'); + throw new Error('Can\'t retrieve Notifications Broker events from the Broker events REST service'); } - this.openaireBrokerEventRestService.clearFindByTopicRequests(); + this.notificationsBrokerEventRestService.clearFindByTopicRequests(); }); } @@ -370,15 +370,15 @@ export class OpenaireBrokerEventsComponent implements OnInit { } /** - * Set the project status for the OpenAIRE Broker events. + * Set the project status for the Notifications Broker events. * - * @param {OpenaireBrokerEventObject[]} events - * the OpenAIRE Broker event item + * @param {NotificationsBrokerEventObject[]} events + * the Notifications Broker event item */ - protected setEventUpdated(events: OpenaireBrokerEventObject[]): void { + protected setEventUpdated(events: NotificationsBrokerEventObject[]): void { this.subs.push( from(events).pipe( - mergeMap((event: OpenaireBrokerEventObject) => { + mergeMap((event: NotificationsBrokerEventObject) => { const related$ = event.related.pipe( getFirstCompletedRemoteData(), ); @@ -387,7 +387,7 @@ export class OpenaireBrokerEventsComponent implements OnInit { ); return combineLatest([related$, target$]).pipe( map(([relatedItemRD, targetItemRD]: [RemoteData, RemoteData]) => { - const data: OpenaireBrokerEventData = { + const data: NotificationsBrokerEventData = { event: event, id: event.id, title: event.title, diff --git a/src/app/openaire/broker/events/openaire-broker-events.scomponent.scss b/src/app/notifications/broker/events/notifications-broker-events.scomponent.scss similarity index 100% rename from src/app/openaire/broker/events/openaire-broker-events.scomponent.scss rename to src/app/notifications/broker/events/notifications-broker-events.scomponent.scss diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.html b/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.html similarity index 100% rename from src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.html rename to src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.html diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.scss b/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.scss similarity index 100% rename from src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.scss rename to src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.scss diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts b/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts similarity index 92% rename from src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts rename to src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts index e19d0a7c867..7cac576844c 100644 --- a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts +++ b/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts @@ -17,16 +17,16 @@ import { buildPaginatedList } from '../../../core/data/paginated-list.model'; import { PageInfo } from '../../../core/shared/page-info.model'; import { ItemMockPid10, - openaireBrokerEventObjectMissingProjectFound, - OpenaireMockDspaceObject -} from '../../../shared/mocks/openaire.mock'; + notificationsBrokerEventObjectMissingProjectFound, + NotificationsMockDspaceObject +} from '../../../shared/mocks/notifications.mock'; const eventData = { - event: openaireBrokerEventObjectMissingProjectFound, - id: openaireBrokerEventObjectMissingProjectFound.id, - title: openaireBrokerEventObjectMissingProjectFound.title, + event: notificationsBrokerEventObjectMissingProjectFound, + id: notificationsBrokerEventObjectMissingProjectFound.id, + title: notificationsBrokerEventObjectMissingProjectFound.title, hasProject: true, - projectTitle: openaireBrokerEventObjectMissingProjectFound.message.title, + projectTitle: notificationsBrokerEventObjectMissingProjectFound.message.title, projectId: ItemMockPid10.id, handle: ItemMockPid10.handle, reason: null, @@ -36,7 +36,7 @@ const eventData = { const searchString = 'Test project to search'; const pagination = Object.assign( new PaginationComponentOptions(), { - id: 'openaire-project-bound', + id: 'notifications-project-bound', pageSize: 3 } ); @@ -54,7 +54,7 @@ const pageInfo = new PageInfo({ currentPage: 1 }); const array = [ - OpenaireMockDspaceObject, + NotificationsMockDspaceObject, ]; const paginatedList = buildPaginatedList(pageInfo, array); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); @@ -143,7 +143,7 @@ describe('ProjectEntryImportModalComponent test suite', () => { spyOn(comp, 'deselectAllLists'); spyOn(comp, 'close'); spyOn(comp.importedObject, 'emit'); - comp.selectedEntity = OpenaireMockDspaceObject; + comp.selectedEntity = NotificationsMockDspaceObject; comp.bound(); expect(comp.importedObject.emit).toHaveBeenCalled(); diff --git a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.ts b/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.ts similarity index 89% rename from src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.ts rename to src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.ts index 5d8cb20c6d2..64672fa1fac 100644 --- a/src/app/openaire/broker/project-entry-import-modal/project-entry-import-modal.component.ts +++ b/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.ts @@ -12,7 +12,11 @@ import { ListableObject } from '../../../shared/object-collection/shared/listabl import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { SearchService } from '../../../core/shared/search/search.service'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; -import { OpenaireBrokerEventObject } from '../../../core/openaire/broker/models/openaire-broker-event.model'; +import { + NotificationsBrokerEventObject, + NotificationsBrokerEventMessageObject, + OpenaireBrokerEventMessageObject, +} from '../../../core/notifications/broker/models/notifications-broker-event.model'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; import { Item } from '../../../core/shared/item.model'; @@ -30,13 +34,13 @@ export enum ImportType { /** * The data type passed from the parent page */ -export interface OpenaireBrokerEventData { +export interface NotificationsBrokerEventData { /** - * The OpenAIRE Broker event + * The Notifications Broker event */ - event: OpenaireBrokerEventObject; + event: NotificationsBrokerEventObject; /** - * The OpenAIRE Broker event Id (uuid) + * The Notifications Broker event Id (uuid) */ id: string; /** @@ -79,14 +83,14 @@ export interface OpenaireBrokerEventData { templateUrl: './project-entry-import-modal.component.html' }) /** - * Component to display a modal window for linking a project to an OpenAIRE Broker event + * Component to display a modal window for linking a project to an Notifications Broker event * Shows information about the selected project and a selectable list. */ export class ProjectEntryImportModalComponent implements OnInit { /** * The external source entry */ - @Input() externalSourceEntry: OpenaireBrokerEventData; + @Input() externalSourceEntry: NotificationsBrokerEventData; /** * The number of results per page */ @@ -94,7 +98,7 @@ export class ProjectEntryImportModalComponent implements OnInit { /** * The prefix for every i18n key within this modal */ - labelPrefix = 'openaire.broker.event.modal.'; + labelPrefix = 'notifications.broker.event.modal.'; /** * The search configuration to retrieve project */ @@ -126,11 +130,11 @@ export class ProjectEntryImportModalComponent implements OnInit { /** * List ID for selecting local entities */ - entityListId = 'openaire-project-bound'; + entityListId = 'notifications-project-bound'; /** * List ID for selecting local authorities */ - authorityListId = 'openaire-project-bound-authority'; + authorityListId = 'notifications-project-bound-authority'; /** * ImportType enum */ @@ -175,8 +179,9 @@ export class ProjectEntryImportModalComponent implements OnInit { * Component intitialization. */ public ngOnInit(): void { - this.pagination = Object.assign(new PaginationComponentOptions(), { id: 'openaire-project-bound', pageSize: this.pageSize }); - this.projectTitle = (this.externalSourceEntry.projectTitle !== null) ? this.externalSourceEntry.projectTitle : this.externalSourceEntry.event.message.title; + this.pagination = Object.assign(new PaginationComponentOptions(), { id: 'notifications-project-bound', pageSize: this.pageSize }); + this.projectTitle = (this.externalSourceEntry.projectTitle !== null) ? this.externalSourceEntry.projectTitle + : (this.externalSourceEntry.event.message as OpenaireBrokerEventMessageObject).title; this.searchOptions = Object.assign(new PaginatedSearchOptions( { configuration: this.configuration, diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.actions.ts b/src/app/notifications/broker/topics/notifications-broker-topics.actions.ts similarity index 60% rename from src/app/openaire/broker/topics/openaire-broker-topics.actions.ts rename to src/app/notifications/broker/topics/notifications-broker-topics.actions.ts index fd98c6acb8b..622ecc81414 100644 --- a/src/app/openaire/broker/topics/openaire-broker-topics.actions.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.actions.ts @@ -1,6 +1,6 @@ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/openaire-broker-topic.model'; +import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; /** * For each action type in an action group, make a simple @@ -10,19 +10,19 @@ import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/ * literal types and runs a simple check to guarantee all * action types in the application are unique. */ -export const OpenaireBrokerTopicActionTypes = { - ADD_TOPICS: type('dspace/integration/openaire/broker/topic/ADD_TOPICS'), - RETRIEVE_ALL_TOPICS: type('dspace/integration/openaire/broker/topic/RETRIEVE_ALL_TOPICS'), - RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/openaire/broker/topic/RETRIEVE_ALL_TOPICS_ERROR'), +export const NotificationsBrokerTopicActionTypes = { + ADD_TOPICS: type('dspace/integration/notifications/broker/topic/ADD_TOPICS'), + RETRIEVE_ALL_TOPICS: type('dspace/integration/notifications/broker/topic/RETRIEVE_ALL_TOPICS'), + RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/notifications/broker/topic/RETRIEVE_ALL_TOPICS_ERROR'), }; /* tslint:disable:max-classes-per-file */ /** - * An ngrx action to retrieve all the OpenAIRE Broker topics. + * An ngrx action to retrieve all the Notifications Broker topics. */ export class RetrieveAllTopicsAction implements Action { - type = OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS; + type = NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS; payload: { elementsPerPage: number; currentPage: number; @@ -45,20 +45,20 @@ export class RetrieveAllTopicsAction implements Action { } /** - * An ngrx action for retrieving 'all OpenAIRE Broker topics' error. + * An ngrx action for retrieving 'all Notifications Broker topics' error. */ export class RetrieveAllTopicsErrorAction implements Action { - type = OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR; + type = NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR; } /** - * An ngrx action to load the OpenAIRE Broker topic objects. + * An ngrx action to load the Notifications Broker topic objects. * Called by the ??? effect. */ export class AddTopicsAction implements Action { - type = OpenaireBrokerTopicActionTypes.ADD_TOPICS; + type = NotificationsBrokerTopicActionTypes.ADD_TOPICS; payload: { - topics: OpenaireBrokerTopicObject[]; + topics: NotificationsBrokerTopicObject[]; totalPages: number; currentPage: number; totalElements: number; @@ -74,9 +74,9 @@ export class AddTopicsAction implements Action { * @param currentPage * the current page * @param totalElements - * the total available OpenAIRE Broker topics + * the total available Notifications Broker topics */ - constructor(topics: OpenaireBrokerTopicObject[], totalPages: number, currentPage: number, totalElements: number) { + constructor(topics: NotificationsBrokerTopicObject[], totalPages: number, currentPage: number, totalElements: number) { this.payload = { topics, totalPages, @@ -93,7 +93,7 @@ export class AddTopicsAction implements Action { * Export a type alias of all actions in this action group * so that reducers can easily compose action types. */ -export type OpenaireBrokerTopicsActions +export type NotificationsBrokerTopicsActions = AddTopicsAction |RetrieveAllTopicsAction |RetrieveAllTopicsErrorAction; diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.html b/src/app/notifications/broker/topics/notifications-broker-topics.component.html similarity index 66% rename from src/app/openaire/broker/topics/openaire-broker-topics.component.html rename to src/app/notifications/broker/topics/notifications-broker-topics.component.html index d8321bc932b..02371a8a6b9 100644 --- a/src/app/openaire/broker/topics/openaire-broker-topics.component.html +++ b/src/app/notifications/broker/topics/notifications-broker-topics.component.html @@ -1,34 +1,34 @@
-

{{'openaire.broker.title'| translate}}

-

{{'openaire.broker.topics.description'| translate}}

+

{{'notifications.broker.title'| translate}}

+

{{'notifications.broker.topics.description'| translate}}

-

{{'openaire.broker.topics'| translate}}

+

{{'notifications.broker.topics'| translate}}

- + + (paginationChange)="getNotificationsBrokerTopics()"> - +

{{'openaire.broker.event.table.trust' | translate}}{{'openaire.broker.event.table.publication' | translate}}{{'openaire.broker.event.table.details' | translate}}{{'openaire.broker.event.table.project-details' | translate}}{{'openaire.broker.event.table.actions' | translate}}{{'notifications.broker.event.table.trust' | translate}}{{'notifications.broker.event.table.publication' | translate}}{{'notifications.broker.event.table.details' | translate}}{{'notifications.broker.event.table.project-details' | translate}}{{'notifications.broker.event.table.actions' | translate}}
-

{{'openaire.broker.event.table.pidtype' | translate}} {{eventElement.event.message.type}}

-

{{'openaire.broker.event.table.pidvalue' | translate}}
+

{{'notifications.broker.event.table.pidtype' | translate}} {{eventElement.event.message.type}}

+

{{'notifications.broker.event.table.pidvalue' | translate}}
{{eventElement.event.message.value}} @@ -60,37 +60,37 @@

-

{{'openaire.broker.event.table.subjectValue' | translate}}
{{eventElement.event.message.value}}

+

{{'notifications.broker.event.table.subjectValue' | translate}}
{{eventElement.event.message.value}}

- {{'openaire.broker.event.table.abstract' | translate}}
+ {{'notifications.broker.event.table.abstract' | translate}}
{{eventElement.event.message.abstract}}

- {{'openaire.broker.event.table.suggestedProject' | translate}} + {{'notifications.broker.event.table.suggestedProject' | translate}}

- {{'openaire.broker.event.table.project' | translate}}
+ {{'notifications.broker.event.table.project' | translate}}
{{eventElement.event.message.title}}

- {{'openaire.broker.event.table.acronym' | translate}} {{eventElement.event.message.acronym}}
- {{'openaire.broker.event.table.code' | translate}} {{eventElement.event.message.code}}
- {{'openaire.broker.event.table.funder' | translate}} {{eventElement.event.message.funder}}
- {{'openaire.broker.event.table.fundingProgram' | translate}} {{eventElement.event.message.fundingProgram}}
- {{'openaire.broker.event.table.jurisdiction' | translate}} {{eventElement.event.message.jurisdiction}} + {{'notifications.broker.event.table.acronym' | translate}} {{eventElement.event.message.acronym}}
+ {{'notifications.broker.event.table.code' | translate}} {{eventElement.event.message.code}}
+ {{'notifications.broker.event.table.funder' | translate}} {{eventElement.event.message.funder}}
+ {{'notifications.broker.event.table.fundingProgram' | translate}} {{eventElement.event.message.fundingProgram}}
+ {{'notifications.broker.event.table.jurisdiction' | translate}} {{eventElement.event.message.jurisdiction}}


- {{(eventElement.hasProject ? 'openaire.broker.event.project.found' : 'openaire.broker.event.project.notFound') | translate}} + {{(eventElement.hasProject ? 'notifications.broker.event.project.found' : 'notifications.broker.event.project.notFound') | translate}} {{eventElement.handle}}
- - - + + + @@ -39,7 +39,7 @@

{{'openaire.broker.topics'| translate}}

{{'openaire.broker.table.topic' | translate}}{{'openaire.broker.table.last-event' | translate}}{{'openaire.broker.table.actions' | translate}}{{'notifications.broker.table.topic' | translate}}{{'notifications.broker.table.last-event' | translate}}{{'notifications.broker.table.actions' | translate}}
+ + + + + + + + + + + + + + +
{{'notifications.broker.table.source' | translate}}{{'notifications.broker.table.last-event' | translate}}{{'notifications.broker.table.actions' | translate}}
{{sourceElement.id}}{{sourceElement.lastEvent}} +
+ +
+
+
+
+
+
+
+
+ diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.scss b/src/app/notifications/broker/source/notifications-broker-source.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts b/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts new file mode 100644 index 00000000000..7d18c726c51 --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NotificationsBrokerSourceComponent } from './notifications-broker-source.component'; + +describe('NotificationsBrokerSourceComponent', () => { + let component: NotificationsBrokerSourceComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ NotificationsBrokerSourceComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NotificationsBrokerSourceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.ts b/src/app/notifications/broker/source/notifications-broker-source.component.ts new file mode 100644 index 00000000000..070e03f396f --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.component.ts @@ -0,0 +1,139 @@ +import { Component, OnInit } from '@angular/core'; +import { PaginationService } from '../../../core/pagination/pagination.service'; +import { Observable, Subscription } from 'rxjs'; +import { distinctUntilChanged, take } from 'rxjs/operators'; +import { SortOptions } from '../../../core/cache/models/sort-options.model'; +import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; +import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { NotificationsStateService } from '../../notifications-state.service'; +import { AdminNotificationsBrokerSourcePageParams } from '../../../admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service'; +import { hasValue } from '../../../shared/empty.util'; + +@Component({ + selector: 'ds-notifications-broker-source', + templateUrl: './notifications-broker-source.component.html', + styleUrls: ['./notifications-broker-source.component.scss'] +}) +export class NotificationsBrokerSourceComponent implements OnInit { + + /** + * The pagination system configuration for HTML listing. + * @type {PaginationComponentOptions} + */ + public paginationConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { + id: 'btp', + pageSize: 10, + pageSizeOptions: [5, 10, 20, 40, 60] + }); + /** + * The Notifications Broker source list sort options. + * @type {SortOptions} + */ + public paginationSortConfig: SortOptions; + /** + * The Notifications Broker source list. + */ + public sources$: Observable; + /** + * The total number of Notifications Broker sources. + */ + public totalElements$: Observable; + /** + * Array to track all the component subscriptions. Useful to unsubscribe them with 'onDestroy'. + * @type {Array} + */ + protected subs: Subscription[] = []; + + /** + * Initialize the component variables. + * @param {PaginationService} paginationService + * @param {NotificationsStateService} notificationsStateService + */ + constructor( + private paginationService: PaginationService, + private notificationsStateService: NotificationsStateService, + ) { } + + /** + * Component initialization. + */ + ngOnInit(): void { + this.sources$ = this.notificationsStateService.getNotificationsBrokerSource(); + this.totalElements$ = this.notificationsStateService.getNotificationsBrokerSourceTotals(); + } + + /** + * First Notifications Broker source loading after view initialization. + */ + ngAfterViewInit(): void { + this.subs.push( + this.notificationsStateService.isNotificationsBrokerSourceLoaded().pipe( + take(1) + ).subscribe(() => { + this.getNotificationsBrokerSource(); + }) + ); + } + + /** + * Returns the information about the loading status of the Notifications Broker source (if it's running or not). + * + * @return Observable + * 'true' if the source are loading, 'false' otherwise. + */ + public isSourceLoading(): Observable { + return this.notificationsStateService.isNotificationsBrokerSourceLoading(); + } + + /** + * Returns the information about the processing status of the Notifications Broker source (if it's running or not). + * + * @return Observable + * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. + */ + public isSourceProcessing(): Observable { + return this.notificationsStateService.isNotificationsBrokerSourceProcessing(); + } + + /** + * Dispatch the Notifications Broker source retrival. + */ + public getNotificationsBrokerSource(): void { + this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe( + distinctUntilChanged(), + ).subscribe((options: PaginationComponentOptions) => { + this.notificationsStateService.dispatchRetrieveNotificationsBrokerSource( + options.pageSize, + options.currentPage + ); + }); + } + + /** + * Update pagination Config from route params + * + * @param eventsRouteParams + */ + protected updatePaginationFromRouteParams(eventsRouteParams: AdminNotificationsBrokerSourcePageParams) { + if (eventsRouteParams.currentPage) { + this.paginationConfig.currentPage = eventsRouteParams.currentPage; + } + if (eventsRouteParams.pageSize) { + if (this.paginationConfig.pageSizeOptions.includes(eventsRouteParams.pageSize)) { + this.paginationConfig.pageSize = eventsRouteParams.pageSize; + } else { + this.paginationConfig.pageSize = this.paginationConfig.pageSizeOptions[0]; + } + } + } + + /** + * Unsubscribe from all subscriptions. + */ + ngOnDestroy(): void { + this.subs + .filter((sub) => hasValue(sub)) + .forEach((sub) => sub.unsubscribe()); + } + +} diff --git a/src/app/notifications/broker/source/notifications-broker-source.effects.ts b/src/app/notifications/broker/source/notifications-broker-source.effects.ts new file mode 100644 index 00000000000..bd8b3f00cd9 --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.effects.ts @@ -0,0 +1,87 @@ +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Actions, Effect, ofType } from '@ngrx/effects'; +import { TranslateService } from '@ngx-translate/core'; +import { catchError, map, switchMap, tap, withLatestFrom } from 'rxjs/operators'; +import { of as observableOf } from 'rxjs'; +import { + AddSourceAction, + NotificationsBrokerSourceActionTypes, + RetrieveAllSourceAction, + RetrieveAllSourceErrorAction, +} from './notifications-broker-source.actions'; + +import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { NotificationsBrokerSourceService } from './notifications-broker-source.service'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { NotificationsBrokerSourceRestService } from '../../../core/notifications/broker/source/notifications-broker-source-rest.service'; + +/** + * Provides effect methods for the Notifications Broker source actions. + */ +@Injectable() +export class NotificationsBrokerSourceEffects { + + /** + * Retrieve all Notifications Broker source managing pagination and errors. + */ + @Effect() retrieveAllSource$ = this.actions$.pipe( + ofType(NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE), + withLatestFrom(this.store$), + switchMap(([action, currentState]: [RetrieveAllSourceAction, any]) => { + return this.notificationsBrokerSourceService.getSources( + action.payload.elementsPerPage, + action.payload.currentPage + ).pipe( + map((sources: PaginatedList) => + new AddSourceAction(sources.page, sources.totalPages, sources.currentPage, sources.totalElements) + ), + catchError((error: Error) => { + if (error) { + console.error(error.message); + } + return observableOf(new RetrieveAllSourceErrorAction()); + }) + ); + }) + ); + + /** + * Show a notification on error. + */ + @Effect({ dispatch: false }) retrieveAllSourceErrorAction$ = this.actions$.pipe( + ofType(NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR), + tap(() => { + this.notificationsService.error(null, this.translate.get('notifications.broker.source.error.service.retrieve')); + }) + ); + + /** + * Clear find all source requests from cache. + */ + @Effect({ dispatch: false }) addSourceAction$ = this.actions$.pipe( + ofType(NotificationsBrokerSourceActionTypes.ADD_SOURCE), + tap(() => { + this.notificationsBrokerSourceDataService.clearFindAllSourceRequests(); + }) + ); + + /** + * Initialize the effect class variables. + * @param {Actions} actions$ + * @param {Store} store$ + * @param {TranslateService} translate + * @param {NotificationsService} notificationsService + * @param {NotificationsBrokerSourceService} notificationsBrokerSourceService + * @param {NotificationsBrokerSourceRestService} notificationsBrokerSourceDataService + */ + constructor( + private actions$: Actions, + private store$: Store, + private translate: TranslateService, + private notificationsService: NotificationsService, + private notificationsBrokerSourceService: NotificationsBrokerSourceService, + private notificationsBrokerSourceDataService: NotificationsBrokerSourceRestService + ) { } +} diff --git a/src/app/notifications/broker/source/notifications-broker-source.reducer.ts b/src/app/notifications/broker/source/notifications-broker-source.reducer.ts new file mode 100644 index 00000000000..5395796380c --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.reducer.ts @@ -0,0 +1,72 @@ +import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; +import { NotificationsBrokerSourceActionTypes, NotificationsBrokerSourceActions } from './notifications-broker-source.actions'; + +/** + * The interface representing the Notifications Broker source state. + */ +export interface NotificationsBrokerSourceState { + source: NotificationsBrokerSourceObject[]; + processing: boolean; + loaded: boolean; + totalPages: number; + currentPage: number; + totalElements: number; +} + +/** + * Used for the Notifications Broker source state initialization. + */ +const notificationsBrokerSourceInitialState: NotificationsBrokerSourceState = { + source: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0 +}; + +/** + * The Notifications Broker Source Reducer + * + * @param state + * the current state initialized with notificationsBrokerSourceInitialState + * @param action + * the action to perform on the state + * @return NotificationsBrokerSourceState + * the new state + */ +export function notificationsBrokerSourceReducer(state = notificationsBrokerSourceInitialState, action: NotificationsBrokerSourceActions): NotificationsBrokerSourceState { + switch (action.type) { + case NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE: { + return Object.assign({}, state, { + source: [], + processing: true + }); + } + + case NotificationsBrokerSourceActionTypes.ADD_SOURCE: { + return Object.assign({}, state, { + source: action.payload.source, + processing: false, + loaded: true, + totalPages: action.payload.totalPages, + currentPage: state.currentPage, + totalElements: action.payload.totalElements + }); + } + + case NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR: { + return Object.assign({}, state, { + processing: false, + loaded: true, + totalPages: 0, + currentPage: 0, + totalElements: 0 + }); + } + + default: { + return state; + } + } +} diff --git a/src/app/notifications/broker/source/notifications-broker-source.service.ts b/src/app/notifications/broker/source/notifications-broker-source.service.ts new file mode 100644 index 00000000000..e80643049c2 --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { find, map } from 'rxjs/operators'; +import { NotificationsBrokerSourceRestService } from '../../../core/notifications/broker/source/notifications-broker-source-rest.service'; +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { FindListOptions } from '../../../core/data/request.models'; +import { RemoteData } from '../../../core/data/remote-data'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; + +/** + * The service handling all Notifications Broker source requests to the REST service. + */ +@Injectable() +export class NotificationsBrokerSourceService { + + /** + * Initialize the service variables. + * @param {NotificationsBrokerSourceRestService} notificationsBrokerSourceRestService + */ + constructor( + private notificationsBrokerSourceRestService: NotificationsBrokerSourceRestService + ) { } + + /** + * Return the list of Notifications Broker source managing pagination and errors. + * + * @param elementsPerPage + * The number of the source per page + * @param currentPage + * The page number to retrieve + * @return Observable> + * The list of Notifications Broker source. + */ + public getSources(elementsPerPage, currentPage): Observable> { + const sortOptions = new SortOptions('name', SortDirection.ASC); + + const findListOptions: FindListOptions = { + elementsPerPage: elementsPerPage, + currentPage: currentPage, + sort: sortOptions + }; + + return this.notificationsBrokerSourceRestService.getSources(findListOptions).pipe( + find((rd: RemoteData>) => !rd.isResponsePending), + map((rd: RemoteData>) => { + if (rd.hasSucceeded) { + return rd.payload; + } else { + throw new Error('Can\'t retrieve Notifications Broker source from the Broker source REST service'); + } + }) + ); + } +} diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.html b/src/app/notifications/broker/topics/notifications-broker-topics.component.html index 02371a8a6b9..8b27778ee94 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.component.html +++ b/src/app/notifications/broker/topics/notifications-broker-topics.component.html @@ -2,7 +2,7 @@

{{'notifications.broker.title'| translate}}

-

{{'notifications.broker.topics.description'| translate}}

+

{{'notifications.broker.topics.description'| translate:{source: sourceId} }}

diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.ts b/src/app/notifications/broker/topics/notifications-broker-topics.component.ts index 3bedf6b9d02..f33d3c2fb10 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.component.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { Observable, Subscription } from 'rxjs'; -import { distinctUntilChanged, take } from 'rxjs/operators'; +import { distinctUntilChanged, map, take } from 'rxjs/operators'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; @@ -10,6 +10,8 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio import { NotificationsStateService } from '../../notifications-state.service'; import { AdminNotificationsBrokerTopicsPageParams } from '../../../admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; +import { ActivatedRoute } from '@angular/router'; +import { NotificationsBrokerTopicsService } from './notifications-broker-topics.service'; /** * Component to display the Notifications Broker topic list. @@ -48,6 +50,12 @@ export class NotificationsBrokerTopicsComponent implements OnInit { */ protected subs: Subscription[] = []; + /** + * This property represents a sourceId which is used to retrive a topic + * @type {string} + */ + public sourceId: string; + /** * Initialize the component variables. * @param {PaginationService} paginationService @@ -55,8 +63,18 @@ export class NotificationsBrokerTopicsComponent implements OnInit { */ constructor( private paginationService: PaginationService, + private activatedRoute: ActivatedRoute, private notificationsStateService: NotificationsStateService, - ) { } + private notificationsBrokerTopicsService: NotificationsBrokerTopicsService + ) { + this.activatedRoute.paramMap.pipe( + map((params) => params.get('sourceId')), + take(1) + ).subscribe((id: string) => { + this.sourceId = id; + this.notificationsBrokerTopicsService.setSourceId(this.sourceId); + }); + } /** * Component initialization. diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.service.ts b/src/app/notifications/broker/topics/notifications-broker-topics.service.ts index b04229e0d9d..80c52a70a96 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.service.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.service.ts @@ -7,6 +7,7 @@ import { FindListOptions } from '../../../core/data/request.models'; import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; +import { RequestParam } from '../../../core/cache/models/request-param.model'; /** * The service handling all Notifications Broker topic requests to the REST service. @@ -22,6 +23,11 @@ export class NotificationsBrokerTopicsService { private notificationsBrokerTopicRestService: NotificationsBrokerTopicRestService ) { } + /** + * sourceId used to get topics + */ + sourceId: string; + /** * Return the list of Notifications Broker topics managing pagination and errors. * @@ -38,7 +44,8 @@ export class NotificationsBrokerTopicsService { const findListOptions: FindListOptions = { elementsPerPage: elementsPerPage, currentPage: currentPage, - sort: sortOptions + sort: sortOptions, + searchParams: [new RequestParam('source', this.sourceId)] }; return this.notificationsBrokerTopicRestService.getTopics(findListOptions).pipe( @@ -52,4 +59,12 @@ export class NotificationsBrokerTopicsService { }) ); } + + /** + * set sourceId which is used to get topics + * @param sourceId string + */ + setSourceId(sourceId: string) { + this.sourceId = sourceId; + } } diff --git a/src/app/notifications/notifications-state.service.ts b/src/app/notifications/notifications-state.service.ts index c81c924465e..cbee503acd1 100644 --- a/src/app/notifications/notifications-state.service.ts +++ b/src/app/notifications/notifications-state.service.ts @@ -8,11 +8,19 @@ import { getNotificationsBrokerTopicsTotalsSelector, isNotificationsBrokerTopicsLoadedSelector, notificationsBrokerTopicsObjectSelector, - isNotificationsBrokerTopicsProcessingSelector + isNotificationsBrokerTopicsProcessingSelector, + notificationsBrokerSourceObjectSelector, + isNotificationsBrokerSourceLoadedSelector, + isNotificationsBrokerSourceProcessingSelector, + getNotificationsBrokerSourceTotalPagesSelector, + getNotificationsBrokerSourceCurrentPageSelector, + getNotificationsBrokerSourceTotalsSelector } from './selectors'; import { NotificationsBrokerTopicObject } from '../core/notifications/broker/models/notifications-broker-topic.model'; import { NotificationsState } from './notifications.reducer'; import { RetrieveAllTopicsAction } from './broker/topics/notifications-broker-topics.actions'; +import { NotificationsBrokerSourceObject } from '../core/notifications/broker/models/notifications-broker-source.model'; +import { RetrieveAllSourceAction } from './broker/source/notifications-broker-source.actions'; /** * The service handling the Notifications State. @@ -113,4 +121,92 @@ export class NotificationsStateService { public dispatchRetrieveNotificationsBrokerTopics(elementsPerPage: number, currentPage: number): void { this.store.dispatch(new RetrieveAllTopicsAction(elementsPerPage, currentPage)); } + + // Notifications Broker source + // -------------------------------------------------------------------------- + + /** + * Returns the list of Notifications Broker source from the state. + * + * @return Observable + * The list of Notifications Broker source. + */ + public getNotificationsBrokerSource(): Observable { + return this.store.pipe(select(notificationsBrokerSourceObjectSelector())); + } + + /** + * Returns the information about the loading status of the Notifications Broker source (if it's running or not). + * + * @return Observable + * 'true' if the source are loading, 'false' otherwise. + */ + public isNotificationsBrokerSourceLoading(): Observable { + return this.store.pipe( + select(isNotificationsBrokerSourceLoadedSelector), + map((loaded: boolean) => !loaded) + ); + } + + /** + * Returns the information about the loading status of the Notifications Broker source (whether or not they were loaded). + * + * @return Observable + * 'true' if the source are loaded, 'false' otherwise. + */ + public isNotificationsBrokerSourceLoaded(): Observable { + return this.store.pipe(select(isNotificationsBrokerSourceLoadedSelector)); + } + + /** + * Returns the information about the processing status of the Notifications Broker source (if it's running or not). + * + * @return Observable + * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. + */ + public isNotificationsBrokerSourceProcessing(): Observable { + return this.store.pipe(select(isNotificationsBrokerSourceProcessingSelector)); + } + + /** + * Returns, from the state, the total available pages of the Notifications Broker source. + * + * @return Observable + * The number of the Notifications Broker source pages. + */ + public getNotificationsBrokerSourceTotalPages(): Observable { + return this.store.pipe(select(getNotificationsBrokerSourceTotalPagesSelector)); + } + + /** + * Returns the current page of the Notifications Broker source, from the state. + * + * @return Observable + * The number of the current Notifications Broker source page. + */ + public getNotificationsBrokerSourceCurrentPage(): Observable { + return this.store.pipe(select(getNotificationsBrokerSourceCurrentPageSelector)); + } + + /** + * Returns the total number of the Notifications Broker source. + * + * @return Observable + * The number of the Notifications Broker source. + */ + public getNotificationsBrokerSourceTotals(): Observable { + return this.store.pipe(select(getNotificationsBrokerSourceTotalsSelector)); + } + + /** + * Dispatch a request to change the Notifications Broker source state, retrieving the source from the server. + * + * @param elementsPerPage + * The number of the source per page. + * @param currentPage + * The number of the current page. + */ + public dispatchRetrieveNotificationsBrokerSource(elementsPerPage: number, currentPage: number): void { + this.store.dispatch(new RetrieveAllSourceAction(elementsPerPage, currentPage)); + } } diff --git a/src/app/notifications/notifications.effects.ts b/src/app/notifications/notifications.effects.ts index cbc76a5b3eb..39ecded7970 100644 --- a/src/app/notifications/notifications.effects.ts +++ b/src/app/notifications/notifications.effects.ts @@ -1,5 +1,7 @@ +import { NotificationsBrokerSourceEffects } from './broker/source/notifications-broker-source.effects'; import { NotificationsBrokerTopicsEffects } from './broker/topics/notifications-broker-topics.effects'; export const notificationsEffects = [ - NotificationsBrokerTopicsEffects + NotificationsBrokerTopicsEffects, + NotificationsBrokerSourceEffects ]; diff --git a/src/app/notifications/notifications.module.ts b/src/app/notifications/notifications.module.ts index 4b0ba3cfd18..63224fdd81b 100644 --- a/src/app/notifications/notifications.module.ts +++ b/src/app/notifications/notifications.module.ts @@ -17,6 +17,9 @@ import { NotificationsBrokerEventRestService } from '../core/notifications/broke import { ProjectEntryImportModalComponent } from './broker/project-entry-import-modal/project-entry-import-modal.component'; import { TranslateModule } from '@ngx-translate/core'; import { SearchModule } from '../shared/search/search.module'; +import { NotificationsBrokerSourceComponent } from './broker/source/notifications-broker-source.component'; +import { NotificationsBrokerSourceService } from './broker/source/notifications-broker-source.service'; +import { NotificationsBrokerSourceRestService } from '../core/notifications/broker/source/notifications-broker-source-rest.service'; const MODULES = [ CommonModule, @@ -29,7 +32,8 @@ const MODULES = [ const COMPONENTS = [ NotificationsBrokerTopicsComponent, - NotificationsBrokerEventsComponent + NotificationsBrokerEventsComponent, + NotificationsBrokerSourceComponent ]; const DIRECTIVES = [ ]; @@ -41,7 +45,9 @@ const ENTRY_COMPONENTS = [ const PROVIDERS = [ NotificationsStateService, NotificationsBrokerTopicsService, + NotificationsBrokerSourceService, NotificationsBrokerTopicRestService, + NotificationsBrokerSourceRestService, NotificationsBrokerEventRestService ]; diff --git a/src/app/notifications/notifications.reducer.ts b/src/app/notifications/notifications.reducer.ts index b3dc54d5249..27bebbea205 100644 --- a/src/app/notifications/notifications.reducer.ts +++ b/src/app/notifications/notifications.reducer.ts @@ -1,5 +1,5 @@ import { ActionReducerMap, createFeatureSelector } from '@ngrx/store'; - +import { notificationsBrokerSourceReducer, NotificationsBrokerSourceState } from './broker/source/notifications-broker-source.reducer'; import { notificationsBrokerTopicsReducer, NotificationsBrokerTopicState, } from './broker/topics/notifications-broker-topics.reducer'; /** @@ -7,10 +7,12 @@ import { notificationsBrokerTopicsReducer, NotificationsBrokerTopicState, } from */ export interface NotificationsState { 'brokerTopic': NotificationsBrokerTopicState; + 'brokerSource': NotificationsBrokerSourceState; } export const notificationsReducers: ActionReducerMap = { brokerTopic: notificationsBrokerTopicsReducer, + brokerSource: notificationsBrokerSourceReducer }; export const notificationsSelector = createFeatureSelector('notifications'); diff --git a/src/app/notifications/selectors.ts b/src/app/notifications/selectors.ts index 7474aa3adc8..0436a35eb30 100644 --- a/src/app/notifications/selectors.ts +++ b/src/app/notifications/selectors.ts @@ -3,6 +3,8 @@ import { subStateSelector } from '../shared/selector.util'; import { notificationsSelector, NotificationsState } from './notifications.reducer'; import { NotificationsBrokerTopicObject } from '../core/notifications/broker/models/notifications-broker-topic.model'; import { NotificationsBrokerTopicState } from './broker/topics/notifications-broker-topics.reducer'; +import { NotificationsBrokerSourceState } from './broker/source/notifications-broker-source.reducer'; +import { NotificationsBrokerSourceObject } from '../core/notifications/broker/models/notifications-broker-source.model'; /** * Returns the Notifications state. @@ -77,3 +79,69 @@ export const getNotificationsBrokerTopicsCurrentPageSelector = createSelector(_g export const getNotificationsBrokerTopicsTotalsSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerTopic.totalElements ); + +// Notifications Broker source +// ---------------------------------------------------------------------------- + +/** + * Returns the Notifications Broker source State. + * @function notificationsBrokerSourceStateSelector + * @return {NotificationsBrokerSourceState} + */ + export function notificationsBrokerSourceStateSelector(): MemoizedSelector { + return subStateSelector(notificationsSelector, 'brokerSource'); +} + +/** + * Returns the Notifications Broker source list. + * @function notificationsBrokerSourceObjectSelector + * @return {NotificationsBrokerSourceObject[]} + */ +export function notificationsBrokerSourceObjectSelector(): MemoizedSelector { + return subStateSelector(notificationsBrokerSourceStateSelector(), 'source'); +} + +/** + * Returns true if the Notifications Broker source are loaded. + * @function isNotificationsBrokerSourceLoadedSelector + * @return {boolean} + */ +export const isNotificationsBrokerSourceLoadedSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerSource.loaded +); + +/** + * Returns true if the deduplication sets are processing. + * @function isDeduplicationSetsProcessingSelector + * @return {boolean} + */ +export const isNotificationsBrokerSourceProcessingSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerSource.processing +); + +/** + * Returns the total available pages of Notifications Broker source. + * @function getNotificationsBrokerSourceTotalPagesSelector + * @return {number} + */ +export const getNotificationsBrokerSourceTotalPagesSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerSource.totalPages +); + +/** + * Returns the current page of Notifications Broker source. + * @function getNotificationsBrokerSourceCurrentPageSelector + * @return {number} + */ +export const getNotificationsBrokerSourceCurrentPageSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerSource.currentPage +); + +/** + * Returns the total number of Notifications Broker source. + * @function getNotificationsBrokerSourceTotalsSelector + * @return {number} + */ +export const getNotificationsBrokerSourceTotalsSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerSource.totalElements +); diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 674254e6057..e04792273b8 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -487,6 +487,8 @@ "admin.notifications.broker.page.title": "Notifications Broker", + "admin.notifications.source.breadcrumbs": "Notifications Source", + "admin.search.breadcrumbs": "Administrative Search", "admin.search.collection.edit": "Edit", @@ -2713,14 +2715,20 @@ "none.listelement.badge": "Item", - "notifications.broker.title": "{{source}} Broker", + "notifications.broker.title": "Broker Title", "notifications.broker.topics.description": "Below you can see all the topics received from the subscriptions to {{source}}.", + "notifications.broker.source.description": "Below you can see all the sources.", + "notifications.broker.topics": "Current Topics", + "notifications.broker.source": "Current Sources", + "notifications.broker.table.topic": "Topic", + "notifications.broker.table.source": "Source", + "notifications.broker.table.last-event": "Last Event", "notifications.broker.table.actions": "Actions", @@ -2729,10 +2737,14 @@ "notifications.broker.noTopics": "No topics found.", + "notifications.broker.noSource": "No sources found.", + "notifications.events.title": "{{source}} Broker Suggestions", "notifications.broker.topic.error.service.retrieve": "An error occurred while loading the Notifications Broker topics", + "notifications.broker.source.error.service.retrieve": "An error occurred while loading the Notifications Broker source", + "notifications.broker.events.description": "Below the list of all the suggestions, received from {{source}}, for the selected topic.", "notifications.broker.loading": "Loading ...", From 00f7fa97f1462d5370a50025c63e2dd97cc27d74 Mon Sep 17 00:00:00 2001 From: Pratik Rajkotiya Date: Thu, 10 Mar 2022 11:49:12 +0530 Subject: [PATCH 004/196] [CST-5337] test cases done. --- config/config.yml | 4 +- ...tions-broker-source-page.component.spec.ts | 6 +- ...cations-broker-source-rest.service.spec.ts | 127 ++++ ...ifications-broker-source.component.spec.ts | 159 ++++- ...otifications-broker-source.reducer.spec.ts | 68 ++ ...otifications-broker-source.service.spec.ts | 68 ++ ...ifications-broker-topics.component.spec.ts | 15 +- .../notifications-broker-topics.component.ts | 9 +- ...otifications-broker-topics.service.spec.ts | 5 +- .../notifications-state.service.spec.ts | 656 ++++++++++++------ src/app/shared/mocks/notifications.mock.ts | 58 ++ 11 files changed, 948 insertions(+), 227 deletions(-) create mode 100644 src/app/core/notifications/broker/source/notifications-broker-source-rest.service.spec.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.reducer.spec.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.service.spec.ts diff --git a/config/config.yml b/config/config.yml index b5eecd112f0..3866797f5d3 100644 --- a/config/config.yml +++ b/config/config.yml @@ -1,5 +1,5 @@ rest: - ssl: true - host: api7.dspace.org + ssl: false + host: localhost:8080 port: 443 nameSpace: /server diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts index c4a3611c584..f6d3eb20fe5 100644 --- a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts +++ b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts @@ -1,3 +1,4 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AdminNotificationsBrokerSourcePageComponent } from './admin-notifications-broker-source-page.component'; @@ -8,7 +9,8 @@ describe('AdminNotificationsBrokerSourcePageComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ AdminNotificationsBrokerSourcePageComponent ] + declarations: [ AdminNotificationsBrokerSourcePageComponent ], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); }); @@ -19,7 +21,7 @@ describe('AdminNotificationsBrokerSourcePageComponent', () => { fixture.detectChanges(); }); - it('should create', () => { + it('should create AdminNotificationsBrokerSourcePageComponent', () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.spec.ts b/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.spec.ts new file mode 100644 index 00000000000..984f44bd15d --- /dev/null +++ b/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.spec.ts @@ -0,0 +1,127 @@ +import { HttpClient } from '@angular/common/http'; + +import { TestScheduler } from 'rxjs/testing'; +import { of as observableOf } from 'rxjs'; +import { cold, getTestScheduler } from 'jasmine-marbles'; + +import { RequestService } from '../../../data/request.service'; +import { buildPaginatedList } from '../../../data/paginated-list.model'; +import { RequestEntry } from '../../../data/request.reducer'; +import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../cache/object-cache.service'; +import { RestResponse } from '../../../cache/response.models'; +import { PageInfo } from '../../../shared/page-info.model'; +import { HALEndpointService } from '../../../shared/hal-endpoint.service'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; +import { NotificationsBrokerSourceRestService } from './notifications-broker-source-rest.service'; +import { + notificationsBrokerSourceObjectMoreAbstract, + notificationsBrokerSourceObjectMorePid +} from '../../../../shared/mocks/notifications.mock'; + +describe('NotificationsBrokerSourceRestService', () => { + let scheduler: TestScheduler; + let service: NotificationsBrokerSourceRestService; + let responseCacheEntry: RequestEntry; + let requestService: RequestService; + let rdbService: RemoteDataBuildService; + let objectCache: ObjectCacheService; + let halService: HALEndpointService; + let notificationsService: NotificationsService; + let http: HttpClient; + let comparator: any; + + const endpointURL = 'https://rest.api/rest/api/integration/nbsources'; + const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; + + const pageInfo = new PageInfo(); + const array = [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ]; + const paginatedList = buildPaginatedList(pageInfo, array); + const brokerSourceObjectRD = createSuccessfulRemoteDataObject(notificationsBrokerSourceObjectMorePid); + const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); + + beforeEach(() => { + scheduler = getTestScheduler(); + + responseCacheEntry = new RequestEntry(); + responseCacheEntry.response = new RestResponse(true, 200, 'Success'); + requestService = jasmine.createSpyObj('requestService', { + generateRequestId: requestUUID, + send: true, + removeByHrefSubstring: {}, + getByHref: observableOf(responseCacheEntry), + getByUUID: observableOf(responseCacheEntry), + }); + + rdbService = jasmine.createSpyObj('rdbService', { + buildSingle: cold('(a)', { + a: brokerSourceObjectRD + }), + buildList: cold('(a)', { + a: paginatedListRD + }), + }); + + objectCache = {} as ObjectCacheService; + halService = jasmine.createSpyObj('halService', { + getEndpoint: cold('a|', { a: endpointURL }) + }); + + notificationsService = {} as NotificationsService; + http = {} as HttpClient; + comparator = {} as any; + + service = new NotificationsBrokerSourceRestService( + requestService, + rdbService, + objectCache, + halService, + notificationsService, + http, + comparator + ); + + spyOn((service as any).dataService, 'findAllByHref').and.callThrough(); + spyOn((service as any).dataService, 'findByHref').and.callThrough(); + }); + + describe('getSources', () => { + it('should proxy the call to dataservice.findAllByHref', (done) => { + service.getSources().subscribe( + (res) => { + expect((service as any).dataService.findAllByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); + } + ); + done(); + }); + + it('should return a RemoteData> for the object with the given URL', () => { + const result = service.getSources(); + const expected = cold('(a)', { + a: paginatedListRD + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getSource', () => { + it('should proxy the call to dataservice.findByHref', (done) => { + service.getSource(notificationsBrokerSourceObjectMorePid.id).subscribe( + (res) => { + expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + notificationsBrokerSourceObjectMorePid.id, true, true); + } + ); + done(); + }); + + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getSource(notificationsBrokerSourceObjectMorePid.id); + const expected = cold('(a)', { + a: brokerSourceObjectRD + }); + expect(result).toBeObservable(expected); + }); + }); + +}); diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts b/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts index 7d18c726c51..6c0ad42ce8a 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts +++ b/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts @@ -1,25 +1,152 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - +import { CommonModule } from '@angular/common'; +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs'; +import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing'; +import { createTestComponent } from '../../../shared/testing/utils.test'; +import { + getMockNotificationsStateService, + notificationsBrokerSourceObjectMoreAbstract, + notificationsBrokerSourceObjectMorePid +} from '../../../shared/mocks/notifications.mock'; import { NotificationsBrokerSourceComponent } from './notifications-broker-source.component'; +import { NotificationsStateService } from '../../notifications-state.service'; +import { cold } from 'jasmine-marbles'; +import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; +import { PaginationService } from '../../../core/pagination/pagination.service'; -describe('NotificationsBrokerSourceComponent', () => { - let component: NotificationsBrokerSourceComponent; +describe('NotificationsBrokerSourceComponent test suite', () => { let fixture: ComponentFixture; + let comp: NotificationsBrokerSourceComponent; + let compAsAny: any; + const mockNotificationsStateService = getMockNotificationsStateService(); + const activatedRouteParams = { + notificationsBrokerSourceParams: { + currentPage: 0, + pageSize: 5 + } + }; + const paginationService = new PaginationServiceStub(); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ NotificationsBrokerSourceComponent ] - }) - .compileComponents(); - }); + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + CommonModule, + TranslateModule.forRoot(), + ], + declarations: [ + NotificationsBrokerSourceComponent, + TestComponent, + ], + providers: [ + { provide: NotificationsStateService, useValue: mockNotificationsStateService }, + { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), params: observableOf({}) } }, + { provide: PaginationService, useValue: paginationService }, + NotificationsBrokerSourceComponent + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents().then(() => { + mockNotificationsStateService.getNotificationsBrokerSource.and.returnValue(observableOf([ + notificationsBrokerSourceObjectMorePid, + notificationsBrokerSourceObjectMoreAbstract + ])); + mockNotificationsStateService.getNotificationsBrokerSourceTotalPages.and.returnValue(observableOf(1)); + mockNotificationsStateService.getNotificationsBrokerSourceCurrentPage.and.returnValue(observableOf(0)); + mockNotificationsStateService.getNotificationsBrokerSourceTotals.and.returnValue(observableOf(2)); + mockNotificationsStateService.isNotificationsBrokerSourceLoaded.and.returnValue(observableOf(true)); + mockNotificationsStateService.isNotificationsBrokerSourceLoading.and.returnValue(observableOf(false)); + mockNotificationsStateService.isNotificationsBrokerSourceProcessing.and.returnValue(observableOf(false)); + }); + })); + + // First test to check the correct component creation + describe('', () => { + let testComp: TestComponent; + let testFixture: ComponentFixture; + + // synchronous beforeEach + beforeEach(() => { + const html = ` + `; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture; + testComp = testFixture.componentInstance; + }); + + afterEach(() => { + testFixture.destroy(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(NotificationsBrokerSourceComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + it('should create NotificationsBrokerSourceComponent', inject([NotificationsBrokerSourceComponent], (app: NotificationsBrokerSourceComponent) => { + expect(app).toBeDefined(); + })); }); - it('should create', () => { - expect(component).toBeTruthy(); + describe('Main tests running with two Source', () => { + beforeEach(() => { + fixture = TestBed.createComponent(NotificationsBrokerSourceComponent); + comp = fixture.componentInstance; + compAsAny = comp; + + }); + + afterEach(() => { + fixture.destroy(); + comp = null; + compAsAny = null; + }); + + it(('Should init component properly'), () => { + comp.ngOnInit(); + fixture.detectChanges(); + + expect(comp.sources$).toBeObservable(cold('(a|)', { + a: [ + notificationsBrokerSourceObjectMorePid, + notificationsBrokerSourceObjectMoreAbstract + ] + })); + expect(comp.totalElements$).toBeObservable(cold('(a|)', { + a: 2 + })); + }); + + it(('Should set data properly after the view init'), () => { + spyOn(compAsAny, 'getNotificationsBrokerSource'); + + comp.ngAfterViewInit(); + fixture.detectChanges(); + + expect(compAsAny.getNotificationsBrokerSource).toHaveBeenCalled(); + }); + + it(('isSourceLoading should return FALSE'), () => { + expect(comp.isSourceLoading()).toBeObservable(cold('(a|)', { + a: false + })); + }); + + it(('isSourceProcessing should return FALSE'), () => { + expect(comp.isSourceProcessing()).toBeObservable(cold('(a|)', { + a: false + })); + }); + + it(('getNotificationsBrokerSource should call the service to dispatch a STATE change'), () => { + comp.ngOnInit(); + fixture.detectChanges(); + + compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerSource(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage).and.callThrough(); + expect(compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerSource).toHaveBeenCalledWith(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage); + }); }); }); + +// declare a test component +@Component({ + selector: 'ds-test-cmp', + template: `` +}) +class TestComponent { + +} diff --git a/src/app/notifications/broker/source/notifications-broker-source.reducer.spec.ts b/src/app/notifications/broker/source/notifications-broker-source.reducer.spec.ts new file mode 100644 index 00000000000..74bc77d3ec4 --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.reducer.spec.ts @@ -0,0 +1,68 @@ +import { + AddSourceAction, + RetrieveAllSourceAction, + RetrieveAllSourceErrorAction + } from './notifications-broker-source.actions'; + import { notificationsBrokerSourceReducer, NotificationsBrokerSourceState } from './notifications-broker-source.reducer'; + import { + notificationsBrokerSourceObjectMoreAbstract, + notificationsBrokerSourceObjectMorePid + } from '../../../shared/mocks/notifications.mock'; + + describe('notificationsBrokerSourceReducer test suite', () => { + let notificationsBrokerSourceInitialState: NotificationsBrokerSourceState; + const elementPerPage = 3; + const currentPage = 0; + + beforeEach(() => { + notificationsBrokerSourceInitialState = { + source: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0 + }; + }); + + it('Action RETRIEVE_ALL_SOURCE should set the State property "processing" to TRUE', () => { + const expectedState = notificationsBrokerSourceInitialState; + expectedState.processing = true; + + const action = new RetrieveAllSourceAction(elementPerPage, currentPage); + const newState = notificationsBrokerSourceReducer(notificationsBrokerSourceInitialState, action); + + expect(newState).toEqual(expectedState); + }); + + it('Action RETRIEVE_ALL_SOURCE_ERROR should change the State to initial State but processing, loaded, and currentPage', () => { + const expectedState = notificationsBrokerSourceInitialState; + expectedState.processing = false; + expectedState.loaded = true; + expectedState.currentPage = 0; + + const action = new RetrieveAllSourceErrorAction(); + const newState = notificationsBrokerSourceReducer(notificationsBrokerSourceInitialState, action); + + expect(newState).toEqual(expectedState); + }); + + it('Action ADD_SOURCE should populate the State with Notifications Broker source', () => { + const expectedState = { + source: [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ], + processing: false, + loaded: true, + totalPages: 1, + currentPage: 0, + totalElements: 2 + }; + + const action = new AddSourceAction( + [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ], + 1, 0, 2 + ); + const newState = notificationsBrokerSourceReducer(notificationsBrokerSourceInitialState, action); + + expect(newState).toEqual(expectedState); + }); + }); diff --git a/src/app/notifications/broker/source/notifications-broker-source.service.spec.ts b/src/app/notifications/broker/source/notifications-broker-source.service.spec.ts new file mode 100644 index 00000000000..e94804cbf68 --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.service.spec.ts @@ -0,0 +1,68 @@ +import { TestBed } from '@angular/core/testing'; +import { of as observableOf } from 'rxjs'; +import { NotificationsBrokerSourceService } from './notifications-broker-source.service'; +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { PageInfo } from '../../../core/shared/page-info.model'; +import { FindListOptions } from '../../../core/data/request.models'; +import { + getMockNotificationsBrokerSourceRestService, + notificationsBrokerSourceObjectMoreAbstract, + notificationsBrokerSourceObjectMorePid +} from '../../../shared/mocks/notifications.mock'; +import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; +import { cold } from 'jasmine-marbles'; +import { buildPaginatedList } from '../../../core/data/paginated-list.model'; +import { NotificationsBrokerSourceRestService } from '../../../core/notifications/broker/source/notifications-broker-source-rest.service'; +import { RequestParam } from '../../../core/cache/models/request-param.model'; + +describe('NotificationsBrokerSourceService', () => { + let service: NotificationsBrokerSourceService; + let restService: NotificationsBrokerSourceRestService; + let serviceAsAny: any; + let restServiceAsAny: any; + + const pageInfo = new PageInfo(); + const array = [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ]; + const paginatedList = buildPaginatedList(pageInfo, array); + const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); + const elementsPerPage = 3; + const currentPage = 0; + + beforeEach(async () => { + TestBed.configureTestingModule({ + providers: [ + { provide: NotificationsBrokerSourceRestService, useClass: getMockNotificationsBrokerSourceRestService }, + { provide: NotificationsBrokerSourceService, useValue: service } + ] + }).compileComponents(); + }); + + beforeEach(() => { + restService = TestBed.get(NotificationsBrokerSourceRestService); + restServiceAsAny = restService; + restServiceAsAny.getSources.and.returnValue(observableOf(paginatedListRD)); + service = new NotificationsBrokerSourceService(restService); + serviceAsAny = service; + }); + + describe('getSources', () => { + it('Should proxy the call to notificationsBrokerSourceRestService.getSources', () => { + const sortOptions = new SortOptions('name', SortDirection.ASC); + const findListOptions: FindListOptions = { + elementsPerPage: elementsPerPage, + currentPage: currentPage, + sort: sortOptions + }; + const result = service.getSources(elementsPerPage, currentPage); + expect((service as any).notificationsBrokerSourceRestService.getSources).toHaveBeenCalledWith(findListOptions); + }); + + it('Should return a paginated list of Notifications Broker Source', () => { + const expected = cold('(a|)', { + a: paginatedList + }); + const result = service.getSources(elementsPerPage, currentPage); + expect(result).toBeObservable(expected); + }); + }); +}); diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts b/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts index 5bbe3b29079..dbb81373211 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts @@ -1,8 +1,8 @@ import { CommonModule } from '@angular/common'; import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; -import { of as observableOf } from 'rxjs'; +import { of as observableOf, of } from 'rxjs'; import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing'; import { createTestComponent } from '../../../shared/testing/utils.test'; import { @@ -15,6 +15,7 @@ import { NotificationsStateService } from '../../notifications-state.service'; import { cold } from 'jasmine-marbles'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; +import { NotificationsBrokerTopicsService } from './notifications-broker-topics.service'; describe('NotificationsBrokerTopicsComponent test suite', () => { let fixture: ComponentFixture; @@ -41,9 +42,15 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { ], providers: [ { provide: NotificationsStateService, useValue: mockNotificationsStateService }, - { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), params: observableOf({}) } }, + { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), snapshot: { + paramMap: { + get: () => 'openaire', + }, + }}}, { provide: PaginationService, useValue: paginationService }, - NotificationsBrokerTopicsComponent + NotificationsBrokerTopicsComponent, + // tslint:disable-next-line: no-empty + { provide: NotificationsBrokerTopicsService, useValue: { setSourceId: (sourceId: string) => { } }} ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(() => { diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.ts b/src/app/notifications/broker/topics/notifications-broker-topics.component.ts index f33d3c2fb10..a740ca5c1ee 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.component.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.component.ts @@ -67,19 +67,14 @@ export class NotificationsBrokerTopicsComponent implements OnInit { private notificationsStateService: NotificationsStateService, private notificationsBrokerTopicsService: NotificationsBrokerTopicsService ) { - this.activatedRoute.paramMap.pipe( - map((params) => params.get('sourceId')), - take(1) - ).subscribe((id: string) => { - this.sourceId = id; - this.notificationsBrokerTopicsService.setSourceId(this.sourceId); - }); } /** * Component initialization. */ ngOnInit(): void { + this.sourceId = this.activatedRoute.snapshot.paramMap.get('sourceId'); + this.notificationsBrokerTopicsService.setSourceId(this.sourceId); this.topics$ = this.notificationsStateService.getNotificationsBrokerTopics(); this.totalElements$ = this.notificationsStateService.getNotificationsBrokerTopicsTotals(); } diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts b/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts index 3b780fc173d..e5616df3208 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts @@ -13,6 +13,7 @@ import { import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; import { cold } from 'jasmine-marbles'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; +import { RequestParam } from '../../../core/cache/models/request-param.model'; describe('NotificationsBrokerTopicsService', () => { let service: NotificationsBrokerTopicsService; @@ -50,8 +51,10 @@ describe('NotificationsBrokerTopicsService', () => { const findListOptions: FindListOptions = { elementsPerPage: elementsPerPage, currentPage: currentPage, - sort: sortOptions + sort: sortOptions, + searchParams: [new RequestParam('source', 'ENRICH!MORE!ABSTRACT')] }; + service.setSourceId('ENRICH!MORE!ABSTRACT'); const result = service.getTopics(elementsPerPage, currentPage); expect((service as any).notificationsBrokerTopicRestService.getTopics).toHaveBeenCalledWith(findListOptions); }); diff --git a/src/app/notifications/notifications-state.service.spec.ts b/src/app/notifications/notifications-state.service.spec.ts index 97d958e2435..91048a93ef3 100644 --- a/src/app/notifications/notifications-state.service.spec.ts +++ b/src/app/notifications/notifications-state.service.spec.ts @@ -5,11 +5,15 @@ import { cold } from 'jasmine-marbles'; import { notificationsReducers } from './notifications.reducer'; import { NotificationsStateService } from './notifications-state.service'; import { + notificationsBrokerSourceObjectMissingPid, + notificationsBrokerSourceObjectMoreAbstract, + notificationsBrokerSourceObjectMorePid, notificationsBrokerTopicObjectMissingPid, notificationsBrokerTopicObjectMoreAbstract, notificationsBrokerTopicObjectMorePid } from '../shared/mocks/notifications.mock'; import { RetrieveAllTopicsAction } from './broker/topics/notifications-broker-topics.actions'; +import { RetrieveAllSourceAction } from './broker/source/notifications-broker-source.actions'; describe('NotificationsStateService', () => { let service: NotificationsStateService; @@ -17,259 +21,521 @@ describe('NotificationsStateService', () => { let store: any; let initialState: any; - function init(mode: string) { - if (mode === 'empty') { - initialState = { - notifications: { - brokerTopic: { - topics: [], - processing: false, - loaded: false, - totalPages: 0, - currentPage: 0, - totalElements: 0, - totalLoadedPages: 0 + describe('Topis State', () => { + function init(mode: string) { + if (mode === 'empty') { + initialState = { + notifications: { + brokerTopic: { + topics: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0, + totalLoadedPages: 0 + } } - } - }; - } else { - initialState = { - notifications: { - brokerTopic: { - topics: [ - notificationsBrokerTopicObjectMorePid, - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMissingPid - ], - processing: false, - loaded: true, - totalPages: 1, - currentPage: 1, - totalElements: 3, - totalLoadedPages: 1 + }; + } else { + initialState = { + notifications: { + brokerTopic: { + topics: [ + notificationsBrokerTopicObjectMorePid, + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMissingPid + ], + processing: false, + loaded: true, + totalPages: 1, + currentPage: 1, + totalElements: 3, + totalLoadedPages: 1 + } } - } - }; + }; + } } - } - - describe('Testing methods with empty topic objects', () => { - beforeEach(async () => { - init('empty'); - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), - ], - providers: [ - provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } - ] - }).compileComponents(); - }); - beforeEach(() => { - store = TestBed.get(Store); - service = new NotificationsStateService(store); - serviceAsAny = service; - spyOn(store, 'dispatch'); - }); + describe('Testing methods with empty topic objects', () => { + beforeEach(async () => { + init('empty'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ notifications: notificationsReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: NotificationsStateService, useValue: service } + ] + }).compileComponents(); + }); - describe('getNotificationsBrokerTopics', () => { - it('Should return an empty array', () => { - const result = service.getNotificationsBrokerTopics(); - const expected = cold('(a)', { - a: [] + beforeEach(() => { + store = TestBed.get(Store); + service = new NotificationsStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('getNotificationsBrokerTopics', () => { + it('Should return an empty array', () => { + const result = service.getNotificationsBrokerTopics(); + const expected = cold('(a)', { + a: [] + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('getNotificationsBrokerTopicsTotalPages', () => { - it('Should return zero (0)', () => { - const result = service.getNotificationsBrokerTopicsTotalPages(); - const expected = cold('(a)', { - a: 0 + describe('getNotificationsBrokerTopicsTotalPages', () => { + it('Should return zero (0)', () => { + const result = service.getNotificationsBrokerTopicsTotalPages(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('getNotificationsBrokerTopicsCurrentPage', () => { - it('Should return minus one (0)', () => { - const result = service.getNotificationsBrokerTopicsCurrentPage(); - const expected = cold('(a)', { - a: 0 + describe('getNotificationsBrokerTopicsCurrentPage', () => { + it('Should return minus one (0)', () => { + const result = service.getNotificationsBrokerTopicsCurrentPage(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('getNotificationsBrokerTopicsTotals', () => { - it('Should return zero (0)', () => { - const result = service.getNotificationsBrokerTopicsTotals(); - const expected = cold('(a)', { - a: 0 + describe('getNotificationsBrokerTopicsTotals', () => { + it('Should return zero (0)', () => { + const result = service.getNotificationsBrokerTopicsTotals(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('isNotificationsBrokerTopicsLoading', () => { - it('Should return TRUE', () => { - const result = service.isNotificationsBrokerTopicsLoading(); - const expected = cold('(a)', { - a: true + describe('isNotificationsBrokerTopicsLoading', () => { + it('Should return TRUE', () => { + const result = service.isNotificationsBrokerTopicsLoading(); + const expected = cold('(a)', { + a: true + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerTopicsLoaded', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerTopicsLoaded(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerTopicsProcessing', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerTopicsProcessing(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); }); - describe('isNotificationsBrokerTopicsLoaded', () => { - it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsLoaded(); - const expected = cold('(a)', { - a: false + describe('Testing methods with topic objects', () => { + beforeEach(async () => { + init('full'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ notifications: notificationsReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: NotificationsStateService, useValue: service } + ] + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.get(Store); + service = new NotificationsStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('getNotificationsBrokerTopics', () => { + it('Should return an array of topics', () => { + const result = service.getNotificationsBrokerTopics(); + const expected = cold('(a)', { + a: [ + notificationsBrokerTopicObjectMorePid, + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMissingPid + ] + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getNotificationsBrokerTopicsTotalPages', () => { + it('Should return one (1)', () => { + const result = service.getNotificationsBrokerTopicsTotalPages(); + const expected = cold('(a)', { + a: 1 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getNotificationsBrokerTopicsCurrentPage', () => { + it('Should return minus zero (1)', () => { + const result = service.getNotificationsBrokerTopicsCurrentPage(); + const expected = cold('(a)', { + a: 1 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getNotificationsBrokerTopicsTotals', () => { + it('Should return three (3)', () => { + const result = service.getNotificationsBrokerTopicsTotals(); + const expected = cold('(a)', { + a: 3 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerTopicsLoading', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerTopicsLoading(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerTopicsLoaded', () => { + it('Should return TRUE', () => { + const result = service.isNotificationsBrokerTopicsLoaded(); + const expected = cold('(a)', { + a: true + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerTopicsProcessing', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerTopicsProcessing(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); }); - describe('isNotificationsBrokerTopicsProcessing', () => { - it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsProcessing(); - const expected = cold('(a)', { - a: false + describe('Testing the topic dispatch methods', () => { + beforeEach(async () => { + init('full'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ notifications: notificationsReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: NotificationsStateService, useValue: service } + ] + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.get(Store); + service = new NotificationsStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('dispatchRetrieveNotificationsBrokerTopics', () => { + it('Should call store.dispatch', () => { + const elementsPerPage = 3; + const currentPage = 1; + const action = new RetrieveAllTopicsAction(elementsPerPage, currentPage); + service.dispatchRetrieveNotificationsBrokerTopics(elementsPerPage, currentPage); + expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action); }); - expect(result).toBeObservable(expected); }); }); }); - describe('Testing methods with topic objects', () => { - beforeEach(async () => { - init('full'); - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), - ], - providers: [ - provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } - ] - }).compileComponents(); - }); + describe('Source State', () => { + function init(mode: string) { + if (mode === 'empty') { + initialState = { + notifications: { + brokerSource: { + source: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0, + totalLoadedPages: 0 + } + } + }; + } else { + initialState = { + notifications: { + brokerSource: { + source: [ + notificationsBrokerSourceObjectMorePid, + notificationsBrokerSourceObjectMoreAbstract, + notificationsBrokerSourceObjectMissingPid + ], + processing: false, + loaded: true, + totalPages: 1, + currentPage: 1, + totalElements: 3, + totalLoadedPages: 1 + } + } + }; + } + } + + describe('Testing methods with empty source objects', () => { + beforeEach(async () => { + init('empty'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ notifications: notificationsReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: NotificationsStateService, useValue: service } + ] + }).compileComponents(); + }); - beforeEach(() => { - store = TestBed.get(Store); - service = new NotificationsStateService(store); - serviceAsAny = service; - spyOn(store, 'dispatch'); + beforeEach(() => { + store = TestBed.get(Store); + service = new NotificationsStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('getNotificationsBrokerSource', () => { + it('Should return an empty array', () => { + const result = service.getNotificationsBrokerSource(); + const expected = cold('(a)', { + a: [] + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getNotificationsBrokerSourceTotalPages', () => { + it('Should return zero (0)', () => { + const result = service.getNotificationsBrokerSourceTotalPages(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getNotificationsBrokerSourcesCurrentPage', () => { + it('Should return minus one (0)', () => { + const result = service.getNotificationsBrokerSourceCurrentPage(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('getNotificationsBrokerSourceTotals', () => { + it('Should return zero (0)', () => { + const result = service.getNotificationsBrokerSourceTotals(); + const expected = cold('(a)', { + a: 0 + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerSourceLoading', () => { + it('Should return TRUE', () => { + const result = service.isNotificationsBrokerSourceLoading(); + const expected = cold('(a)', { + a: true + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerSourceLoaded', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerSourceLoaded(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); + + describe('isNotificationsBrokerSourceProcessing', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerSourceProcessing(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); + }); + }); }); - describe('getNotificationsBrokerTopics', () => { - it('Should return an array of topics', () => { - const result = service.getNotificationsBrokerTopics(); - const expected = cold('(a)', { - a: [ - notificationsBrokerTopicObjectMorePid, - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMissingPid + describe('Testing methods with Source objects', () => { + beforeEach(async () => { + init('full'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ notifications: notificationsReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: NotificationsStateService, useValue: service } ] + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.get(Store); + service = new NotificationsStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); + + describe('getNotificationsBrokerSource', () => { + it('Should return an array of Source', () => { + const result = service.getNotificationsBrokerSource(); + const expected = cold('(a)', { + a: [ + notificationsBrokerSourceObjectMorePid, + notificationsBrokerSourceObjectMoreAbstract, + notificationsBrokerSourceObjectMissingPid + ] + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('getNotificationsBrokerTopicsTotalPages', () => { - it('Should return one (1)', () => { - const result = service.getNotificationsBrokerTopicsTotalPages(); - const expected = cold('(a)', { - a: 1 + describe('getNotificationsBrokerSourceTotalPages', () => { + it('Should return one (1)', () => { + const result = service.getNotificationsBrokerSourceTotalPages(); + const expected = cold('(a)', { + a: 1 + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('getNotificationsBrokerTopicsCurrentPage', () => { - it('Should return minus zero (1)', () => { - const result = service.getNotificationsBrokerTopicsCurrentPage(); - const expected = cold('(a)', { - a: 1 + describe('getNotificationsBrokerSourceCurrentPage', () => { + it('Should return minus zero (1)', () => { + const result = service.getNotificationsBrokerSourceCurrentPage(); + const expected = cold('(a)', { + a: 1 + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('getNotificationsBrokerTopicsTotals', () => { - it('Should return three (3)', () => { - const result = service.getNotificationsBrokerTopicsTotals(); - const expected = cold('(a)', { - a: 3 + describe('getNotificationsBrokerSourceTotals', () => { + it('Should return three (3)', () => { + const result = service.getNotificationsBrokerSourceTotals(); + const expected = cold('(a)', { + a: 3 + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('isNotificationsBrokerTopicsLoading', () => { - it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsLoading(); - const expected = cold('(a)', { - a: false + describe('isNotificationsBrokerSourceLoading', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerSourceLoading(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('isNotificationsBrokerTopicsLoaded', () => { - it('Should return TRUE', () => { - const result = service.isNotificationsBrokerTopicsLoaded(); - const expected = cold('(a)', { - a: true + describe('isNotificationsBrokerSourceLoaded', () => { + it('Should return TRUE', () => { + const result = service.isNotificationsBrokerSourceLoaded(); + const expected = cold('(a)', { + a: true + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); - }); - describe('isNotificationsBrokerTopicsProcessing', () => { - it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsProcessing(); - const expected = cold('(a)', { - a: false + describe('isNotificationsBrokerSourceProcessing', () => { + it('Should return FALSE', () => { + const result = service.isNotificationsBrokerSourceProcessing(); + const expected = cold('(a)', { + a: false + }); + expect(result).toBeObservable(expected); }); - expect(result).toBeObservable(expected); }); }); - }); - describe('Testing the topic dispatch methods', () => { - beforeEach(async () => { - init('full'); - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), - ], - providers: [ - provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } - ] - }).compileComponents(); - }); + describe('Testing the Source dispatch methods', () => { + beforeEach(async () => { + init('full'); + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot({ notifications: notificationsReducers } as any), + ], + providers: [ + provideMockStore({ initialState }), + { provide: NotificationsStateService, useValue: service } + ] + }).compileComponents(); + }); - beforeEach(() => { - store = TestBed.get(Store); - service = new NotificationsStateService(store); - serviceAsAny = service; - spyOn(store, 'dispatch'); - }); + beforeEach(() => { + store = TestBed.get(Store); + service = new NotificationsStateService(store); + serviceAsAny = service; + spyOn(store, 'dispatch'); + }); - describe('dispatchRetrieveNotificationsBrokerTopics', () => { - it('Should call store.dispatch', () => { - const elementsPerPage = 3; - const currentPage = 1; - const action = new RetrieveAllTopicsAction(elementsPerPage, currentPage); - service.dispatchRetrieveNotificationsBrokerTopics(elementsPerPage, currentPage); - expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action); + describe('dispatchRetrieveNotificationsBrokerSource', () => { + it('Should call store.dispatch', () => { + const elementsPerPage = 3; + const currentPage = 1; + const action = new RetrieveAllSourceAction(elementsPerPage, currentPage); + service.dispatchRetrieveNotificationsBrokerSource(elementsPerPage, currentPage); + expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action); + }); }); }); - }); + }); + + }); diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index 2e9303c3a35..8af034ea323 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -13,6 +13,7 @@ import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { SearchResult } from '../search/models/search-result.model'; +import { NotificationsBrokerSourceObject } from '../../core/notifications/broker/models/notifications-broker-source.model'; // REST Mock --------------------------------------------------------------------- // ------------------------------------------------------------------------------- @@ -1329,6 +1330,45 @@ export const NotificationsMockDspaceObject: SearchResult = Object. } ); +// Sources +// ------------------------------------------------------------------------------- + +export const notificationsBrokerSourceObjectMorePid: NotificationsBrokerSourceObject = { + type: new ResourceType('nbsource'), + id: 'ENRICH!MORE!PID', + lastEvent: '2020/10/09 10:11 UTC', + totalEvents: 33, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbsources/ENRICH!MORE!PID' + } + } +}; + +export const notificationsBrokerSourceObjectMoreAbstract: NotificationsBrokerSourceObject = { + type: new ResourceType('nbsource'), + id: 'ENRICH!MORE!ABSTRACT', + lastEvent: '2020/09/08 21:14 UTC', + totalEvents: 5, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbsources/ENRICH!MORE!ABSTRACT' + } + } +}; + +export const notificationsBrokerSourceObjectMissingPid: NotificationsBrokerSourceObject = { + type: new ResourceType('nbsource'), + id: 'ENRICH!MISSING!PID', + lastEvent: '2020/10/01 07:36 UTC', + totalEvents: 4, + _links: { + self: { + href: 'https://rest.api/rest/api/integration/nbsources/ENRICH!MISSING!PID' + } + } +}; + // Topics // ------------------------------------------------------------------------------- @@ -1753,10 +1793,28 @@ export function getMockNotificationsStateService(): any { getNotificationsBrokerTopicsCurrentPage: jasmine.createSpy('getNotificationsBrokerTopicsCurrentPage'), getNotificationsBrokerTopicsTotals: jasmine.createSpy('getNotificationsBrokerTopicsTotals'), dispatchRetrieveNotificationsBrokerTopics: jasmine.createSpy('dispatchRetrieveNotificationsBrokerTopics'), + getNotificationsBrokerSource: jasmine.createSpy('getNotificationsBrokerSource'), + isNotificationsBrokerSourceLoading: jasmine.createSpy('isNotificationsBrokerSourceLoading'), + isNotificationsBrokerSourceLoaded: jasmine.createSpy('isNotificationsBrokerSourceLoaded'), + isNotificationsBrokerSourceProcessing: jasmine.createSpy('isNotificationsBrokerSourceProcessing'), + getNotificationsBrokerSourceTotalPages: jasmine.createSpy('getNotificationsBrokerSourceTotalPages'), + getNotificationsBrokerSourceCurrentPage: jasmine.createSpy('getNotificationsBrokerSourceCurrentPage'), + getNotificationsBrokerSourceTotals: jasmine.createSpy('getNotificationsBrokerSourceTotals'), + dispatchRetrieveNotificationsBrokerSource: jasmine.createSpy('dispatchRetrieveNotificationsBrokerSource'), dispatchMarkUserSuggestionsAsVisitedAction: jasmine.createSpy('dispatchMarkUserSuggestionsAsVisitedAction') }); } +/** + * Mock for [[NotificationsBrokerSourceRestService]] + */ + export function getMockNotificationsBrokerSourceRestService(): NotificationsBrokerTopicRestService { + return jasmine.createSpyObj('NotificationsBrokerSourceRestService', { + getSources: jasmine.createSpy('getSources'), + getSource: jasmine.createSpy('getSource'), + }); +} + /** * Mock for [[NotificationsBrokerTopicRestService]] */ From d63bf55458bd9cab6a417107c14325b3add16b85 Mon Sep 17 00:00:00 2001 From: Pratik Rajkotiya Date: Thu, 10 Mar 2022 11:56:39 +0530 Subject: [PATCH 005/196] [CST-5337] change end point. --- config/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yml b/config/config.yml index 3866797f5d3..b5eecd112f0 100644 --- a/config/config.yml +++ b/config/config.yml @@ -1,5 +1,5 @@ rest: - ssl: false - host: localhost:8080 + ssl: true + host: api7.dspace.org port: 443 nameSpace: /server From 6dfeb1a06b0310f3a087fb3c10b7f5d2f10aecc7 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Thu, 17 Mar 2022 16:53:59 +0100 Subject: [PATCH 006/196] [CST-5337] Fixed notifications labels --- src/assets/i18n/en.json5 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 72d22fb5028..873fad622c6 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2716,11 +2716,11 @@ "none.listelement.badge": "Item", - "notifications.broker.title": "Broker Title", + "notifications.broker.title": "Notifications", "notifications.broker.topics.description": "Below you can see all the topics received from the subscriptions to {{source}}.", - "notifications.broker.source.description": "Below you can see all the sources.", + "notifications.broker.source.description": "Below you can see all the notification's sources.", "notifications.broker.topics": "Current Topics", @@ -2740,13 +2740,13 @@ "notifications.broker.noSource": "No sources found.", - "notifications.events.title": "{{source}} Broker Suggestions", + "notifications.events.title": "Broker Suggestions", "notifications.broker.topic.error.service.retrieve": "An error occurred while loading the Notifications Broker topics", "notifications.broker.source.error.service.retrieve": "An error occurred while loading the Notifications Broker source", - "notifications.broker.events.description": "Below the list of all the suggestions, received from {{source}}, for the selected topic.", + "notifications.broker.events.description": "Below the list of all the suggestions for the selected topic.", "notifications.broker.loading": "Loading ...", From d5c1b11d77a67e29e687f94d529764b2bbb410b5 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Wed, 6 Jul 2022 17:04:11 +0200 Subject: [PATCH 007/196] [CST-5337] Replace Notifications broker with Quality assurance --- ...ications-broker-events-page.component.html | 1 - ...tions-broker-events-page.component.spec.ts | 26 --- ...ifications-broker-events-page.component.ts | 9 - ...ications-broker-source-page.component.html | 1 - ...tions-broker-source-page.component.spec.ts | 27 --- ...ifications-broker-source-page.component.ts | 7 - ...ications-broker-topics-page.component.html | 1 - ...tions-broker-topics-page.component.spec.ts | 26 --- ...ifications-broker-topics-page.component.ts | 9 - .../admin-notifications-routing-paths.ts | 6 +- .../admin-notifications-routing.module.ts | 40 ++--- .../admin-notifications.module.ts | 12 +- ...ality-assurance-events-page.component.html | 1 + ...ty-assurance-events-page.component.spec.ts | 26 +++ ...quality-assurance-events-page.component.ts | 9 + ...quality-assurance-events-page.resolver.ts} | 8 +- ...quality-assurance-source-data.reslover.ts} | 18 +- ...assurance-source-page-resolver.service.ts} | 8 +- ...ality-assurance-source-page.component.html | 1 + ...ty-assurance-source-page.component.spec.ts | 27 +++ ...quality-assurance-source-page.component.ts | 7 + ...assurance-topics-page-resolver.service.ts} | 8 +- ...ality-assurance-topics-page.component.html | 1 + ...ty-assurance-topics-page.component.spec.ts | 26 +++ ...quality-assurance-topics-page.component.ts | 9 + src/app/core/core.module.ts | 12 +- ...lity-assurance-event-rest.service.spec.ts} | 56 +++--- .../quality-assurance-event-rest.service.ts} | 60 +++---- ...y-assurance-event-object.resource-type.ts} | 4 +- .../models/quality-assurance-event.model.ts} | 10 +- ...-assurance-source-object.resource-type.ts} | 4 +- .../models/quality-assurance-source.model.ts} | 12 +- ...y-assurance-topic-object.resource-type.ts} | 4 +- .../models/quality-assurance-topic.model.ts} | 14 +- ...ity-assurance-source-rest.service.spec.ts} | 28 +-- .../quality-assurance-source-rest.service.ts} | 42 ++--- ...lity-assurance-topic-rest.service.spec.ts} | 28 +-- .../quality-assurance-topic-rest.service.ts} | 42 ++--- .../notifications-broker-source.reducer.ts | 72 -------- .../notifications-broker-source.service.ts | 55 ------ .../notifications-broker-topics.reducer.ts | 72 -------- .../notifications-state.service.spec.ts | 160 +++++++++--------- .../notifications-state.service.ts | 148 ++++++++-------- .../notifications/notifications.effects.ts | 8 +- src/app/notifications/notifications.module.ts | 34 ++-- .../notifications/notifications.reducer.ts | 12 +- .../quality-assurance-events.component.html} | 6 +- ...uality-assurance-events.component.spec.ts} | 110 ++++++------ .../quality-assurance-events.component.ts} | 118 ++++++------- .../quality-assurance-events.scomponent.scss} | 0 .../project-entry-import-modal.component.html | 0 .../project-entry-import-modal.component.scss | 0 ...oject-entry-import-modal.component.spec.ts | 10 +- .../project-entry-import-modal.component.ts | 18 +- .../quality-assurance-source.actions.ts} | 30 ++-- .../quality-assurance-source.component.html} | 8 +- .../quality-assurance-source.component.scss} | 0 ...uality-assurance-source.component.spec.ts} | 56 +++--- .../quality-assurance-source.component.ts} | 46 ++--- .../quality-assurance-source.effects.ts} | 36 ++-- .../quality-assurance-source.reducer.spec.ts} | 30 ++-- .../quality-assurance-source.reducer.ts | 72 ++++++++ .../quality-assurance-source.service.spec.ts} | 34 ++-- .../quality-assurance-source.service.ts | 55 ++++++ .../quality-assurance-topics.actions.ts} | 30 ++-- .../quality-assurance-topics.component.html} | 2 +- .../quality-assurance-topics.component.scss} | 0 ...uality-assurance-topics.component.spec.ts} | 60 +++---- .../quality-assurance-topics.component.ts} | 54 +++--- .../quality-assurance-topics.effects.ts} | 36 ++-- .../quality-assurance-topics.reducer.spec.ts} | 30 ++-- .../quality-assurance-topics.reducer.ts | 72 ++++++++ .../quality-assurance-topics.service.spec.ts} | 34 ++-- .../quality-assurance-topics.service.ts} | 30 ++-- src/app/notifications/selectors.ts | 104 ++++++------ src/app/shared/mocks/notifications.mock.ts | 114 ++++++------- src/assets/i18n/en.json5 | 10 +- 77 files changed, 1198 insertions(+), 1198 deletions(-) delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.html delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts delete mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.ts rename src/app/admin/admin-notifications/{admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts => admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver.ts} (72%) rename src/app/admin/admin-notifications/{admin-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover.ts => admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts} (61%) rename src/app/admin/admin-notifications/{admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts => admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service.ts} (72%) create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts rename src/app/admin/admin-notifications/{admin-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service.ts => admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service.ts} (72%) create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts rename src/app/core/notifications/{broker/events/notifications-broker-event-rest.service.spec.ts => qa/events/quality-assurance-event-rest.service.spec.ts} (77%) rename src/app/core/notifications/{broker/events/notifications-broker-event-rest.service.ts => qa/events/quality-assurance-event-rest.service.ts} (71%) rename src/app/core/notifications/{broker/models/notifications-broker-topic-object.resource-type.ts => qa/models/quality-assurance-event-object.resource-type.ts} (53%) rename src/app/core/notifications/{broker/models/notifications-broker-event.model.ts => qa/models/quality-assurance-event.model.ts} (90%) rename src/app/core/notifications/{broker/models/notifications-broker-event-object.resource-type.ts => qa/models/quality-assurance-source-object.resource-type.ts} (53%) rename src/app/core/notifications/{broker/models/notifications-broker-source.model.ts => qa/models/quality-assurance-source.model.ts} (69%) rename src/app/core/notifications/{broker/models/notifications-broker-source-object.resource-type.ts => qa/models/quality-assurance-topic-object.resource-type.ts} (53%) rename src/app/core/notifications/{broker/models/notifications-broker-topic.model.ts => qa/models/quality-assurance-topic.model.ts} (68%) rename src/app/core/notifications/{broker/source/notifications-broker-source-rest.service.spec.ts => qa/source/quality-assurance-source-rest.service.spec.ts} (78%) rename src/app/core/notifications/{broker/source/notifications-broker-source-rest.service.ts => qa/source/quality-assurance-source-rest.service.ts} (72%) rename src/app/core/notifications/{broker/topics/notifications-broker-topic-rest.service.spec.ts => qa/topics/quality-assurance-topic-rest.service.spec.ts} (76%) rename src/app/core/notifications/{broker/topics/notifications-broker-topic-rest.service.ts => qa/topics/quality-assurance-topic-rest.service.ts} (73%) delete mode 100644 src/app/notifications/broker/source/notifications-broker-source.reducer.ts delete mode 100644 src/app/notifications/broker/source/notifications-broker-source.service.ts delete mode 100644 src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts rename src/app/notifications/{broker/events/notifications-broker-events.component.html => qa/events/quality-assurance-events.component.html} (98%) rename src/app/notifications/{broker/events/notifications-broker-events.component.spec.ts => qa/events/quality-assurance-events.component.spec.ts} (66%) rename src/app/notifications/{broker/events/notifications-broker-events.component.ts => qa/events/quality-assurance-events.component.ts} (74%) rename src/app/notifications/{broker/events/notifications-broker-events.scomponent.scss => qa/events/quality-assurance-events.scomponent.scss} (100%) rename src/app/notifications/{broker => qa}/project-entry-import-modal/project-entry-import-modal.component.html (100%) rename src/app/notifications/{broker => qa}/project-entry-import-modal/project-entry-import-modal.component.scss (100%) rename src/app/notifications/{broker => qa}/project-entry-import-modal/project-entry-import-modal.component.spec.ts (95%) rename src/app/notifications/{broker => qa}/project-entry-import-modal/project-entry-import-modal.component.ts (94%) rename src/app/notifications/{broker/source/notifications-broker-source.actions.ts => qa/source/quality-assurance-source.actions.ts} (62%) rename src/app/notifications/{broker/source/notifications-broker-source.component.html => qa/source/quality-assurance-source.component.html} (97%) rename src/app/notifications/{broker/source/notifications-broker-source.component.scss => qa/source/quality-assurance-source.component.scss} (100%) rename src/app/notifications/{broker/source/notifications-broker-source.component.spec.ts => qa/source/quality-assurance-source.component.spec.ts} (60%) rename src/app/notifications/{broker/source/notifications-broker-source.component.ts => qa/source/quality-assurance-source.component.ts} (64%) rename src/app/notifications/{broker/source/notifications-broker-source.effects.ts => qa/source/quality-assurance-source.effects.ts} (59%) rename src/app/notifications/{broker/source/notifications-broker-source.reducer.spec.ts => qa/source/quality-assurance-source.reducer.spec.ts} (52%) create mode 100644 src/app/notifications/qa/source/quality-assurance-source.reducer.ts rename src/app/notifications/{broker/source/notifications-broker-source.service.spec.ts => qa/source/quality-assurance-source.service.spec.ts} (56%) create mode 100644 src/app/notifications/qa/source/quality-assurance-source.service.ts rename src/app/notifications/{broker/topics/notifications-broker-topics.actions.ts => qa/topics/quality-assurance-topics.actions.ts} (62%) rename src/app/notifications/{broker/topics/notifications-broker-topics.component.html => qa/topics/quality-assurance-topics.component.html} (97%) rename src/app/notifications/{broker/topics/notifications-broker-topics.component.scss => qa/topics/quality-assurance-topics.component.scss} (100%) rename src/app/notifications/{broker/topics/notifications-broker-topics.component.spec.ts => qa/topics/quality-assurance-topics.component.spec.ts} (59%) rename src/app/notifications/{broker/topics/notifications-broker-topics.component.ts => qa/topics/quality-assurance-topics.component.ts} (63%) rename src/app/notifications/{broker/topics/notifications-broker-topics.effects.ts => qa/topics/quality-assurance-topics.effects.ts} (59%) rename src/app/notifications/{broker/topics/notifications-broker-topics.reducer.spec.ts => qa/topics/quality-assurance-topics.reducer.spec.ts} (51%) create mode 100644 src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts rename src/app/notifications/{broker/topics/notifications-broker-topics.service.spec.ts => qa/topics/quality-assurance-topics.service.spec.ts} (58%) rename src/app/notifications/{broker/topics/notifications-broker-topics.service.ts => qa/topics/quality-assurance-topics.service.ts} (51%) diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html deleted file mode 100644 index 89ef1bfc885..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts deleted file mode 100644 index 57a79e017bf..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { AdminNotificationsBrokerEventsPageComponent } from './admin-notifications-broker-events-page.component'; - -describe('AdminNotificationsBrokerEventsPageComponent', () => { - let component: AdminNotificationsBrokerEventsPageComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AdminNotificationsBrokerEventsPageComponent ], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AdminNotificationsBrokerEventsPageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create AdminNotificationsBrokerEventsPageComponent', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts deleted file mode 100644 index f014b4d133e..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'ds-notifications-broker-events-page', - templateUrl: './admin-notifications-broker-events-page.component.html' -}) -export class AdminNotificationsBrokerEventsPageComponent { - -} diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.html b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.html deleted file mode 100644 index 57f635d5da3..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts deleted file mode 100644 index f6d3eb20fe5..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AdminNotificationsBrokerSourcePageComponent } from './admin-notifications-broker-source-page.component'; - -describe('AdminNotificationsBrokerSourcePageComponent', () => { - let component: AdminNotificationsBrokerSourcePageComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ AdminNotificationsBrokerSourcePageComponent ], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AdminNotificationsBrokerSourcePageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create AdminNotificationsBrokerSourcePageComponent', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.ts deleted file mode 100644 index 1ec08948270..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'ds-admin-notifications-broker-source-page-component', - templateUrl: './admin-notifications-broker-source-page.component.html', -}) -export class AdminNotificationsBrokerSourcePageComponent {} diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html deleted file mode 100644 index dbdae2e6b9a..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts deleted file mode 100644 index c21e0ce73ba..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { AdminNotificationsBrokerTopicsPageComponent } from './admin-notifications-broker-topics-page.component'; - -describe('AdminNotificationsBrokerTopicsPageComponent', () => { - let component: AdminNotificationsBrokerTopicsPageComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AdminNotificationsBrokerTopicsPageComponent ], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AdminNotificationsBrokerTopicsPageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create AdminNotificationsBrokerTopicsPageComponent', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts b/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts deleted file mode 100644 index 4f60ffd3fdd..00000000000 --- a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'ds-notification-broker-page', - templateUrl: './admin-notifications-broker-topics-page.component.html' -}) -export class AdminNotificationsBrokerTopicsPageComponent { - -} diff --git a/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts index 469cbb980ff..2820a9a2c7b 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing-paths.ts @@ -1,8 +1,8 @@ import { URLCombiner } from '../../core/url-combiner/url-combiner'; import { getNotificationsModuleRoute } from '../admin-routing-paths'; -export const NOTIFICATIONS_EDIT_PATH = 'notifications-broker'; +export const QUALITY_ASSURANCE_EDIT_PATH = 'quality-assurance'; -export function getNotificationsBrokerbrokerRoute(id: string) { - return new URLCombiner(getNotificationsModuleRoute(), NOTIFICATIONS_EDIT_PATH, id).toString(); +export function getQualityAssuranceRoute(id: string) { + return new URLCombiner(getNotificationsModuleRoute(), QUALITY_ASSURANCE_EDIT_PATH, id).toString(); } diff --git a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts index 4e5997e2035..c9cca6d8d80 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -4,26 +4,26 @@ import { RouterModule } from '@angular/router'; import { AuthenticatedGuard } from '../../core/auth/authenticated.guard'; import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver'; import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service'; -import { NOTIFICATIONS_EDIT_PATH } from './admin-notifications-routing-paths'; -import { AdminNotificationsBrokerTopicsPageComponent } from './admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component'; -import { AdminNotificationsBrokerEventsPageComponent } from './admin-notifications-broker-events-page/admin-notifications-broker-events-page.component'; -import { AdminNotificationsBrokerTopicsPageResolver } from './admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service'; -import { AdminNotificationsBrokerEventsPageResolver } from './admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver'; -import { AdminNotificationsBrokerSourcePageComponent } from './admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component'; -import { AdminNotificationsBrokerSourcePageResolver } from './admin-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service'; -import { SourceDataResolver } from './admin-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover'; +import { QUALITY_ASSURANCE_EDIT_PATH } from './admin-notifications-routing-paths'; +import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component'; +import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.component'; +import { AdminQualityAssuranceTopicsPageResolver } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service'; +import { AdminQualityAssuranceEventsPageResolver } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver'; +import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component'; +import { AdminQualityAssuranceSourcePageResolver } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service'; +import { SourceDataResolver } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover'; @NgModule({ imports: [ RouterModule.forChild([ { canActivate: [ AuthenticatedGuard ], - path: `${NOTIFICATIONS_EDIT_PATH}/:sourceId`, - component: AdminNotificationsBrokerTopicsPageComponent, + path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId`, + component: AdminQualityAssuranceTopicsPageComponent, pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerTopicsParams: AdminNotificationsBrokerTopicsPageResolver + openaireBrokerTopicsParams: AdminQualityAssuranceTopicsPageResolver }, data: { title: 'admin.notifications.broker.page.title', @@ -33,12 +33,12 @@ import { SourceDataResolver } from './admin-notifications-broker-source-page-com }, { canActivate: [ AuthenticatedGuard ], - path: `${NOTIFICATIONS_EDIT_PATH}`, - component: AdminNotificationsBrokerSourcePageComponent, + path: `${QUALITY_ASSURANCE_EDIT_PATH}`, + component: AdminQualityAssuranceSourcePageComponent, pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerSourceParams: AdminNotificationsBrokerSourcePageResolver, + openaireBrokerSourceParams: AdminQualityAssuranceSourcePageResolver, sourceData: SourceDataResolver }, data: { @@ -49,12 +49,12 @@ import { SourceDataResolver } from './admin-notifications-broker-source-page-com }, { canActivate: [ AuthenticatedGuard ], - path: `${NOTIFICATIONS_EDIT_PATH}/:sourceId/:topicId`, - component: AdminNotificationsBrokerEventsPageComponent, + path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId/:topicId`, + component: AdminQualityAssuranceEventsPageComponent, pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerEventsParams: AdminNotificationsBrokerEventsPageResolver + openaireBrokerEventsParams: AdminQualityAssuranceEventsPageResolver }, data: { title: 'admin.notifications.event.page.title', @@ -68,9 +68,9 @@ import { SourceDataResolver } from './admin-notifications-broker-source-page-com I18nBreadcrumbResolver, I18nBreadcrumbsService, SourceDataResolver, - AdminNotificationsBrokerTopicsPageResolver, - AdminNotificationsBrokerEventsPageResolver, - AdminNotificationsBrokerSourcePageResolver + AdminQualityAssuranceTopicsPageResolver, + AdminQualityAssuranceEventsPageResolver, + AdminQualityAssuranceSourcePageResolver ] }) /** diff --git a/src/app/admin/admin-notifications/admin-notifications.module.ts b/src/app/admin/admin-notifications/admin-notifications.module.ts index 6351498dc57..ba0c6eee58a 100644 --- a/src/app/admin/admin-notifications/admin-notifications.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications.module.ts @@ -3,10 +3,10 @@ import { NgModule } from '@angular/core'; import { CoreModule } from '../../core/core.module'; import { SharedModule } from '../../shared/shared.module'; import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module'; -import { AdminNotificationsBrokerTopicsPageComponent } from './admin-notifications-broker-topics-page/admin-notifications-broker-topics-page.component'; -import { AdminNotificationsBrokerEventsPageComponent } from './admin-notifications-broker-events-page/admin-notifications-broker-events-page.component'; +import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component'; +import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.component'; import { NotificationsModule } from '../../notifications/notifications.module'; -import { AdminNotificationsBrokerSourcePageComponent } from './admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component'; +import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component'; @NgModule({ imports: [ @@ -17,9 +17,9 @@ import { AdminNotificationsBrokerSourcePageComponent } from './admin-notificatio NotificationsModule ], declarations: [ - AdminNotificationsBrokerTopicsPageComponent, - AdminNotificationsBrokerEventsPageComponent, - AdminNotificationsBrokerSourcePageComponent + AdminQualityAssuranceTopicsPageComponent, + AdminQualityAssuranceEventsPageComponent, + AdminQualityAssuranceSourcePageComponent ], entryComponents: [] }) diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.html b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.html new file mode 100644 index 00000000000..315209d3429 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.html @@ -0,0 +1 @@ + diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.spec.ts b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.spec.ts new file mode 100644 index 00000000000..b9520782154 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.spec.ts @@ -0,0 +1,26 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page.component'; + +describe('AdminQualityAssuranceEventsPageComponent', () => { + let component: AdminQualityAssuranceEventsPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AdminQualityAssuranceEventsPageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminQualityAssuranceEventsPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create AdminQualityAssuranceEventsPageComponent', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.ts new file mode 100644 index 00000000000..a1e15d5bdb7 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-quality-assurance-events-page', + templateUrl: './admin-quality-assurance-events-page.component.html' +}) +export class AdminQualityAssuranceEventsPageComponent { + +} diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver.ts similarity index 72% rename from src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts rename to src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver.ts index dcf530858cc..3139355629f 100644 --- a/src/app/admin/admin-notifications/admin-notifications-broker-events-page/admin-notifications-broker-events-page.resolver.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver.ts @@ -4,7 +4,7 @@ import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/r /** * Interface for the route parameters. */ -export interface AdminNotificationsBrokerEventsPageParams { +export interface AdminQualityAssuranceEventsPageParams { pageId?: string; pageSize?: number; currentPage?: number; @@ -14,15 +14,15 @@ export interface AdminNotificationsBrokerEventsPageParams { * This class represents a resolver that retrieve the route data before the route is activated. */ @Injectable() -export class AdminNotificationsBrokerEventsPageResolver implements Resolve { +export class AdminQualityAssuranceEventsPageResolver implements Resolve { /** * Method for resolving the parameters in the current route. * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot * @param {RouterStateSnapshot} state The current RouterStateSnapshot - * @returns AdminNotificationsBrokerEventsPageParams Emits the route parameters + * @returns AdminQualityAssuranceEventsPageParams Emits the route parameters */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsBrokerEventsPageParams { + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminQualityAssuranceEventsPageParams { return { pageId: route.queryParams.pageId, pageSize: parseInt(route.queryParams.pageSize, 10), diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts similarity index 61% rename from src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover.ts rename to src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts index 114f5f7df12..6201e0a7435 100644 --- a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts @@ -3,30 +3,30 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot, Router } from '@a import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { PaginatedList } from '../../../core/data/paginated-list.model'; -import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; -import { NotificationsBrokerSourceService } from '../../../notifications/broker/source/notifications-broker-source.service'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceService } from '../../../notifications/qa/source/quality-assurance-source.service'; /** * This class represents a resolver that retrieve the route data before the route is activated. */ @Injectable() -export class SourceDataResolver implements Resolve> { +export class SourceDataResolver implements Resolve> { /** * Initialize the effect class variables. - * @param {NotificationsBrokerSourceService} notificationsBrokerSourceService + * @param {QualityAssuranceSourceService} qualityAssuranceSourceService */ constructor( - private notificationsBrokerSourceService: NotificationsBrokerSourceService, + private qualityAssuranceSourceService: QualityAssuranceSourceService, private router: Router ) { } /** * Method for resolving the parameters in the current route. * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot * @param {RouterStateSnapshot} state The current RouterStateSnapshot - * @returns Observable + * @returns Observable */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.notificationsBrokerSourceService.getSources(5,0).pipe( - map((sources: PaginatedList) => { + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.qualityAssuranceSourceService.getSources(5,0).pipe( + map((sources: PaginatedList) => { if (sources.page.length === 1) { this.router.navigate([this.getResolvedUrl(route) + '/' + sources.page[0].id]); } diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service.ts similarity index 72% rename from src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts rename to src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service.ts index d4fd354d92b..ac9bdb48d66 100644 --- a/src/app/admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service.ts @@ -4,7 +4,7 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/r /** * Interface for the route parameters. */ -export interface AdminNotificationsBrokerTopicsPageParams { +export interface AdminQualityAssuranceSourcePageParams { pageId?: string; pageSize?: number; currentPage?: number; @@ -14,15 +14,15 @@ export interface AdminNotificationsBrokerTopicsPageParams { * This class represents a resolver that retrieve the route data before the route is activated. */ @Injectable() -export class AdminNotificationsBrokerTopicsPageResolver implements Resolve { +export class AdminQualityAssuranceSourcePageResolver implements Resolve { /** * Method for resolving the parameters in the current route. * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot * @param {RouterStateSnapshot} state The current RouterStateSnapshot - * @returns AdminNotificationsBrokerTopicsPageParams Emits the route parameters + * @returns AdminQualityAssuranceSourcePageParams Emits the route parameters */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsBrokerTopicsPageParams { + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminQualityAssuranceSourcePageParams { return { pageId: route.queryParams.pageId, pageSize: parseInt(route.queryParams.pageSize, 10), diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.html b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.html new file mode 100644 index 00000000000..709103cf3d2 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.html @@ -0,0 +1 @@ + diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.spec.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.spec.ts new file mode 100644 index 00000000000..451c911c4ce --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.spec.ts @@ -0,0 +1,27 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page.component'; + +describe('AdminQualityAssuranceSourcePageComponent', () => { + let component: AdminQualityAssuranceSourcePageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AdminQualityAssuranceSourcePageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminQualityAssuranceSourcePageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create AdminQualityAssuranceSourcePageComponent', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts new file mode 100644 index 00000000000..624e71f281e --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts @@ -0,0 +1,7 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'ds-admin-quality-assurance-source-page-component', + templateUrl: './admin-quality-assurance-source-page.component.html', +}) +export class AdminQualityAssuranceSourcePageComponent {} diff --git a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service.ts b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service.ts similarity index 72% rename from src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service.ts rename to src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service.ts index 8450e20c3ce..47500d18783 100644 --- a/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service.ts @@ -4,7 +4,7 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/r /** * Interface for the route parameters. */ -export interface AdminNotificationsBrokerSourcePageParams { +export interface AdminQualityAssuranceTopicsPageParams { pageId?: string; pageSize?: number; currentPage?: number; @@ -14,15 +14,15 @@ export interface AdminNotificationsBrokerSourcePageParams { * This class represents a resolver that retrieve the route data before the route is activated. */ @Injectable() -export class AdminNotificationsBrokerSourcePageResolver implements Resolve { +export class AdminQualityAssuranceTopicsPageResolver implements Resolve { /** * Method for resolving the parameters in the current route. * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot * @param {RouterStateSnapshot} state The current RouterStateSnapshot - * @returns AdminNotificationsBrokerSourcePageParams Emits the route parameters + * @returns AdminQualityAssuranceTopicsPageParams Emits the route parameters */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsBrokerSourcePageParams { + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminQualityAssuranceTopicsPageParams { return { pageId: route.queryParams.pageId, pageSize: parseInt(route.queryParams.pageSize, 10), diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.html b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.html new file mode 100644 index 00000000000..fc905ad7240 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.html @@ -0,0 +1 @@ + diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.spec.ts b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.spec.ts new file mode 100644 index 00000000000..a32f60f017a --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.spec.ts @@ -0,0 +1,26 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page.component'; + +describe('AdminQualityAssuranceTopicsPageComponent', () => { + let component: AdminQualityAssuranceTopicsPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AdminQualityAssuranceTopicsPageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminQualityAssuranceTopicsPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create AdminQualityAssuranceTopicsPageComponent', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts new file mode 100644 index 00000000000..53f951ba541 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-notification-broker-page', + templateUrl: './admin-quality-assurance-topics-page.component.html' +}) +export class AdminQualityAssuranceTopicsPageComponent { + +} diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index a2ee9abc2d8..fcc8160f88b 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -167,9 +167,9 @@ import { SequenceService } from './shared/sequence.service'; import { CoreState } from './core-state.model'; import { GroupDataService } from './eperson/group-data.service'; import { SubmissionAccessesModel } from './config/models/config-submission-accesses.model'; -import { NotificationsBrokerTopicObject } from './notifications/broker/models/notifications-broker-topic.model'; -import { NotificationsBrokerEventObject } from './notifications/broker/models/notifications-broker-event.model'; -import { NotificationsBrokerSourceObject } from './notifications/broker/models/notifications-broker-source.model'; +import { QualityAssuranceTopicObject } from './notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceEventObject } from './notifications/qa/models/quality-assurance-event.model'; +import { QualityAssuranceSourceObject } from './notifications/qa/models/quality-assurance-source.model'; import { AccessStatusObject } from '../shared/object-list/access-status-badge/access-status.model'; import { AccessStatusDataService } from './data/access-status-data.service'; import { LinkHeadService } from './services/link-head.service'; @@ -369,12 +369,12 @@ export const models = ShortLivedToken, Registration, UsageReport, - NotificationsBrokerTopicObject, - NotificationsBrokerEventObject, + QualityAssuranceTopicObject, + QualityAssuranceEventObject, Root, SearchConfig, SubmissionAccessesModel, - NotificationsBrokerSourceObject, + QualityAssuranceSourceObject, AccessStatusObject, ResearcherProfile, OrcidQueue, diff --git a/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.spec.ts b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts similarity index 77% rename from src/app/core/notifications/broker/events/notifications-broker-event-rest.service.spec.ts rename to src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts index 16d55479ae0..556665adbd7 100644 --- a/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.spec.ts +++ b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts @@ -6,8 +6,6 @@ import { cold, getTestScheduler } from 'jasmine-marbles'; import { RequestService } from '../../../data/request.service'; import { buildPaginatedList } from '../../../data/paginated-list.model'; -import { RequestEntry } from '../../../data/request.reducer'; -import { FindListOptions } from '../../../data/request.models'; import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../../../cache/object-cache.service'; import { RestResponse } from '../../../cache/response.models'; @@ -15,17 +13,19 @@ import { PageInfo } from '../../../shared/page-info.model'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; -import { NotificationsBrokerEventRestService } from './notifications-broker-event-rest.service'; +import { QualityAssuranceEventRestService } from './quality-assurance-event-rest.service'; import { - notificationsBrokerEventObjectMissingPid, - notificationsBrokerEventObjectMissingPid2, - notificationsBrokerEventObjectMissingProjectFound + qualityAssuranceEventObjectMissingPid, + qualityAssuranceEventObjectMissingPid2, + qualityAssuranceEventObjectMissingProjectFound } from '../../../../shared/mocks/notifications.mock'; import { ReplaceOperation } from 'fast-json-patch'; +import {RequestEntry} from '../../../data/request-entry.model'; +import {FindListOptions} from '../../../data/find-list-options.model'; -describe('NotificationsBrokerEventRestService', () => { +describe('QualityAssuranceEventRestService', () => { let scheduler: TestScheduler; - let service: NotificationsBrokerEventRestService; + let service: QualityAssuranceEventRestService; let serviceASAny: any; let responseCacheEntry: RequestEntry; let responseCacheEntryB: RequestEntry; @@ -43,10 +43,10 @@ describe('NotificationsBrokerEventRestService', () => { const topic = 'ENRICH!MORE!PID'; const pageInfo = new PageInfo(); - const array = [ notificationsBrokerEventObjectMissingPid, notificationsBrokerEventObjectMissingPid2 ]; + const array = [ qualityAssuranceEventObjectMissingPid, qualityAssuranceEventObjectMissingPid2 ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerEventObjectRD = createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingPid); - const brokerEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingProjectFound); + const brokerEventObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingPid); + const brokerEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingProjectFound); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); const status = 'ACCEPTED'; @@ -99,7 +99,7 @@ describe('NotificationsBrokerEventRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new NotificationsBrokerEventRestService( + service = new QualityAssuranceEventRestService( requestService, rdbService, objectCache, @@ -138,7 +138,7 @@ describe('NotificationsBrokerEventRestService', () => { expect(serviceASAny.dataService.searchBy).toHaveBeenCalledWith('findByTopic', options, true, true); }); - it('should return a RemoteData> for the object with the given Topic', () => { + it('should return a RemoteData> for the object with the given Topic', () => { const result = service.getEventsByTopic(topic); const expected = cold('(a)', { a: paginatedListRD @@ -155,15 +155,15 @@ describe('NotificationsBrokerEventRestService', () => { }); it('should proxy the call to dataservice.findById', () => { - service.getEvent(notificationsBrokerEventObjectMissingPid.id).subscribe( + service.getEvent(qualityAssuranceEventObjectMissingPid.id).subscribe( (res) => { - expect(serviceASAny.dataService.findById).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingPid.id, true, true); + expect(serviceASAny.dataService.findById).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingPid.id, true, true); } ); }); - it('should return a RemoteData for the object with the given URL', () => { - const result = service.getEvent(notificationsBrokerEventObjectMissingPid.id); + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getEvent(qualityAssuranceEventObjectMissingPid.id); const expected = cold('(a)', { a: brokerEventObjectRD }); @@ -179,17 +179,17 @@ describe('NotificationsBrokerEventRestService', () => { }); it('should proxy the call to dataservice.patch', () => { - service.patchEvent(status, notificationsBrokerEventObjectMissingPid).subscribe( + service.patchEvent(status, qualityAssuranceEventObjectMissingPid).subscribe( (res) => { - expect(serviceASAny.dataService.patch).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingPid, operation); + expect(serviceASAny.dataService.patch).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingPid, operation); } ); }); it('should return a RemoteData with HTTP 200', () => { - const result = service.patchEvent(status, notificationsBrokerEventObjectMissingPid); + const result = service.patchEvent(status, qualityAssuranceEventObjectMissingPid); const expected = cold('(a|)', { - a: createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingPid) + a: createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingPid) }); expect(result).toBeObservable(expected); }); @@ -203,17 +203,17 @@ describe('NotificationsBrokerEventRestService', () => { }); it('should proxy the call to dataservice.postOnRelated', () => { - service.boundProject(notificationsBrokerEventObjectMissingProjectFound.id, requestUUID).subscribe( + service.boundProject(qualityAssuranceEventObjectMissingProjectFound.id, requestUUID).subscribe( (res) => { - expect(serviceASAny.dataService.postOnRelated).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingProjectFound.id, requestUUID); + expect(serviceASAny.dataService.postOnRelated).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingProjectFound.id, requestUUID); } ); }); it('should return a RestResponse with HTTP 201', () => { - const result = service.boundProject(notificationsBrokerEventObjectMissingProjectFound.id, requestUUID); + const result = service.boundProject(qualityAssuranceEventObjectMissingProjectFound.id, requestUUID); const expected = cold('(a|)', { - a: createSuccessfulRemoteDataObject(notificationsBrokerEventObjectMissingProjectFound) + a: createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingProjectFound) }); expect(result).toBeObservable(expected); }); @@ -227,15 +227,15 @@ describe('NotificationsBrokerEventRestService', () => { }); it('should proxy the call to dataservice.deleteOnRelated', () => { - service.removeProject(notificationsBrokerEventObjectMissingProjectFound.id).subscribe( + service.removeProject(qualityAssuranceEventObjectMissingProjectFound.id).subscribe( (res) => { - expect(serviceASAny.dataService.deleteOnRelated).toHaveBeenCalledWith(notificationsBrokerEventObjectMissingProjectFound.id); + expect(serviceASAny.dataService.deleteOnRelated).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingProjectFound.id); } ); }); it('should return a RestResponse with HTTP 204', () => { - const result = service.removeProject(notificationsBrokerEventObjectMissingProjectFound.id); + const result = service.removeProject(qualityAssuranceEventObjectMissingProjectFound.id); const expected = cold('(a|)', { a: createSuccessfulRemoteDataObject({}) }); diff --git a/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.ts b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts similarity index 71% rename from src/app/core/notifications/broker/events/notifications-broker-event-rest.service.ts rename to src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts index 7f4761009d9..59f6c31e057 100644 --- a/src/app/core/notifications/broker/events/notifications-broker-event-rest.service.ts +++ b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts @@ -4,7 +4,6 @@ import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; -import { CoreState } from '../../../core.reducers'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; @@ -12,24 +11,25 @@ import { RestResponse } from '../../../cache/response.models'; import { ObjectCacheService } from '../../../cache/object-cache.service'; import { dataService } from '../../../cache/builders/build-decorators'; import { RequestService } from '../../../data/request.service'; -import { FindListOptions } from '../../../data/request.models'; import { DataService } from '../../../data/data.service'; import { ChangeAnalyzer } from '../../../data/change-analyzer'; import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; import { RemoteData } from '../../../data/remote-data'; -import { NotificationsBrokerEventObject } from '../models/notifications-broker-event.model'; -import { NOTIFICATIONS_BROKER_EVENT_OBJECT } from '../models/notifications-broker-event-object.resource-type'; +import { QualityAssuranceEventObject } from '../models/quality-assurance-event.model'; +import { QUALITY_ASSURANCE_EVENT_OBJECT } from '../models/quality-assurance-event-object.resource-type'; import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model'; import { PaginatedList } from '../../../data/paginated-list.model'; import { ReplaceOperation } from 'fast-json-patch'; import { NoContent } from '../../../shared/NoContent.model'; +import {CoreState} from '../../../core-state.model'; +import {FindListOptions} from '../../../data/find-list-options.model'; /* tslint:disable:max-classes-per-file */ /** * A private DataService implementation to delegate specific methods to. */ -class DataServiceImpl extends DataService { +class DataServiceImpl extends DataService { /** * The REST endpoint. */ @@ -44,7 +44,7 @@ class DataServiceImpl extends DataService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer} comparator + * @param {ChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -54,17 +54,17 @@ class DataServiceImpl extends DataService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer) { + protected comparator: ChangeAnalyzer) { super(); } } /** - * The service handling all Notifications Broker topic REST requests. + * The service handling all Quality Assurance topic REST requests. */ @Injectable() -@dataService(NOTIFICATIONS_BROKER_EVENT_OBJECT) -export class NotificationsBrokerEventRestService { +@dataService(QUALITY_ASSURANCE_EVENT_OBJECT) +export class QualityAssuranceEventRestService { /** * A private DataService implementation to delegate specific methods to. */ @@ -78,7 +78,7 @@ export class NotificationsBrokerEventRestService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {DefaultChangeAnalyzer} comparator + * @param {DefaultChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -87,23 +87,23 @@ export class NotificationsBrokerEventRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer) { + protected comparator: DefaultChangeAnalyzer) { this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } /** - * Return the list of Notifications Broker events by topic. + * Return the list of Quality Assurance events by topic. * * @param topic - * The Notifications Broker topic + * The Quality Assurance topic * @param options * Find list options object. * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable>> - * The list of Notifications Broker events. + * @return Observable>> + * The list of Quality Assurance events. */ - public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { + public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { options.searchParams = [ { fieldName: 'topic', @@ -121,32 +121,32 @@ export class NotificationsBrokerEventRestService { } /** - * Return a single Notifications Broker event. + * Return a single Quality Assurance event. * * @param id - * The Notifications Broker event id + * The Quality Assurance event id * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved - * @return Observable> - * The Notifications Broker event. + * @return Observable> + * The Quality Assurance event. */ - public getEvent(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { + public getEvent(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { return this.dataService.findById(id, true, true, ...linksToFollow); } /** - * Save the new status of a Notifications Broker event. + * Save the new status of a Quality Assurance event. * * @param status * The new status - * @param dso NotificationsBrokerEventObject + * @param dso QualityAssuranceEventObject * The event item * @param reason * The optional reason (not used for now; for future implementation) * @return Observable * The REST response. */ - public patchEvent(status, dso, reason?: string): Observable> { + public patchEvent(status, dso, reason?: string): Observable> { const operation: ReplaceOperation[] = [ { path: '/status', @@ -158,24 +158,24 @@ export class NotificationsBrokerEventRestService { } /** - * Bound a project to a Notifications Broker event publication. + * Bound a project to a Quality Assurance event publication. * * @param itemId - * The Id of the Notifications Broker event + * The Id of the Quality Assurance event * @param projectId * The project Id to bound * @return Observable * The REST response. */ - public boundProject(itemId: string, projectId: string): Observable> { + public boundProject(itemId: string, projectId: string): Observable> { return this.dataService.postOnRelated(itemId, projectId); } /** - * Remove a project from a Notifications Broker event publication. + * Remove a project from a Quality Assurance event publication. * * @param itemId - * The Id of the Notifications Broker event + * The Id of the Quality Assurance event * @return Observable * The REST response. */ diff --git a/src/app/core/notifications/broker/models/notifications-broker-topic-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts similarity index 53% rename from src/app/core/notifications/broker/models/notifications-broker-topic-object.resource-type.ts rename to src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts index e7012eee4fe..33c7b338edb 100644 --- a/src/app/core/notifications/broker/models/notifications-broker-topic-object.resource-type.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts @@ -1,9 +1,9 @@ import { ResourceType } from '../../../shared/resource-type'; /** - * The resource type for the Notifications Broker topic + * The resource type for the Quality Assurance event * * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const NOTIFICATIONS_BROKER_TOPIC_OBJECT = new ResourceType('nbtopic'); +export const QUALITY_ASSURANCE_EVENT_OBJECT = new ResourceType('nbevent'); diff --git a/src/app/core/notifications/broker/models/notifications-broker-event.model.ts b/src/app/core/notifications/qa/models/quality-assurance-event.model.ts similarity index 90% rename from src/app/core/notifications/broker/models/notifications-broker-event.model.ts rename to src/app/core/notifications/qa/models/quality-assurance-event.model.ts index 4df326f325b..15fbae7821d 100644 --- a/src/app/core/notifications/broker/models/notifications-broker-event.model.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-event.model.ts @@ -1,7 +1,6 @@ import { Observable } from 'rxjs'; import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; -import { CacheableObject } from '../../../cache/object-cache.reducer'; -import { NOTIFICATIONS_BROKER_EVENT_OBJECT } from './notifications-broker-event-object.resource-type'; +import { QUALITY_ASSURANCE_EVENT_OBJECT } from './quality-assurance-event-object.resource-type'; import { excludeFromEquals } from '../../../utilities/equals.decorators'; import { ResourceType } from '../../../shared/resource-type'; import { HALLink } from '../../../shared/hal-link.model'; @@ -9,11 +8,12 @@ import { Item } from '../../../shared/item.model'; import { ITEM } from '../../../shared/item.resource-type'; import { link, typedObject } from '../../../cache/builders/build-decorators'; import { RemoteData } from '../../../data/remote-data'; +import {CacheableObject} from '../../../cache/cacheable-object.model'; /** * The interface representing the Notifications Broker event message */ -export interface NotificationsBrokerEventMessageObject { +export interface QualityAssuranceEventMessageObject { } @@ -77,11 +77,11 @@ export interface OpenaireBrokerEventMessageObject { * The interface representing the Notifications Broker event model */ @typedObject -export class NotificationsBrokerEventObject implements CacheableObject { +export class QualityAssuranceEventObject implements CacheableObject { /** * A string representing the kind of object, e.g. community, item, … */ - static type = NOTIFICATIONS_BROKER_EVENT_OBJECT; + static type = QUALITY_ASSURANCE_EVENT_OBJECT; /** * The Notifications Broker event uuid inside DSpace diff --git a/src/app/core/notifications/broker/models/notifications-broker-event-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts similarity index 53% rename from src/app/core/notifications/broker/models/notifications-broker-event-object.resource-type.ts rename to src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts index 2493ae02d1e..585216c34f8 100644 --- a/src/app/core/notifications/broker/models/notifications-broker-event-object.resource-type.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts @@ -1,9 +1,9 @@ import { ResourceType } from '../../../shared/resource-type'; /** - * The resource type for the Notifications Broker event + * The resource type for the Quality Assurance source * * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const NOTIFICATIONS_BROKER_EVENT_OBJECT = new ResourceType('nbevent'); +export const QUALITY_ASSURANCE_SOURCE_OBJECT = new ResourceType('nbsource'); diff --git a/src/app/core/notifications/broker/models/notifications-broker-source.model.ts b/src/app/core/notifications/qa/models/quality-assurance-source.model.ts similarity index 69% rename from src/app/core/notifications/broker/models/notifications-broker-source.model.ts rename to src/app/core/notifications/qa/models/quality-assurance-source.model.ts index 3f18c3affb0..f59467384ff 100644 --- a/src/app/core/notifications/broker/models/notifications-broker-source.model.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-source.model.ts @@ -1,24 +1,24 @@ import { autoserialize, deserialize } from 'cerialize'; -import { CacheableObject } from '../../../cache/object-cache.reducer'; import { excludeFromEquals } from '../../../utilities/equals.decorators'; import { ResourceType } from '../../../shared/resource-type'; import { HALLink } from '../../../shared/hal-link.model'; import { typedObject } from '../../../cache/builders/build-decorators'; -import { NOTIFICATIONS_BROKER_SOURCE_OBJECT } from './notifications-broker-source-object.resource-type'; +import { QUALITY_ASSURANCE_SOURCE_OBJECT } from './quality-assurance-source-object.resource-type'; +import {CacheableObject} from '../../../cache/cacheable-object.model'; /** - * The interface representing the Notifications Broker source model + * The interface representing the Quality Assurance source model */ @typedObject -export class NotificationsBrokerSourceObject implements CacheableObject { +export class QualityAssuranceSourceObject implements CacheableObject { /** * A string representing the kind of object, e.g. community, item, … */ - static type = NOTIFICATIONS_BROKER_SOURCE_OBJECT; + static type = QUALITY_ASSURANCE_SOURCE_OBJECT; /** - * The Notifications Broker source id + * The Quality Assurance source id */ @autoserialize id: string; diff --git a/src/app/core/notifications/broker/models/notifications-broker-source-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts similarity index 53% rename from src/app/core/notifications/broker/models/notifications-broker-source-object.resource-type.ts rename to src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts index e3d10dc5abf..8cd5bec61bc 100644 --- a/src/app/core/notifications/broker/models/notifications-broker-source-object.resource-type.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts @@ -1,9 +1,9 @@ import { ResourceType } from '../../../shared/resource-type'; /** - * The resource type for the Notifications Broker source + * The resource type for the Quality Assurance topic * * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const NOTIFICATIONS_BROKER_SOURCE_OBJECT = new ResourceType('nbsource'); +export const QUALITY_ASSURANCE_TOPIC_OBJECT = new ResourceType('nbtopic'); diff --git a/src/app/core/notifications/broker/models/notifications-broker-topic.model.ts b/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts similarity index 68% rename from src/app/core/notifications/broker/models/notifications-broker-topic.model.ts rename to src/app/core/notifications/qa/models/quality-assurance-topic.model.ts index d1f2e6ff502..529980e5f7c 100644 --- a/src/app/core/notifications/broker/models/notifications-broker-topic.model.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts @@ -1,30 +1,30 @@ import { autoserialize, deserialize } from 'cerialize'; -import { CacheableObject } from '../../../cache/object-cache.reducer'; -import { NOTIFICATIONS_BROKER_TOPIC_OBJECT } from './notifications-broker-topic-object.resource-type'; +import { QUALITY_ASSURANCE_TOPIC_OBJECT } from './quality-assurance-topic-object.resource-type'; import { excludeFromEquals } from '../../../utilities/equals.decorators'; import { ResourceType } from '../../../shared/resource-type'; import { HALLink } from '../../../shared/hal-link.model'; import { typedObject } from '../../../cache/builders/build-decorators'; +import {CacheableObject} from '../../../cache/cacheable-object.model'; /** - * The interface representing the Notifications Broker topic model + * The interface representing the Quality Assurance topic model */ @typedObject -export class NotificationsBrokerTopicObject implements CacheableObject { +export class QualityAssuranceTopicObject implements CacheableObject { /** * A string representing the kind of object, e.g. community, item, … */ - static type = NOTIFICATIONS_BROKER_TOPIC_OBJECT; + static type = QUALITY_ASSURANCE_TOPIC_OBJECT; /** - * The Notifications Broker topic id + * The Quality Assurance topic id */ @autoserialize id: string; /** - * The Notifications Broker topic name to display + * The Quality Assurance topic name to display */ @autoserialize name: string; diff --git a/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.spec.ts b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts similarity index 78% rename from src/app/core/notifications/broker/source/notifications-broker-source-rest.service.spec.ts rename to src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts index 984f44bd15d..dff604b0c40 100644 --- a/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.spec.ts +++ b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts @@ -6,7 +6,6 @@ import { cold, getTestScheduler } from 'jasmine-marbles'; import { RequestService } from '../../../data/request.service'; import { buildPaginatedList } from '../../../data/paginated-list.model'; -import { RequestEntry } from '../../../data/request.reducer'; import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../../../cache/object-cache.service'; import { RestResponse } from '../../../cache/response.models'; @@ -14,15 +13,16 @@ import { PageInfo } from '../../../shared/page-info.model'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; -import { NotificationsBrokerSourceRestService } from './notifications-broker-source-rest.service'; import { - notificationsBrokerSourceObjectMoreAbstract, - notificationsBrokerSourceObjectMorePid + qualityAssuranceSourceObjectMoreAbstract, + qualityAssuranceSourceObjectMorePid } from '../../../../shared/mocks/notifications.mock'; +import {RequestEntry} from '../../../data/request-entry.model'; +import {QualityAssuranceSourceRestService} from './quality-assurance-source-rest.service'; -describe('NotificationsBrokerSourceRestService', () => { +describe('QualityAssuranceSourceRestService', () => { let scheduler: TestScheduler; - let service: NotificationsBrokerSourceRestService; + let service: QualityAssuranceSourceRestService; let responseCacheEntry: RequestEntry; let requestService: RequestService; let rdbService: RemoteDataBuildService; @@ -36,9 +36,9 @@ describe('NotificationsBrokerSourceRestService', () => { const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); - const array = [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ]; + const array = [ qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerSourceObjectRD = createSuccessfulRemoteDataObject(notificationsBrokerSourceObjectMorePid); + const brokerSourceObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceSourceObjectMorePid); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); beforeEach(() => { @@ -72,7 +72,7 @@ describe('NotificationsBrokerSourceRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new NotificationsBrokerSourceRestService( + service = new QualityAssuranceSourceRestService( requestService, rdbService, objectCache, @@ -96,7 +96,7 @@ describe('NotificationsBrokerSourceRestService', () => { done(); }); - it('should return a RemoteData> for the object with the given URL', () => { + it('should return a RemoteData> for the object with the given URL', () => { const result = service.getSources(); const expected = cold('(a)', { a: paginatedListRD @@ -107,16 +107,16 @@ describe('NotificationsBrokerSourceRestService', () => { describe('getSource', () => { it('should proxy the call to dataservice.findByHref', (done) => { - service.getSource(notificationsBrokerSourceObjectMorePid.id).subscribe( + service.getSource(qualityAssuranceSourceObjectMorePid.id).subscribe( (res) => { - expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + notificationsBrokerSourceObjectMorePid.id, true, true); + expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + qualityAssuranceSourceObjectMorePid.id, true, true); } ); done(); }); - it('should return a RemoteData for the object with the given URL', () => { - const result = service.getSource(notificationsBrokerSourceObjectMorePid.id); + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getSource(qualityAssuranceSourceObjectMorePid.id); const expected = cold('(a)', { a: brokerSourceObjectRD }); diff --git a/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.ts b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts similarity index 72% rename from src/app/core/notifications/broker/source/notifications-broker-source-rest.service.ts rename to src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts index ebbbe995d1a..85045aebcd0 100644 --- a/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.ts +++ b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts @@ -5,29 +5,29 @@ import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { mergeMap, take } from 'rxjs/operators'; -import { CoreState } from '../../../core.reducers'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../../../cache/object-cache.service'; import { dataService } from '../../../cache/builders/build-decorators'; import { RequestService } from '../../../data/request.service'; -import { FindListOptions } from '../../../data/request.models'; import { DataService } from '../../../data/data.service'; import { ChangeAnalyzer } from '../../../data/change-analyzer'; import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; import { RemoteData } from '../../../data/remote-data'; -import { NotificationsBrokerSourceObject } from '../models/notifications-broker-source.model'; -import { NOTIFICATIONS_BROKER_SOURCE_OBJECT } from '../models/notifications-broker-source-object.resource-type'; +import { QualityAssuranceSourceObject } from '../models/quality-assurance-source.model'; +import { QUALITY_ASSURANCE_SOURCE_OBJECT } from '../models/quality-assurance-source-object.resource-type'; import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model'; import { PaginatedList } from '../../../data/paginated-list.model'; +import {CoreState} from '../../../core-state.model'; +import {FindListOptions} from '../../../data/find-list-options.model'; /* tslint:disable:max-classes-per-file */ /** * A private DataService implementation to delegate specific methods to. */ -class DataServiceImpl extends DataService { +class DataServiceImpl extends DataService { /** * The REST endpoint. */ @@ -42,7 +42,7 @@ class DataServiceImpl extends DataService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer} comparator + * @param {ChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -52,17 +52,17 @@ class DataServiceImpl extends DataService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer) { + protected comparator: ChangeAnalyzer) { super(); } } /** - * The service handling all Notifications Broker source REST requests. + * The service handling all Quality Assurance source REST requests. */ @Injectable() -@dataService(NOTIFICATIONS_BROKER_SOURCE_OBJECT) -export class NotificationsBrokerSourceRestService { +@dataService(QUALITY_ASSURANCE_SOURCE_OBJECT) +export class QualityAssuranceSourceRestService { /** * A private DataService implementation to delegate specific methods to. */ @@ -76,7 +76,7 @@ export class NotificationsBrokerSourceRestService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {DefaultChangeAnalyzer} comparator + * @param {DefaultChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -85,21 +85,21 @@ export class NotificationsBrokerSourceRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer) { + protected comparator: DefaultChangeAnalyzer) { this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } /** - * Return the list of Notifications Broker source. + * Return the list of Quality Assurance source. * * @param options * Find list options object. * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable>> - * The list of Notifications Broker source. + * @return Observable>> + * The list of Quality Assurance source. */ - public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { + public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { return this.dataService.getBrowseEndpoint(options, 'nbsources').pipe( take(1), mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), @@ -114,16 +114,16 @@ export class NotificationsBrokerSourceRestService { } /** - * Return a single Notifications Broker source. + * Return a single Quality Assurance source. * * @param id - * The Notifications Broker source id + * The Quality Assurance source id * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable> - * The Notifications Broker source. + * @return Observable> + * The Quality Assurance source. */ - public getSource(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { + public getSource(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { const options = {}; return this.dataService.getBrowseEndpoint(options, 'nbsources').pipe( take(1), diff --git a/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.spec.ts b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts similarity index 76% rename from src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.spec.ts rename to src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts index 06931e2032c..cb828141a6d 100644 --- a/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.spec.ts +++ b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts @@ -6,7 +6,6 @@ import { cold, getTestScheduler } from 'jasmine-marbles'; import { RequestService } from '../../../data/request.service'; import { buildPaginatedList } from '../../../data/paginated-list.model'; -import { RequestEntry } from '../../../data/request.reducer'; import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../../../cache/object-cache.service'; import { RestResponse } from '../../../cache/response.models'; @@ -14,15 +13,16 @@ import { PageInfo } from '../../../shared/page-info.model'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; -import { NotificationsBrokerTopicRestService } from './notifications-broker-topic-rest.service'; +import { QualityAssuranceTopicRestService } from './quality-assurance-topic-rest.service'; import { - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMorePid + qualityAssuranceTopicObjectMoreAbstract, + qualityAssuranceTopicObjectMorePid } from '../../../../shared/mocks/notifications.mock'; +import {RequestEntry} from '../../../data/request-entry.model'; -describe('NotificationsBrokerTopicRestService', () => { +describe('QualityAssuranceTopicRestService', () => { let scheduler: TestScheduler; - let service: NotificationsBrokerTopicRestService; + let service: QualityAssuranceTopicRestService; let responseCacheEntry: RequestEntry; let requestService: RequestService; let rdbService: RemoteDataBuildService; @@ -36,9 +36,9 @@ describe('NotificationsBrokerTopicRestService', () => { const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); - const array = [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ]; + const array = [ qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerTopicObjectRD = createSuccessfulRemoteDataObject(notificationsBrokerTopicObjectMorePid); + const brokerTopicObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceTopicObjectMorePid); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); beforeEach(() => { @@ -72,7 +72,7 @@ describe('NotificationsBrokerTopicRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new NotificationsBrokerTopicRestService( + service = new QualityAssuranceTopicRestService( requestService, rdbService, objectCache, @@ -96,7 +96,7 @@ describe('NotificationsBrokerTopicRestService', () => { done(); }); - it('should return a RemoteData> for the object with the given URL', () => { + it('should return a RemoteData> for the object with the given URL', () => { const result = service.getTopics(); const expected = cold('(a)', { a: paginatedListRD @@ -107,16 +107,16 @@ describe('NotificationsBrokerTopicRestService', () => { describe('getTopic', () => { it('should proxy the call to dataservice.findByHref', (done) => { - service.getTopic(notificationsBrokerTopicObjectMorePid.id).subscribe( + service.getTopic(qualityAssuranceTopicObjectMorePid.id).subscribe( (res) => { - expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + notificationsBrokerTopicObjectMorePid.id, true, true); + expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + qualityAssuranceTopicObjectMorePid.id, true, true); } ); done(); }); - it('should return a RemoteData for the object with the given URL', () => { - const result = service.getTopic(notificationsBrokerTopicObjectMorePid.id); + it('should return a RemoteData for the object with the given URL', () => { + const result = service.getTopic(qualityAssuranceTopicObjectMorePid.id); const expected = cold('(a)', { a: brokerTopicObjectRD }); diff --git a/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.ts b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts similarity index 73% rename from src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.ts rename to src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts index 9f0b93cfb39..da901267097 100644 --- a/src/app/core/notifications/broker/topics/notifications-broker-topic-rest.service.ts +++ b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts @@ -5,29 +5,29 @@ import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { mergeMap, take } from 'rxjs/operators'; -import { CoreState } from '../../../core.reducers'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../../../cache/object-cache.service'; import { dataService } from '../../../cache/builders/build-decorators'; import { RequestService } from '../../../data/request.service'; -import { FindListOptions } from '../../../data/request.models'; import { DataService } from '../../../data/data.service'; import { ChangeAnalyzer } from '../../../data/change-analyzer'; import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; import { RemoteData } from '../../../data/remote-data'; -import { NotificationsBrokerTopicObject } from '../models/notifications-broker-topic.model'; -import { NOTIFICATIONS_BROKER_TOPIC_OBJECT } from '../models/notifications-broker-topic-object.resource-type'; +import { QualityAssuranceTopicObject } from '../models/quality-assurance-topic.model'; +import { QUALITY_ASSURANCE_TOPIC_OBJECT } from '../models/quality-assurance-topic-object.resource-type'; import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model'; import { PaginatedList } from '../../../data/paginated-list.model'; +import {CoreState} from '../../../core-state.model'; +import {FindListOptions} from '../../../data/find-list-options.model'; /* tslint:disable:max-classes-per-file */ /** * A private DataService implementation to delegate specific methods to. */ -class DataServiceImpl extends DataService { +class DataServiceImpl extends DataService { /** * The REST endpoint. */ @@ -42,7 +42,7 @@ class DataServiceImpl extends DataService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer} comparator + * @param {ChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -52,17 +52,17 @@ class DataServiceImpl extends DataService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer) { + protected comparator: ChangeAnalyzer) { super(); } } /** - * The service handling all Notifications Broker topic REST requests. + * The service handling all Quality Assurance topic REST requests. */ @Injectable() -@dataService(NOTIFICATIONS_BROKER_TOPIC_OBJECT) -export class NotificationsBrokerTopicRestService { +@dataService(QUALITY_ASSURANCE_TOPIC_OBJECT) +export class QualityAssuranceTopicRestService { /** * A private DataService implementation to delegate specific methods to. */ @@ -76,7 +76,7 @@ export class NotificationsBrokerTopicRestService { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {DefaultChangeAnalyzer} comparator + * @param {DefaultChangeAnalyzer} comparator */ constructor( protected requestService: RequestService, @@ -85,21 +85,21 @@ export class NotificationsBrokerTopicRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer) { + protected comparator: DefaultChangeAnalyzer) { this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } /** - * Return the list of Notifications Broker topics. + * Return the list of Quality Assurance topics. * * @param options * Find list options object. * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable>> - * The list of Notifications Broker topics. + * @return Observable>> + * The list of Quality Assurance topics. */ - public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { + public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( take(1), mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), @@ -114,16 +114,16 @@ export class NotificationsBrokerTopicRestService { } /** - * Return a single Notifications Broker topic. + * Return a single Quality Assurance topic. * * @param id - * The Notifications Broker topic id + * The Quality Assurance topic id * @param linksToFollow * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable> - * The Notifications Broker topic. + * @return Observable> + * The Quality Assurance topic. */ - public getTopic(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { + public getTopic(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { const options = {}; return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( take(1), diff --git a/src/app/notifications/broker/source/notifications-broker-source.reducer.ts b/src/app/notifications/broker/source/notifications-broker-source.reducer.ts deleted file mode 100644 index 5395796380c..00000000000 --- a/src/app/notifications/broker/source/notifications-broker-source.reducer.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; -import { NotificationsBrokerSourceActionTypes, NotificationsBrokerSourceActions } from './notifications-broker-source.actions'; - -/** - * The interface representing the Notifications Broker source state. - */ -export interface NotificationsBrokerSourceState { - source: NotificationsBrokerSourceObject[]; - processing: boolean; - loaded: boolean; - totalPages: number; - currentPage: number; - totalElements: number; -} - -/** - * Used for the Notifications Broker source state initialization. - */ -const notificationsBrokerSourceInitialState: NotificationsBrokerSourceState = { - source: [], - processing: false, - loaded: false, - totalPages: 0, - currentPage: 0, - totalElements: 0 -}; - -/** - * The Notifications Broker Source Reducer - * - * @param state - * the current state initialized with notificationsBrokerSourceInitialState - * @param action - * the action to perform on the state - * @return NotificationsBrokerSourceState - * the new state - */ -export function notificationsBrokerSourceReducer(state = notificationsBrokerSourceInitialState, action: NotificationsBrokerSourceActions): NotificationsBrokerSourceState { - switch (action.type) { - case NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE: { - return Object.assign({}, state, { - source: [], - processing: true - }); - } - - case NotificationsBrokerSourceActionTypes.ADD_SOURCE: { - return Object.assign({}, state, { - source: action.payload.source, - processing: false, - loaded: true, - totalPages: action.payload.totalPages, - currentPage: state.currentPage, - totalElements: action.payload.totalElements - }); - } - - case NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR: { - return Object.assign({}, state, { - processing: false, - loaded: true, - totalPages: 0, - currentPage: 0, - totalElements: 0 - }); - } - - default: { - return state; - } - } -} diff --git a/src/app/notifications/broker/source/notifications-broker-source.service.ts b/src/app/notifications/broker/source/notifications-broker-source.service.ts deleted file mode 100644 index e80643049c2..00000000000 --- a/src/app/notifications/broker/source/notifications-broker-source.service.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { find, map } from 'rxjs/operators'; -import { NotificationsBrokerSourceRestService } from '../../../core/notifications/broker/source/notifications-broker-source-rest.service'; -import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; -import { FindListOptions } from '../../../core/data/request.models'; -import { RemoteData } from '../../../core/data/remote-data'; -import { PaginatedList } from '../../../core/data/paginated-list.model'; -import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; - -/** - * The service handling all Notifications Broker source requests to the REST service. - */ -@Injectable() -export class NotificationsBrokerSourceService { - - /** - * Initialize the service variables. - * @param {NotificationsBrokerSourceRestService} notificationsBrokerSourceRestService - */ - constructor( - private notificationsBrokerSourceRestService: NotificationsBrokerSourceRestService - ) { } - - /** - * Return the list of Notifications Broker source managing pagination and errors. - * - * @param elementsPerPage - * The number of the source per page - * @param currentPage - * The page number to retrieve - * @return Observable> - * The list of Notifications Broker source. - */ - public getSources(elementsPerPage, currentPage): Observable> { - const sortOptions = new SortOptions('name', SortDirection.ASC); - - const findListOptions: FindListOptions = { - elementsPerPage: elementsPerPage, - currentPage: currentPage, - sort: sortOptions - }; - - return this.notificationsBrokerSourceRestService.getSources(findListOptions).pipe( - find((rd: RemoteData>) => !rd.isResponsePending), - map((rd: RemoteData>) => { - if (rd.hasSucceeded) { - return rd.payload; - } else { - throw new Error('Can\'t retrieve Notifications Broker source from the Broker source REST service'); - } - }) - ); - } -} diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts b/src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts deleted file mode 100644 index 2a7be1bf13d..00000000000 --- a/src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; -import { NotificationsBrokerTopicActionTypes, NotificationsBrokerTopicsActions } from './notifications-broker-topics.actions'; - -/** - * The interface representing the Notifications Broker topic state. - */ -export interface NotificationsBrokerTopicState { - topics: NotificationsBrokerTopicObject[]; - processing: boolean; - loaded: boolean; - totalPages: number; - currentPage: number; - totalElements: number; -} - -/** - * Used for the Notifications Broker topic state initialization. - */ -const notificationsBrokerTopicInitialState: NotificationsBrokerTopicState = { - topics: [], - processing: false, - loaded: false, - totalPages: 0, - currentPage: 0, - totalElements: 0 -}; - -/** - * The Notifications Broker Topic Reducer - * - * @param state - * the current state initialized with notificationsBrokerTopicInitialState - * @param action - * the action to perform on the state - * @return NotificationsBrokerTopicState - * the new state - */ -export function notificationsBrokerTopicsReducer(state = notificationsBrokerTopicInitialState, action: NotificationsBrokerTopicsActions): NotificationsBrokerTopicState { - switch (action.type) { - case NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS: { - return Object.assign({}, state, { - topics: [], - processing: true - }); - } - - case NotificationsBrokerTopicActionTypes.ADD_TOPICS: { - return Object.assign({}, state, { - topics: action.payload.topics, - processing: false, - loaded: true, - totalPages: action.payload.totalPages, - currentPage: state.currentPage, - totalElements: action.payload.totalElements - }); - } - - case NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR: { - return Object.assign({}, state, { - processing: false, - loaded: true, - totalPages: 0, - currentPage: 0, - totalElements: 0 - }); - } - - default: { - return state; - } - } -} diff --git a/src/app/notifications/notifications-state.service.spec.ts b/src/app/notifications/notifications-state.service.spec.ts index 91048a93ef3..cabda48ec58 100644 --- a/src/app/notifications/notifications-state.service.spec.ts +++ b/src/app/notifications/notifications-state.service.spec.ts @@ -5,15 +5,15 @@ import { cold } from 'jasmine-marbles'; import { notificationsReducers } from './notifications.reducer'; import { NotificationsStateService } from './notifications-state.service'; import { - notificationsBrokerSourceObjectMissingPid, - notificationsBrokerSourceObjectMoreAbstract, - notificationsBrokerSourceObjectMorePid, - notificationsBrokerTopicObjectMissingPid, - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMorePid + qualityAssuranceSourceObjectMissingPid, + qualityAssuranceSourceObjectMoreAbstract, + qualityAssuranceSourceObjectMorePid, + qualityAssuranceTopicObjectMissingPid, + qualityAssuranceTopicObjectMoreAbstract, + qualityAssuranceTopicObjectMorePid } from '../shared/mocks/notifications.mock'; -import { RetrieveAllTopicsAction } from './broker/topics/notifications-broker-topics.actions'; -import { RetrieveAllSourceAction } from './broker/source/notifications-broker-source.actions'; +import { RetrieveAllTopicsAction } from './qa/topics/quality-assurance-topics.actions'; +import { RetrieveAllSourceAction } from './qa/source/quality-assurance-source.actions'; describe('NotificationsStateService', () => { let service: NotificationsStateService; @@ -42,9 +42,9 @@ describe('NotificationsStateService', () => { notifications: { brokerTopic: { topics: [ - notificationsBrokerTopicObjectMorePid, - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMissingPid + qualityAssuranceTopicObjectMorePid, + qualityAssuranceTopicObjectMoreAbstract, + qualityAssuranceTopicObjectMissingPid ], processing: false, loaded: true, @@ -79,9 +79,9 @@ describe('NotificationsStateService', () => { spyOn(store, 'dispatch'); }); - describe('getNotificationsBrokerTopics', () => { + describe('getQualityAssuranceTopics', () => { it('Should return an empty array', () => { - const result = service.getNotificationsBrokerTopics(); + const result = service.getQualityAssuranceTopics(); const expected = cold('(a)', { a: [] }); @@ -89,9 +89,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerTopicsTotalPages', () => { + describe('getQualityAssuranceTopicsTotalPages', () => { it('Should return zero (0)', () => { - const result = service.getNotificationsBrokerTopicsTotalPages(); + const result = service.getQualityAssuranceTopicsTotalPages(); const expected = cold('(a)', { a: 0 }); @@ -99,9 +99,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerTopicsCurrentPage', () => { + describe('getQualityAssuranceTopicsCurrentPage', () => { it('Should return minus one (0)', () => { - const result = service.getNotificationsBrokerTopicsCurrentPage(); + const result = service.getQualityAssuranceTopicsCurrentPage(); const expected = cold('(a)', { a: 0 }); @@ -109,9 +109,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerTopicsTotals', () => { + describe('getQualityAssuranceTopicsTotals', () => { it('Should return zero (0)', () => { - const result = service.getNotificationsBrokerTopicsTotals(); + const result = service.getQualityAssuranceTopicsTotals(); const expected = cold('(a)', { a: 0 }); @@ -119,9 +119,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerTopicsLoading', () => { + describe('isQualityAssuranceTopicsLoading', () => { it('Should return TRUE', () => { - const result = service.isNotificationsBrokerTopicsLoading(); + const result = service.isQualityAssuranceTopicsLoading(); const expected = cold('(a)', { a: true }); @@ -129,9 +129,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerTopicsLoaded', () => { + describe('isQualityAssuranceTopicsLoaded', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsLoaded(); + const result = service.isQualityAssuranceTopicsLoaded(); const expected = cold('(a)', { a: false }); @@ -139,9 +139,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerTopicsProcessing', () => { + describe('isQualityAssuranceTopicsProcessing', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsProcessing(); + const result = service.isQualityAssuranceTopicsProcessing(); const expected = cold('(a)', { a: false }); @@ -171,23 +171,23 @@ describe('NotificationsStateService', () => { spyOn(store, 'dispatch'); }); - describe('getNotificationsBrokerTopics', () => { + describe('getQualityAssuranceTopics', () => { it('Should return an array of topics', () => { - const result = service.getNotificationsBrokerTopics(); + const result = service.getQualityAssuranceTopics(); const expected = cold('(a)', { a: [ - notificationsBrokerTopicObjectMorePid, - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMissingPid + qualityAssuranceTopicObjectMorePid, + qualityAssuranceTopicObjectMoreAbstract, + qualityAssuranceTopicObjectMissingPid ] }); expect(result).toBeObservable(expected); }); }); - describe('getNotificationsBrokerTopicsTotalPages', () => { + describe('getQualityAssuranceTopicsTotalPages', () => { it('Should return one (1)', () => { - const result = service.getNotificationsBrokerTopicsTotalPages(); + const result = service.getQualityAssuranceTopicsTotalPages(); const expected = cold('(a)', { a: 1 }); @@ -195,9 +195,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerTopicsCurrentPage', () => { + describe('getQualityAssuranceTopicsCurrentPage', () => { it('Should return minus zero (1)', () => { - const result = service.getNotificationsBrokerTopicsCurrentPage(); + const result = service.getQualityAssuranceTopicsCurrentPage(); const expected = cold('(a)', { a: 1 }); @@ -205,9 +205,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerTopicsTotals', () => { + describe('getQualityAssuranceTopicsTotals', () => { it('Should return three (3)', () => { - const result = service.getNotificationsBrokerTopicsTotals(); + const result = service.getQualityAssuranceTopicsTotals(); const expected = cold('(a)', { a: 3 }); @@ -215,9 +215,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerTopicsLoading', () => { + describe('isQualityAssuranceTopicsLoading', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsLoading(); + const result = service.isQualityAssuranceTopicsLoading(); const expected = cold('(a)', { a: false }); @@ -225,9 +225,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerTopicsLoaded', () => { + describe('isQualityAssuranceTopicsLoaded', () => { it('Should return TRUE', () => { - const result = service.isNotificationsBrokerTopicsLoaded(); + const result = service.isQualityAssuranceTopicsLoaded(); const expected = cold('(a)', { a: true }); @@ -235,9 +235,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerTopicsProcessing', () => { + describe('isQualityAssuranceTopicsProcessing', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerTopicsProcessing(); + const result = service.isQualityAssuranceTopicsProcessing(); const expected = cold('(a)', { a: false }); @@ -267,12 +267,12 @@ describe('NotificationsStateService', () => { spyOn(store, 'dispatch'); }); - describe('dispatchRetrieveNotificationsBrokerTopics', () => { + describe('dispatchRetrieveQualityAssuranceTopics', () => { it('Should call store.dispatch', () => { const elementsPerPage = 3; const currentPage = 1; const action = new RetrieveAllTopicsAction(elementsPerPage, currentPage); - service.dispatchRetrieveNotificationsBrokerTopics(elementsPerPage, currentPage); + service.dispatchRetrieveQualityAssuranceTopics(elementsPerPage, currentPage); expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action); }); }); @@ -300,9 +300,9 @@ describe('NotificationsStateService', () => { notifications: { brokerSource: { source: [ - notificationsBrokerSourceObjectMorePid, - notificationsBrokerSourceObjectMoreAbstract, - notificationsBrokerSourceObjectMissingPid + qualityAssuranceSourceObjectMorePid, + qualityAssuranceSourceObjectMoreAbstract, + qualityAssuranceSourceObjectMissingPid ], processing: false, loaded: true, @@ -337,9 +337,9 @@ describe('NotificationsStateService', () => { spyOn(store, 'dispatch'); }); - describe('getNotificationsBrokerSource', () => { + describe('getQualityAssuranceSource', () => { it('Should return an empty array', () => { - const result = service.getNotificationsBrokerSource(); + const result = service.getQualityAssuranceSource(); const expected = cold('(a)', { a: [] }); @@ -347,9 +347,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerSourceTotalPages', () => { + describe('getQualityAssuranceSourceTotalPages', () => { it('Should return zero (0)', () => { - const result = service.getNotificationsBrokerSourceTotalPages(); + const result = service.getQualityAssuranceSourceTotalPages(); const expected = cold('(a)', { a: 0 }); @@ -357,9 +357,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerSourcesCurrentPage', () => { + describe('getQualityAssuranceSourcesCurrentPage', () => { it('Should return minus one (0)', () => { - const result = service.getNotificationsBrokerSourceCurrentPage(); + const result = service.getQualityAssuranceSourceCurrentPage(); const expected = cold('(a)', { a: 0 }); @@ -367,9 +367,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerSourceTotals', () => { + describe('getQualityAssuranceSourceTotals', () => { it('Should return zero (0)', () => { - const result = service.getNotificationsBrokerSourceTotals(); + const result = service.getQualityAssuranceSourceTotals(); const expected = cold('(a)', { a: 0 }); @@ -377,9 +377,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerSourceLoading', () => { + describe('isQualityAssuranceSourceLoading', () => { it('Should return TRUE', () => { - const result = service.isNotificationsBrokerSourceLoading(); + const result = service.isQualityAssuranceSourceLoading(); const expected = cold('(a)', { a: true }); @@ -387,9 +387,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerSourceLoaded', () => { + describe('isQualityAssuranceSourceLoaded', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerSourceLoaded(); + const result = service.isQualityAssuranceSourceLoaded(); const expected = cold('(a)', { a: false }); @@ -397,9 +397,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerSourceProcessing', () => { + describe('isQualityAssuranceSourceProcessing', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerSourceProcessing(); + const result = service.isQualityAssuranceSourceProcessing(); const expected = cold('(a)', { a: false }); @@ -429,23 +429,23 @@ describe('NotificationsStateService', () => { spyOn(store, 'dispatch'); }); - describe('getNotificationsBrokerSource', () => { + describe('getQualityAssuranceSource', () => { it('Should return an array of Source', () => { - const result = service.getNotificationsBrokerSource(); + const result = service.getQualityAssuranceSource(); const expected = cold('(a)', { a: [ - notificationsBrokerSourceObjectMorePid, - notificationsBrokerSourceObjectMoreAbstract, - notificationsBrokerSourceObjectMissingPid + qualityAssuranceSourceObjectMorePid, + qualityAssuranceSourceObjectMoreAbstract, + qualityAssuranceSourceObjectMissingPid ] }); expect(result).toBeObservable(expected); }); }); - describe('getNotificationsBrokerSourceTotalPages', () => { + describe('getQualityAssuranceSourceTotalPages', () => { it('Should return one (1)', () => { - const result = service.getNotificationsBrokerSourceTotalPages(); + const result = service.getQualityAssuranceSourceTotalPages(); const expected = cold('(a)', { a: 1 }); @@ -453,9 +453,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerSourceCurrentPage', () => { + describe('getQualityAssuranceSourceCurrentPage', () => { it('Should return minus zero (1)', () => { - const result = service.getNotificationsBrokerSourceCurrentPage(); + const result = service.getQualityAssuranceSourceCurrentPage(); const expected = cold('(a)', { a: 1 }); @@ -463,9 +463,9 @@ describe('NotificationsStateService', () => { }); }); - describe('getNotificationsBrokerSourceTotals', () => { + describe('getQualityAssuranceSourceTotals', () => { it('Should return three (3)', () => { - const result = service.getNotificationsBrokerSourceTotals(); + const result = service.getQualityAssuranceSourceTotals(); const expected = cold('(a)', { a: 3 }); @@ -473,9 +473,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerSourceLoading', () => { + describe('isQualityAssuranceSourceLoading', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerSourceLoading(); + const result = service.isQualityAssuranceSourceLoading(); const expected = cold('(a)', { a: false }); @@ -483,9 +483,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerSourceLoaded', () => { + describe('isQualityAssuranceSourceLoaded', () => { it('Should return TRUE', () => { - const result = service.isNotificationsBrokerSourceLoaded(); + const result = service.isQualityAssuranceSourceLoaded(); const expected = cold('(a)', { a: true }); @@ -493,9 +493,9 @@ describe('NotificationsStateService', () => { }); }); - describe('isNotificationsBrokerSourceProcessing', () => { + describe('isQualityAssuranceSourceProcessing', () => { it('Should return FALSE', () => { - const result = service.isNotificationsBrokerSourceProcessing(); + const result = service.isQualityAssuranceSourceProcessing(); const expected = cold('(a)', { a: false }); @@ -525,12 +525,12 @@ describe('NotificationsStateService', () => { spyOn(store, 'dispatch'); }); - describe('dispatchRetrieveNotificationsBrokerSource', () => { + describe('dispatchRetrieveQualityAssuranceSource', () => { it('Should call store.dispatch', () => { const elementsPerPage = 3; const currentPage = 1; const action = new RetrieveAllSourceAction(elementsPerPage, currentPage); - service.dispatchRetrieveNotificationsBrokerSource(elementsPerPage, currentPage); + service.dispatchRetrieveQualityAssuranceSource(elementsPerPage, currentPage); expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action); }); }); diff --git a/src/app/notifications/notifications-state.service.ts b/src/app/notifications/notifications-state.service.ts index cbee503acd1..99605a54fa0 100644 --- a/src/app/notifications/notifications-state.service.ts +++ b/src/app/notifications/notifications-state.service.ts @@ -3,24 +3,24 @@ import { select, Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { - getNotificationsBrokerTopicsCurrentPageSelector, - getNotificationsBrokerTopicsTotalPagesSelector, - getNotificationsBrokerTopicsTotalsSelector, - isNotificationsBrokerTopicsLoadedSelector, - notificationsBrokerTopicsObjectSelector, - isNotificationsBrokerTopicsProcessingSelector, - notificationsBrokerSourceObjectSelector, - isNotificationsBrokerSourceLoadedSelector, - isNotificationsBrokerSourceProcessingSelector, - getNotificationsBrokerSourceTotalPagesSelector, - getNotificationsBrokerSourceCurrentPageSelector, - getNotificationsBrokerSourceTotalsSelector + getQualityAssuranceTopicsCurrentPageSelector, + getQualityAssuranceTopicsTotalPagesSelector, + getQualityAssuranceTopicsTotalsSelector, + isQualityAssuranceTopicsLoadedSelector, + qualityAssuranceTopicsObjectSelector, + isQualityAssuranceTopicsProcessingSelector, + qualityAssuranceSourceObjectSelector, + isQualityAssuranceSourceLoadedSelector, + isQualityAssuranceSourceProcessingSelector, + getQualityAssuranceSourceTotalPagesSelector, + getQualityAssuranceSourceCurrentPageSelector, + getQualityAssuranceSourceTotalsSelector } from './selectors'; -import { NotificationsBrokerTopicObject } from '../core/notifications/broker/models/notifications-broker-topic.model'; +import { QualityAssuranceTopicObject } from '../core/notifications/qa/models/quality-assurance-topic.model'; import { NotificationsState } from './notifications.reducer'; -import { RetrieveAllTopicsAction } from './broker/topics/notifications-broker-topics.actions'; -import { NotificationsBrokerSourceObject } from '../core/notifications/broker/models/notifications-broker-source.model'; -import { RetrieveAllSourceAction } from './broker/source/notifications-broker-source.actions'; +import { RetrieveAllTopicsAction } from './qa/topics/quality-assurance-topics.actions'; +import { QualityAssuranceSourceObject } from '../core/notifications/qa/models/quality-assurance-source.model'; +import { RetrieveAllSourceAction } from './qa/source/quality-assurance-source.actions'; /** * The service handling the Notifications State. @@ -34,179 +34,179 @@ export class NotificationsStateService { */ constructor(private store: Store) { } - // Notifications Broker topics + // Quality Assurance topics // -------------------------------------------------------------------------- /** - * Returns the list of Notifications Broker topics from the state. + * Returns the list of Quality Assurance topics from the state. * - * @return Observable - * The list of Notifications Broker topics. + * @return Observable + * The list of Quality Assurance topics. */ - public getNotificationsBrokerTopics(): Observable { - return this.store.pipe(select(notificationsBrokerTopicsObjectSelector())); + public getQualityAssuranceTopics(): Observable { + return this.store.pipe(select(qualityAssuranceTopicsObjectSelector())); } /** - * Returns the information about the loading status of the Notifications Broker topics (if it's running or not). + * Returns the information about the loading status of the Quality Assurance topics (if it's running or not). * * @return Observable * 'true' if the topics are loading, 'false' otherwise. */ - public isNotificationsBrokerTopicsLoading(): Observable { + public isQualityAssuranceTopicsLoading(): Observable { return this.store.pipe( - select(isNotificationsBrokerTopicsLoadedSelector), + select(isQualityAssuranceTopicsLoadedSelector), map((loaded: boolean) => !loaded) ); } /** - * Returns the information about the loading status of the Notifications Broker topics (whether or not they were loaded). + * Returns the information about the loading status of the Quality Assurance topics (whether or not they were loaded). * * @return Observable * 'true' if the topics are loaded, 'false' otherwise. */ - public isNotificationsBrokerTopicsLoaded(): Observable { - return this.store.pipe(select(isNotificationsBrokerTopicsLoadedSelector)); + public isQualityAssuranceTopicsLoaded(): Observable { + return this.store.pipe(select(isQualityAssuranceTopicsLoadedSelector)); } /** - * Returns the information about the processing status of the Notifications Broker topics (if it's running or not). + * Returns the information about the processing status of the Quality Assurance topics (if it's running or not). * * @return Observable * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. */ - public isNotificationsBrokerTopicsProcessing(): Observable { - return this.store.pipe(select(isNotificationsBrokerTopicsProcessingSelector)); + public isQualityAssuranceTopicsProcessing(): Observable { + return this.store.pipe(select(isQualityAssuranceTopicsProcessingSelector)); } /** - * Returns, from the state, the total available pages of the Notifications Broker topics. + * Returns, from the state, the total available pages of the Quality Assurance topics. * * @return Observable - * The number of the Notifications Broker topics pages. + * The number of the Quality Assurance topics pages. */ - public getNotificationsBrokerTopicsTotalPages(): Observable { - return this.store.pipe(select(getNotificationsBrokerTopicsTotalPagesSelector)); + public getQualityAssuranceTopicsTotalPages(): Observable { + return this.store.pipe(select(getQualityAssuranceTopicsTotalPagesSelector)); } /** - * Returns the current page of the Notifications Broker topics, from the state. + * Returns the current page of the Quality Assurance topics, from the state. * * @return Observable - * The number of the current Notifications Broker topics page. + * The number of the current Quality Assurance topics page. */ - public getNotificationsBrokerTopicsCurrentPage(): Observable { - return this.store.pipe(select(getNotificationsBrokerTopicsCurrentPageSelector)); + public getQualityAssuranceTopicsCurrentPage(): Observable { + return this.store.pipe(select(getQualityAssuranceTopicsCurrentPageSelector)); } /** - * Returns the total number of the Notifications Broker topics. + * Returns the total number of the Quality Assurance topics. * * @return Observable - * The number of the Notifications Broker topics. + * The number of the Quality Assurance topics. */ - public getNotificationsBrokerTopicsTotals(): Observable { - return this.store.pipe(select(getNotificationsBrokerTopicsTotalsSelector)); + public getQualityAssuranceTopicsTotals(): Observable { + return this.store.pipe(select(getQualityAssuranceTopicsTotalsSelector)); } /** - * Dispatch a request to change the Notifications Broker topics state, retrieving the topics from the server. + * Dispatch a request to change the Quality Assurance topics state, retrieving the topics from the server. * * @param elementsPerPage * The number of the topics per page. * @param currentPage * The number of the current page. */ - public dispatchRetrieveNotificationsBrokerTopics(elementsPerPage: number, currentPage: number): void { + public dispatchRetrieveQualityAssuranceTopics(elementsPerPage: number, currentPage: number): void { this.store.dispatch(new RetrieveAllTopicsAction(elementsPerPage, currentPage)); } - // Notifications Broker source + // Quality Assurance source // -------------------------------------------------------------------------- /** - * Returns the list of Notifications Broker source from the state. + * Returns the list of Quality Assurance source from the state. * - * @return Observable - * The list of Notifications Broker source. + * @return Observable + * The list of Quality Assurance source. */ - public getNotificationsBrokerSource(): Observable { - return this.store.pipe(select(notificationsBrokerSourceObjectSelector())); + public getQualityAssuranceSource(): Observable { + return this.store.pipe(select(qualityAssuranceSourceObjectSelector())); } /** - * Returns the information about the loading status of the Notifications Broker source (if it's running or not). + * Returns the information about the loading status of the Quality Assurance source (if it's running or not). * * @return Observable * 'true' if the source are loading, 'false' otherwise. */ - public isNotificationsBrokerSourceLoading(): Observable { + public isQualityAssuranceSourceLoading(): Observable { return this.store.pipe( - select(isNotificationsBrokerSourceLoadedSelector), + select(isQualityAssuranceSourceLoadedSelector), map((loaded: boolean) => !loaded) ); } /** - * Returns the information about the loading status of the Notifications Broker source (whether or not they were loaded). + * Returns the information about the loading status of the Quality Assurance source (whether or not they were loaded). * * @return Observable * 'true' if the source are loaded, 'false' otherwise. */ - public isNotificationsBrokerSourceLoaded(): Observable { - return this.store.pipe(select(isNotificationsBrokerSourceLoadedSelector)); + public isQualityAssuranceSourceLoaded(): Observable { + return this.store.pipe(select(isQualityAssuranceSourceLoadedSelector)); } /** - * Returns the information about the processing status of the Notifications Broker source (if it's running or not). + * Returns the information about the processing status of the Quality Assurance source (if it's running or not). * * @return Observable * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. */ - public isNotificationsBrokerSourceProcessing(): Observable { - return this.store.pipe(select(isNotificationsBrokerSourceProcessingSelector)); + public isQualityAssuranceSourceProcessing(): Observable { + return this.store.pipe(select(isQualityAssuranceSourceProcessingSelector)); } /** - * Returns, from the state, the total available pages of the Notifications Broker source. + * Returns, from the state, the total available pages of the Quality Assurance source. * * @return Observable - * The number of the Notifications Broker source pages. + * The number of the Quality Assurance source pages. */ - public getNotificationsBrokerSourceTotalPages(): Observable { - return this.store.pipe(select(getNotificationsBrokerSourceTotalPagesSelector)); + public getQualityAssuranceSourceTotalPages(): Observable { + return this.store.pipe(select(getQualityAssuranceSourceTotalPagesSelector)); } /** - * Returns the current page of the Notifications Broker source, from the state. + * Returns the current page of the Quality Assurance source, from the state. * * @return Observable - * The number of the current Notifications Broker source page. + * The number of the current Quality Assurance source page. */ - public getNotificationsBrokerSourceCurrentPage(): Observable { - return this.store.pipe(select(getNotificationsBrokerSourceCurrentPageSelector)); + public getQualityAssuranceSourceCurrentPage(): Observable { + return this.store.pipe(select(getQualityAssuranceSourceCurrentPageSelector)); } /** - * Returns the total number of the Notifications Broker source. + * Returns the total number of the Quality Assurance source. * * @return Observable - * The number of the Notifications Broker source. + * The number of the Quality Assurance source. */ - public getNotificationsBrokerSourceTotals(): Observable { - return this.store.pipe(select(getNotificationsBrokerSourceTotalsSelector)); + public getQualityAssuranceSourceTotals(): Observable { + return this.store.pipe(select(getQualityAssuranceSourceTotalsSelector)); } /** - * Dispatch a request to change the Notifications Broker source state, retrieving the source from the server. + * Dispatch a request to change the Quality Assurance source state, retrieving the source from the server. * * @param elementsPerPage * The number of the source per page. * @param currentPage * The number of the current page. */ - public dispatchRetrieveNotificationsBrokerSource(elementsPerPage: number, currentPage: number): void { + public dispatchRetrieveQualityAssuranceSource(elementsPerPage: number, currentPage: number): void { this.store.dispatch(new RetrieveAllSourceAction(elementsPerPage, currentPage)); } } diff --git a/src/app/notifications/notifications.effects.ts b/src/app/notifications/notifications.effects.ts index 39ecded7970..bf70a058554 100644 --- a/src/app/notifications/notifications.effects.ts +++ b/src/app/notifications/notifications.effects.ts @@ -1,7 +1,7 @@ -import { NotificationsBrokerSourceEffects } from './broker/source/notifications-broker-source.effects'; -import { NotificationsBrokerTopicsEffects } from './broker/topics/notifications-broker-topics.effects'; +import { QualityAssuranceSourceEffects } from './qa/source/quality-assurance-source.effects'; +import { QualityAssuranceTopicsEffects } from './qa/topics/quality-assurance-topics.effects'; export const notificationsEffects = [ - NotificationsBrokerTopicsEffects, - NotificationsBrokerSourceEffects + QualityAssuranceTopicsEffects, + QualityAssuranceSourceEffects ]; diff --git a/src/app/notifications/notifications.module.ts b/src/app/notifications/notifications.module.ts index 63224fdd81b..27e34c8d516 100644 --- a/src/app/notifications/notifications.module.ts +++ b/src/app/notifications/notifications.module.ts @@ -6,20 +6,20 @@ import { EffectsModule } from '@ngrx/effects'; import { CoreModule } from '../core/core.module'; import { SharedModule } from '../shared/shared.module'; import { storeModuleConfig } from '../app.reducer'; -import { NotificationsBrokerTopicsComponent } from './broker/topics/notifications-broker-topics.component'; -import { NotificationsBrokerEventsComponent } from './broker/events/notifications-broker-events.component'; +import { QualityAssuranceTopicsComponent } from './qa/topics/quality-assurance-topics.component'; +import { QualityAssuranceEventsComponent } from './qa/events/quality-assurance-events.component'; import { NotificationsStateService } from './notifications-state.service'; import { notificationsReducers, NotificationsState } from './notifications.reducer'; import { notificationsEffects } from './notifications.effects'; -import { NotificationsBrokerTopicsService } from './broker/topics/notifications-broker-topics.service'; -import { NotificationsBrokerTopicRestService } from '../core/notifications/broker/topics/notifications-broker-topic-rest.service'; -import { NotificationsBrokerEventRestService } from '../core/notifications/broker/events/notifications-broker-event-rest.service'; -import { ProjectEntryImportModalComponent } from './broker/project-entry-import-modal/project-entry-import-modal.component'; +import { QualityAssuranceTopicsService } from './qa/topics/quality-assurance-topics.service'; +import { QualityAssuranceTopicRestService } from '../core/notifications/qa/topics/quality-assurance-topic-rest.service'; +import { QualityAssuranceEventRestService } from '../core/notifications/qa/events/quality-assurance-event-rest.service'; +import { ProjectEntryImportModalComponent } from './qa/project-entry-import-modal/project-entry-import-modal.component'; import { TranslateModule } from '@ngx-translate/core'; import { SearchModule } from '../shared/search/search.module'; -import { NotificationsBrokerSourceComponent } from './broker/source/notifications-broker-source.component'; -import { NotificationsBrokerSourceService } from './broker/source/notifications-broker-source.service'; -import { NotificationsBrokerSourceRestService } from '../core/notifications/broker/source/notifications-broker-source-rest.service'; +import { QualityAssuranceSourceComponent } from './qa/source/quality-assurance-source.component'; +import { QualityAssuranceSourceService } from './qa/source/quality-assurance-source.service'; +import { QualityAssuranceSourceRestService } from '../core/notifications/qa/source/quality-assurance-source-rest.service'; const MODULES = [ CommonModule, @@ -31,9 +31,9 @@ const MODULES = [ ]; const COMPONENTS = [ - NotificationsBrokerTopicsComponent, - NotificationsBrokerEventsComponent, - NotificationsBrokerSourceComponent + QualityAssuranceTopicsComponent, + QualityAssuranceEventsComponent, + QualityAssuranceSourceComponent ]; const DIRECTIVES = [ ]; @@ -44,11 +44,11 @@ const ENTRY_COMPONENTS = [ const PROVIDERS = [ NotificationsStateService, - NotificationsBrokerTopicsService, - NotificationsBrokerSourceService, - NotificationsBrokerTopicRestService, - NotificationsBrokerSourceRestService, - NotificationsBrokerEventRestService + QualityAssuranceTopicsService, + QualityAssuranceSourceService, + QualityAssuranceTopicRestService, + QualityAssuranceSourceRestService, + QualityAssuranceEventRestService ]; @NgModule({ diff --git a/src/app/notifications/notifications.reducer.ts b/src/app/notifications/notifications.reducer.ts index 27bebbea205..5800788c42c 100644 --- a/src/app/notifications/notifications.reducer.ts +++ b/src/app/notifications/notifications.reducer.ts @@ -1,18 +1,18 @@ import { ActionReducerMap, createFeatureSelector } from '@ngrx/store'; -import { notificationsBrokerSourceReducer, NotificationsBrokerSourceState } from './broker/source/notifications-broker-source.reducer'; -import { notificationsBrokerTopicsReducer, NotificationsBrokerTopicState, } from './broker/topics/notifications-broker-topics.reducer'; +import { qualityAssuranceSourceReducer, QualityAssuranceSourceState } from './qa/source/quality-assurance-source.reducer'; +import { qualityAssuranceTopicsReducer, QualityAssuranceTopicState, } from './qa/topics/quality-assurance-topics.reducer'; /** * The OpenAIRE State */ export interface NotificationsState { - 'brokerTopic': NotificationsBrokerTopicState; - 'brokerSource': NotificationsBrokerSourceState; + 'brokerTopic': QualityAssuranceTopicState; + 'brokerSource': QualityAssuranceSourceState; } export const notificationsReducers: ActionReducerMap = { - brokerTopic: notificationsBrokerTopicsReducer, - brokerSource: notificationsBrokerSourceReducer + brokerTopic: qualityAssuranceTopicsReducer, + brokerSource: qualityAssuranceSourceReducer }; export const notificationsSelector = createFeatureSelector('notifications'); diff --git a/src/app/notifications/broker/events/notifications-broker-events.component.html b/src/app/notifications/qa/events/quality-assurance-events.component.html similarity index 98% rename from src/app/notifications/broker/events/notifications-broker-events.component.html rename to src/app/notifications/qa/events/quality-assurance-events.component.html index a9f51cefd09..40fa75943f8 100644 --- a/src/app/notifications/broker/events/notifications-broker-events.component.html +++ b/src/app/notifications/qa/events/quality-assurance-events.component.html @@ -4,7 +4,7 @@

{{'notifications.events.title'| translate}}

{{'notifications.broker.events.description'| translate}}

- + {{'notifications.broker.events.back' | translate}} @@ -23,7 +23,7 @@

[paginationOptions]="paginationConfig" [collectionSize]="(totalElements$ | async)" [sortOptions]="paginationSortConfig" - (paginationChange)="getNotificationsBrokerEvents()"> + (paginationChange)="getQualityAssuranceEvents()"> @@ -140,7 +140,7 @@

- + {{'notifications.broker.events.back' | translate}} diff --git a/src/app/notifications/broker/events/notifications-broker-events.component.spec.ts b/src/app/notifications/qa/events/quality-assurance-events.component.spec.ts similarity index 66% rename from src/app/notifications/broker/events/notifications-broker-events.component.spec.ts rename to src/app/notifications/qa/events/quality-assurance-events.component.spec.ts index 40be083567d..976d8540e3a 100644 --- a/src/app/notifications/broker/events/notifications-broker-events.component.spec.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.spec.ts @@ -5,15 +5,15 @@ import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/t import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { of as observableOf } from 'rxjs'; -import { NotificationsBrokerEventRestService } from '../../../core/notifications/broker/events/notifications-broker-event-rest.service'; -import { NotificationsBrokerEventsComponent } from './notifications-broker-events.component'; +import { QualityAssuranceEventRestService } from '../../../core/notifications/qa/events/quality-assurance-event-rest.service'; +import { QualityAssuranceEventsComponent } from './quality-assurance-events.component'; import { - getMockNotificationsBrokerEventRestService, + getMockQualityAssuranceEventRestService, ItemMockPid10, ItemMockPid8, ItemMockPid9, - notificationsBrokerEventObjectMissingProjectFound, - notificationsBrokerEventObjectMissingProjectNotFound, + qualityAssuranceEventObjectMissingProjectFound, + qualityAssuranceEventObjectMissingProjectNotFound, NotificationsMockDspaceObject } from '../../../shared/mocks/notifications.mock'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; @@ -22,8 +22,8 @@ import { getMockTranslateService } from '../../../shared/mocks/translate.service import { createTestComponent } from '../../../shared/testing/utils.test'; import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { NotificationsBrokerEventObject } from '../../../core/notifications/broker/models/notifications-broker-event.model'; -import { NotificationsBrokerEventData } from '../project-entry-import-modal/project-entry-import-modal.component'; +import { QualityAssuranceEventObject } from '../../../core/notifications/qa/models/quality-assurance-event.model'; +import { QualityAssuranceEventData } from '../project-entry-import-modal/project-entry-import-modal.component'; import { TestScheduler } from 'rxjs/testing'; import { getTestScheduler } from 'jasmine-marbles'; import { followLink } from '../../../shared/utils/follow-link-config.model'; @@ -34,14 +34,14 @@ import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; -import { FindListOptions } from '../../../core/data/request.models'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; +import {FindListOptions} from '../../../core/data/find-list-options.model'; -describe('NotificationsBrokerEventsComponent test suite', () => { - let fixture: ComponentFixture; - let comp: NotificationsBrokerEventsComponent; +describe('QualityAssuranceEventsComponent test suite', () => { + let fixture: ComponentFixture; + let comp: QualityAssuranceEventsComponent; let compAsAny: any; let scheduler: TestScheduler; @@ -50,9 +50,9 @@ describe('NotificationsBrokerEventsComponent test suite', () => { close: () => null, dismiss: () => null }; - const notificationsBrokerEventRestServiceStub: any = getMockNotificationsBrokerEventRestService(); + const qualityAssuranceEventRestServiceStub: any = getMockQualityAssuranceEventRestService(); const activatedRouteParams = { - notificationsBrokerEventsParams: { + qualityAssuranceEventsParams: { currentPage: 0, pageSize: 10 } @@ -61,19 +61,19 @@ describe('NotificationsBrokerEventsComponent test suite', () => { id: 'ENRICH!MISSING!PROJECT' }; - const events: NotificationsBrokerEventObject[] = [ - notificationsBrokerEventObjectMissingProjectFound, - notificationsBrokerEventObjectMissingProjectNotFound + const events: QualityAssuranceEventObject[] = [ + qualityAssuranceEventObjectMissingProjectFound, + qualityAssuranceEventObjectMissingProjectNotFound ]; const paginationService = new PaginationServiceStub(); - function getNotificationsBrokerEventData1(): NotificationsBrokerEventData { + function getQualityAssuranceEventData1(): QualityAssuranceEventData { return { - event: notificationsBrokerEventObjectMissingProjectFound, - id: notificationsBrokerEventObjectMissingProjectFound.id, - title: notificationsBrokerEventObjectMissingProjectFound.title, + event: qualityAssuranceEventObjectMissingProjectFound, + id: qualityAssuranceEventObjectMissingProjectFound.id, + title: qualityAssuranceEventObjectMissingProjectFound.title, hasProject: true, - projectTitle: notificationsBrokerEventObjectMissingProjectFound.message.title, + projectTitle: qualityAssuranceEventObjectMissingProjectFound.message.title, projectId: ItemMockPid10.id, handle: ItemMockPid10.handle, reason: null, @@ -82,11 +82,11 @@ describe('NotificationsBrokerEventsComponent test suite', () => { }; } - function getNotificationsBrokerEventData2(): NotificationsBrokerEventData { + function getQualityAssuranceEventData2(): QualityAssuranceEventData { return { - event: notificationsBrokerEventObjectMissingProjectNotFound, - id: notificationsBrokerEventObjectMissingProjectNotFound.id, - title: notificationsBrokerEventObjectMissingProjectNotFound.title, + event: qualityAssuranceEventObjectMissingProjectNotFound, + id: qualityAssuranceEventObjectMissingProjectNotFound.id, + title: qualityAssuranceEventObjectMissingProjectNotFound.title, hasProject: false, projectTitle: null, projectId: null, @@ -104,17 +104,17 @@ describe('NotificationsBrokerEventsComponent test suite', () => { TranslateModule.forRoot(), ], declarations: [ - NotificationsBrokerEventsComponent, + QualityAssuranceEventsComponent, TestComponent, ], providers: [ { provide: ActivatedRoute, useValue: new ActivatedRouteStub(activatedRouteParamsMap, activatedRouteParams) }, - { provide: NotificationsBrokerEventRestService, useValue: notificationsBrokerEventRestServiceStub }, + { provide: QualityAssuranceEventRestService, useValue: qualityAssuranceEventRestServiceStub }, { provide: NgbModal, useValue: modalStub }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: TranslateService, useValue: getMockTranslateService() }, { provide: PaginationService, useValue: paginationService }, - NotificationsBrokerEventsComponent + QualityAssuranceEventsComponent ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(); @@ -129,7 +129,7 @@ describe('NotificationsBrokerEventsComponent test suite', () => { // synchronous beforeEach beforeEach(() => { const html = ` - `; + `; testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; }); @@ -138,14 +138,14 @@ describe('NotificationsBrokerEventsComponent test suite', () => { testFixture.destroy(); }); - it('should create NotificationsBrokerEventsComponent', inject([NotificationsBrokerEventsComponent], (app: NotificationsBrokerEventsComponent) => { + it('should create QualityAssuranceEventsComponent', inject([QualityAssuranceEventsComponent], (app: QualityAssuranceEventsComponent) => { expect(app).toBeDefined(); })); }); describe('Main tests', () => { beforeEach(() => { - fixture = TestBed.createComponent(NotificationsBrokerEventsComponent); + fixture = TestBed.createComponent(QualityAssuranceEventsComponent); comp = fixture.componentInstance; compAsAny = comp; }); @@ -159,8 +159,8 @@ describe('NotificationsBrokerEventsComponent test suite', () => { describe('setEventUpdated', () => { it('should update events', () => { const expected = [ - getNotificationsBrokerEventData1(), - getNotificationsBrokerEventData2() + getQualityAssuranceEventData1(), + getQualityAssuranceEventData2() ]; scheduler.schedule(() => { compAsAny.setEventUpdated(events); @@ -179,14 +179,14 @@ describe('NotificationsBrokerEventsComponent test suite', () => { it('should call executeAction if a project is present', () => { const action = 'ACCEPTED'; - comp.modalChoice(action, getNotificationsBrokerEventData1(), modalStub); - expect(comp.executeAction).toHaveBeenCalledWith(action, getNotificationsBrokerEventData1()); + comp.modalChoice(action, getQualityAssuranceEventData1(), modalStub); + expect(comp.executeAction).toHaveBeenCalledWith(action, getQualityAssuranceEventData1()); }); it('should call openModal if a project is not present', () => { const action = 'ACCEPTED'; - comp.modalChoice(action, getNotificationsBrokerEventData2(), modalStub); - expect(comp.openModal).toHaveBeenCalledWith(action, getNotificationsBrokerEventData2(), modalStub); + comp.modalChoice(action, getQualityAssuranceEventData2(), modalStub); + expect(comp.openModal).toHaveBeenCalledWith(action, getQualityAssuranceEventData2(), modalStub); }); }); @@ -197,7 +197,7 @@ describe('NotificationsBrokerEventsComponent test suite', () => { spyOn(compAsAny.modalService, 'open').and.returnValue({ result: new Promise((res, rej) => 'do' ) }); spyOn(comp, 'executeAction'); - comp.openModal(action, getNotificationsBrokerEventData1(), modalStub); + comp.openModal(action, getQualityAssuranceEventData1(), modalStub); expect(compAsAny.modalService.open).toHaveBeenCalled(); }); }); @@ -217,7 +217,7 @@ describe('NotificationsBrokerEventsComponent test suite', () => { } ); scheduler.schedule(() => { - comp.openModalLookup(getNotificationsBrokerEventData1()); + comp.openModalLookup(getQualityAssuranceEventData1()); }); scheduler.flush(); @@ -227,27 +227,27 @@ describe('NotificationsBrokerEventsComponent test suite', () => { }); describe('executeAction', () => { - it('should call getNotificationsBrokerEvents on 200 response from REST', () => { + it('should call getQualityAssuranceEvents on 200 response from REST', () => { const action = 'ACCEPTED'; - spyOn(compAsAny, 'getNotificationsBrokerEvents'); - notificationsBrokerEventRestServiceStub.patchEvent.and.returnValue(createSuccessfulRemoteDataObject$({})); + spyOn(compAsAny, 'getQualityAssuranceEvents'); + qualityAssuranceEventRestServiceStub.patchEvent.and.returnValue(createSuccessfulRemoteDataObject$({})); scheduler.schedule(() => { - comp.executeAction(action, getNotificationsBrokerEventData1()); + comp.executeAction(action, getQualityAssuranceEventData1()); }); scheduler.flush(); - expect(compAsAny.getNotificationsBrokerEvents).toHaveBeenCalled(); + expect(compAsAny.getQualityAssuranceEvents).toHaveBeenCalled(); }); }); describe('boundProject', () => { it('should populate the project data inside "eventData"', () => { - const eventData = getNotificationsBrokerEventData2(); + const eventData = getQualityAssuranceEventData2(); const projectId = 'UUID-23943-34u43-38344'; const projectName = 'Test Project'; const projectHandle = '1000/1000'; - notificationsBrokerEventRestServiceStub.boundProject.and.returnValue(createSuccessfulRemoteDataObject$({})); + qualityAssuranceEventRestServiceStub.boundProject.and.returnValue(createSuccessfulRemoteDataObject$({})); scheduler.schedule(() => { comp.boundProject(eventData, projectId, projectName, projectHandle); @@ -263,8 +263,8 @@ describe('NotificationsBrokerEventsComponent test suite', () => { describe('removeProject', () => { it('should remove the project data inside "eventData"', () => { - const eventData = getNotificationsBrokerEventData1(); - notificationsBrokerEventRestServiceStub.removeProject.and.returnValue(createNoContentRemoteDataObject$()); + const eventData = getQualityAssuranceEventData1(); + qualityAssuranceEventRestServiceStub.removeProject.and.returnValue(createNoContentRemoteDataObject$()); scheduler.schedule(() => { comp.removeProject(eventData); @@ -278,8 +278,8 @@ describe('NotificationsBrokerEventsComponent test suite', () => { }); }); - describe('getNotificationsBrokerEvents', () => { - it('should call the "notificationsBrokerEventRestService.getEventsByTopic" to take data and "setEventUpdated" to populate eventData', () => { + describe('getQualityAssuranceEvents', () => { + it('should call the "qualityAssuranceEventRestService.getEventsByTopic" to take data and "setEventUpdated" to populate eventData', () => { comp.paginationConfig = new PaginationComponentOptions(); comp.paginationConfig.currentPage = 1; comp.paginationConfig.pageSize = 20; @@ -297,20 +297,20 @@ describe('NotificationsBrokerEventsComponent test suite', () => { currentPage: comp.paginationConfig.currentPage }); const array = [ - notificationsBrokerEventObjectMissingProjectFound, - notificationsBrokerEventObjectMissingProjectNotFound, + qualityAssuranceEventObjectMissingProjectFound, + qualityAssuranceEventObjectMissingProjectNotFound, ]; const paginatedList = buildPaginatedList(pageInfo, array); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); - notificationsBrokerEventRestServiceStub.getEventsByTopic.and.returnValue(observableOf(paginatedListRD)); + qualityAssuranceEventRestServiceStub.getEventsByTopic.and.returnValue(observableOf(paginatedListRD)); spyOn(compAsAny, 'setEventUpdated'); scheduler.schedule(() => { - compAsAny.getNotificationsBrokerEvents(); + compAsAny.getQualityAssuranceEvents(); }); scheduler.flush(); - expect(compAsAny.notificationsBrokerEventRestService.getEventsByTopic).toHaveBeenCalledWith( + expect(compAsAny.qualityAssuranceEventRestService.getEventsByTopic).toHaveBeenCalledWith( activatedRouteParamsMap.id, options, followLink('target'),followLink('related') diff --git a/src/app/notifications/broker/events/notifications-broker-events.component.ts b/src/app/notifications/qa/events/quality-assurance-events.component.ts similarity index 74% rename from src/app/notifications/broker/events/notifications-broker-events.component.ts rename to src/app/notifications/qa/events/quality-assurance-events.component.ts index 7639554c55d..aa47bfc590f 100644 --- a/src/app/notifications/broker/events/notifications-broker-events.component.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.ts @@ -9,12 +9,11 @@ import { distinctUntilChanged, map, mergeMap, scan, switchMap, take } from 'rxjs import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; -import { FindListOptions } from '../../../core/data/request.models'; import { - NotificationsBrokerEventObject, + QualityAssuranceEventObject, OpenaireBrokerEventMessageObject -} from '../../../core/notifications/broker/models/notifications-broker-event.model'; -import { NotificationsBrokerEventRestService } from '../../../core/notifications/broker/events/notifications-broker-event-rest.service'; +} from '../../../core/notifications/qa/models/quality-assurance-event.model'; +import { QualityAssuranceEventRestService } from '../../../core/notifications/qa/events/quality-assurance-event-rest.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { Metadata } from '../../../core/shared/metadata.utils'; import { followLink } from '../../../shared/utils/follow-link-config.model'; @@ -22,23 +21,24 @@ import { hasValue } from '../../../shared/empty.util'; import { ItemSearchResult } from '../../../shared/object-collection/shared/item-search-result.model'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { - NotificationsBrokerEventData, + QualityAssuranceEventData, ProjectEntryImportModalComponent } from '../project-entry-import-modal/project-entry-import-modal.component'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { Item } from '../../../core/shared/item.model'; +import {FindListOptions} from '../../../core/data/find-list-options.model'; /** - * Component to display the Notifications Broker event list. + * Component to display the Quality Assurance event list. */ @Component({ - selector: 'ds-notifications-broker-events', - templateUrl: './notifications-broker-events.component.html', - styleUrls: ['./notifications-broker-events.scomponent.scss'], + selector: 'ds-quality-assurance-events', + templateUrl: './quality-assurance-events.component.html', + styleUrls: ['./quality-assurance-events.scomponent.scss'], }) -export class NotificationsBrokerEventsComponent implements OnInit { +export class QualityAssuranceEventsComponent implements OnInit { /** * The pagination system configuration for HTML listing. * @type {PaginationComponentOptions} @@ -50,27 +50,27 @@ export class NotificationsBrokerEventsComponent implements OnInit { pageSizeOptions: [5, 10, 20, 40, 60] }); /** - * The Notifications Broker event list sort options. + * The Quality Assurance event list sort options. * @type {SortOptions} */ public paginationSortConfig: SortOptions = new SortOptions('trust', SortDirection.DESC); /** - * Array to save the presence of a project inside an Notifications Broker event. - * @type {NotificationsBrokerEventData[]>} + * Array to save the presence of a project inside an Quality Assurance event. + * @type {QualityAssuranceEventData[]>} */ - public eventsUpdated$: BehaviorSubject = new BehaviorSubject([]); + public eventsUpdated$: BehaviorSubject = new BehaviorSubject([]); /** - * The total number of Notifications Broker events. + * The total number of Quality Assurance events. * @type {Observable} */ public totalElements$: Observable; /** - * The topic of the Notifications Broker events; suitable for displaying. + * The topic of the Quality Assurance events; suitable for displaying. * @type {string} */ public showTopic: string; /** - * The topic of the Notifications Broker events; suitable for HTTP calls. + * The topic of the Quality Assurance events; suitable for HTTP calls. * @type {string} */ public topic: string; @@ -114,7 +114,7 @@ export class NotificationsBrokerEventsComponent implements OnInit { * @param {ActivatedRoute} activatedRoute * @param {NgbModal} modalService * @param {NotificationsService} notificationsService - * @param {NotificationsBrokerEventRestService} notificationsBrokerEventRestService + * @param {QualityAssuranceEventRestService} qualityAssuranceEventRestService * @param {PaginationService} paginationService * @param {TranslateService} translateService */ @@ -122,7 +122,7 @@ export class NotificationsBrokerEventsComponent implements OnInit { private activatedRoute: ActivatedRoute, private modalService: NgbModal, private notificationsService: NotificationsService, - private notificationsBrokerEventRestService: NotificationsBrokerEventRestService, + private qualityAssuranceEventRestService: QualityAssuranceEventRestService, private paginationService: PaginationService, private translateService: TranslateService ) { @@ -142,7 +142,7 @@ export class NotificationsBrokerEventsComponent implements OnInit { this.showTopic = id.replace(regEx, '/'); this.topic = id; this.isEventPageLoading.next(false); - this.getNotificationsBrokerEvents(); + this.getQualityAssuranceEvents(); }); } @@ -162,12 +162,12 @@ export class NotificationsBrokerEventsComponent implements OnInit { * * @param {string} action * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) - * @param {NotificationsBrokerEventData} eventData - * the Notifications Broker event data + * @param {QualityAssuranceEventData} eventData + * the Quality Assurance event data * @param {any} content * Reference to the modal */ - public modalChoice(action: string, eventData: NotificationsBrokerEventData, content: any): void { + public modalChoice(action: string, eventData: QualityAssuranceEventData, content: any): void { if (eventData.hasProject) { this.executeAction(action, eventData); } else { @@ -180,12 +180,12 @@ export class NotificationsBrokerEventsComponent implements OnInit { * * @param {string} action * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) - * @param {NotificationsBrokerEventData} eventData - * the Notifications Broker event data + * @param {QualityAssuranceEventData} eventData + * the Quality Assurance event data * @param {any} content * Reference to the modal */ - public openModal(action: string, eventData: NotificationsBrokerEventData, content: any): void { + public openModal(action: string, eventData: QualityAssuranceEventData, content: any): void { this.modalService.open(content, { ariaLabelledBy: 'modal-basic-title' }).result.then( (result) => { if (result === 'do') { @@ -203,10 +203,10 @@ export class NotificationsBrokerEventsComponent implements OnInit { /** * Open a modal where the user can select the project. * - * @param {NotificationsBrokerEventData} eventData - * the Notifications Broker event item data + * @param {QualityAssuranceEventData} eventData + * the Quality Assurance event item data */ - public openModalLookup(eventData: NotificationsBrokerEventData): void { + public openModalLookup(eventData: QualityAssuranceEventData): void { this.modalRef = this.modalService.open(ProjectEntryImportModalComponent, { size: 'lg' }); @@ -232,19 +232,19 @@ export class NotificationsBrokerEventsComponent implements OnInit { * * @param {string} action * the action (can be: ACCEPTED, REJECTED, DISCARDED, PENDING) - * @param {NotificationsBrokerEventData} eventData - * the Notifications Broker event data + * @param {QualityAssuranceEventData} eventData + * the Quality Assurance event data */ - public executeAction(action: string, eventData: NotificationsBrokerEventData): void { + public executeAction(action: string, eventData: QualityAssuranceEventData): void { eventData.isRunning = true; this.subs.push( - this.notificationsBrokerEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) - .subscribe((rd: RemoteData) => { + this.qualityAssuranceEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { if (rd.isSuccess && rd.statusCode === 200) { this.notificationsService.success( this.translateService.instant('notifications.broker.event.action.saved') ); - this.getNotificationsBrokerEvents(); + this.getQualityAssuranceEvents(); } else { this.notificationsService.error( this.translateService.instant('notifications.broker.event.action.error') @@ -256,10 +256,10 @@ export class NotificationsBrokerEventsComponent implements OnInit { } /** - * Bound a project to the publication described in the Notifications Broker event calling the REST service. + * Bound a project to the publication described in the Quality Assurance event calling the REST service. * - * @param {NotificationsBrokerEventData} eventData - * the Notifications Broker event item data + * @param {QualityAssuranceEventData} eventData + * the Quality Assurance event item data * @param {string} projectId * the project Id to bound * @param {string} projectTitle @@ -267,11 +267,11 @@ export class NotificationsBrokerEventsComponent implements OnInit { * @param {string} projectHandle * the project handle */ - public boundProject(eventData: NotificationsBrokerEventData, projectId: string, projectTitle: string, projectHandle: string): void { + public boundProject(eventData: QualityAssuranceEventData, projectId: string, projectTitle: string, projectHandle: string): void { eventData.isRunning = true; this.subs.push( - this.notificationsBrokerEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) - .subscribe((rd: RemoteData) => { + this.qualityAssuranceEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { if (rd.isSuccess) { this.notificationsService.success( this.translateService.instant('notifications.broker.event.project.bounded') @@ -291,16 +291,16 @@ export class NotificationsBrokerEventsComponent implements OnInit { } /** - * Remove the bounded project from the publication described in the Notifications Broker event calling the REST service. + * Remove the bounded project from the publication described in the Quality Assurance event calling the REST service. * - * @param {NotificationsBrokerEventData} eventData - * the Notifications Broker event data + * @param {QualityAssuranceEventData} eventData + * the Quality Assurance event data */ - public removeProject(eventData: NotificationsBrokerEventData): void { + public removeProject(eventData: QualityAssuranceEventData): void { eventData.isRunning = true; this.subs.push( - this.notificationsBrokerEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) - .subscribe((rd: RemoteData) => { + this.qualityAssuranceEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData) => { if (rd.isSuccess) { this.notificationsService.success( this.translateService.instant('notifications.broker.event.project.removed') @@ -337,26 +337,26 @@ export class NotificationsBrokerEventsComponent implements OnInit { /** - * Dispatch the Notifications Broker events retrival. + * Dispatch the Quality Assurance events retrival. */ - public getNotificationsBrokerEvents(): void { + public getQualityAssuranceEvents(): void { this.paginationService.getFindListOptions(this.paginationConfig.id, this.defaultConfig).pipe( distinctUntilChanged(), - switchMap((options: FindListOptions) => this.notificationsBrokerEventRestService.getEventsByTopic( + switchMap((options: FindListOptions) => this.qualityAssuranceEventRestService.getEventsByTopic( this.topic, options, followLink('target'), followLink('related') )), getFirstCompletedRemoteData(), - ).subscribe((rd: RemoteData>) => { + ).subscribe((rd: RemoteData>) => { if (rd.hasSucceeded) { this.isEventLoading.next(false); this.totalElements$ = observableOf(rd.payload.totalElements); this.setEventUpdated(rd.payload.page); } else { - throw new Error('Can\'t retrieve Notifications Broker events from the Broker events REST service'); + throw new Error('Can\'t retrieve Quality Assurance events from the Broker events REST service'); } - this.notificationsBrokerEventRestService.clearFindByTopicRequests(); + this.qualityAssuranceEventRestService.clearFindByTopicRequests(); }); } @@ -370,15 +370,15 @@ export class NotificationsBrokerEventsComponent implements OnInit { } /** - * Set the project status for the Notifications Broker events. + * Set the project status for the Quality Assurance events. * - * @param {NotificationsBrokerEventObject[]} events - * the Notifications Broker event item + * @param {QualityAssuranceEventObject[]} events + * the Quality Assurance event item */ - protected setEventUpdated(events: NotificationsBrokerEventObject[]): void { + protected setEventUpdated(events: QualityAssuranceEventObject[]): void { this.subs.push( from(events).pipe( - mergeMap((event: NotificationsBrokerEventObject) => { + mergeMap((event: QualityAssuranceEventObject) => { const related$ = event.related.pipe( getFirstCompletedRemoteData(), ); @@ -387,7 +387,7 @@ export class NotificationsBrokerEventsComponent implements OnInit { ); return combineLatest([related$, target$]).pipe( map(([relatedItemRD, targetItemRD]: [RemoteData, RemoteData]) => { - const data: NotificationsBrokerEventData = { + const data: QualityAssuranceEventData = { event: event, id: event.id, title: event.title, diff --git a/src/app/notifications/broker/events/notifications-broker-events.scomponent.scss b/src/app/notifications/qa/events/quality-assurance-events.scomponent.scss similarity index 100% rename from src/app/notifications/broker/events/notifications-broker-events.scomponent.scss rename to src/app/notifications/qa/events/quality-assurance-events.scomponent.scss diff --git a/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.html b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html similarity index 100% rename from src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.html rename to src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html diff --git a/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.scss b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.scss similarity index 100% rename from src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.scss rename to src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.scss diff --git a/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts similarity index 95% rename from src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts rename to src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts index 7cac576844c..42a57c2ac5e 100644 --- a/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.spec.ts +++ b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts @@ -17,16 +17,16 @@ import { buildPaginatedList } from '../../../core/data/paginated-list.model'; import { PageInfo } from '../../../core/shared/page-info.model'; import { ItemMockPid10, - notificationsBrokerEventObjectMissingProjectFound, + qualityAssuranceEventObjectMissingProjectFound, NotificationsMockDspaceObject } from '../../../shared/mocks/notifications.mock'; const eventData = { - event: notificationsBrokerEventObjectMissingProjectFound, - id: notificationsBrokerEventObjectMissingProjectFound.id, - title: notificationsBrokerEventObjectMissingProjectFound.title, + event: qualityAssuranceEventObjectMissingProjectFound, + id: qualityAssuranceEventObjectMissingProjectFound.id, + title: qualityAssuranceEventObjectMissingProjectFound.title, hasProject: true, - projectTitle: notificationsBrokerEventObjectMissingProjectFound.message.title, + projectTitle: qualityAssuranceEventObjectMissingProjectFound.message.title, projectId: ItemMockPid10.id, handle: ItemMockPid10.handle, reason: null, diff --git a/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.ts b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts similarity index 94% rename from src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.ts rename to src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts index 64672fa1fac..64a5f6908fe 100644 --- a/src/app/notifications/broker/project-entry-import-modal/project-entry-import-modal.component.ts +++ b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts @@ -13,10 +13,10 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio import { SearchService } from '../../../core/shared/search/search.service'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { - NotificationsBrokerEventObject, - NotificationsBrokerEventMessageObject, + QualityAssuranceEventObject, + QualityAssuranceEventMessageObject, OpenaireBrokerEventMessageObject, -} from '../../../core/notifications/broker/models/notifications-broker-event.model'; +} from '../../../core/notifications/qa/models/quality-assurance-event.model'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; import { Item } from '../../../core/shared/item.model'; @@ -34,13 +34,13 @@ export enum ImportType { /** * The data type passed from the parent page */ -export interface NotificationsBrokerEventData { +export interface QualityAssuranceEventData { /** - * The Notifications Broker event + * The Quality Assurance event */ - event: NotificationsBrokerEventObject; + event: QualityAssuranceEventObject; /** - * The Notifications Broker event Id (uuid) + * The Quality Assurance event Id (uuid) */ id: string; /** @@ -83,14 +83,14 @@ export interface NotificationsBrokerEventData { templateUrl: './project-entry-import-modal.component.html' }) /** - * Component to display a modal window for linking a project to an Notifications Broker event + * Component to display a modal window for linking a project to an Quality Assurance event * Shows information about the selected project and a selectable list. */ export class ProjectEntryImportModalComponent implements OnInit { /** * The external source entry */ - @Input() externalSourceEntry: NotificationsBrokerEventData; + @Input() externalSourceEntry: QualityAssuranceEventData; /** * The number of results per page */ diff --git a/src/app/notifications/broker/source/notifications-broker-source.actions.ts b/src/app/notifications/qa/source/quality-assurance-source.actions.ts similarity index 62% rename from src/app/notifications/broker/source/notifications-broker-source.actions.ts rename to src/app/notifications/qa/source/quality-assurance-source.actions.ts index a3fd9240c81..7a22e7a9ae9 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.actions.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.actions.ts @@ -1,6 +1,6 @@ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; /** * For each action type in an action group, make a simple @@ -10,19 +10,19 @@ import { NotificationsBrokerSourceObject } from '../../../core/notifications/bro * literal types and runs a simple check to guarantee all * action types in the application are unique. */ -export const NotificationsBrokerSourceActionTypes = { - ADD_SOURCE: type('dspace/integration/notifications/broker/ADD_SOURCE'), - RETRIEVE_ALL_SOURCE: type('dspace/integration/notifications/broker/RETRIEVE_ALL_SOURCE'), - RETRIEVE_ALL_SOURCE_ERROR: type('dspace/integration/notifications/broker/RETRIEVE_ALL_SOURCE_ERROR'), +export const QualityAssuranceSourceActionTypes = { + ADD_SOURCE: type('dspace/integration/notifications/qa/ADD_SOURCE'), + RETRIEVE_ALL_SOURCE: type('dspace/integration/notifications/qa/RETRIEVE_ALL_SOURCE'), + RETRIEVE_ALL_SOURCE_ERROR: type('dspace/integration/notifications/qa/RETRIEVE_ALL_SOURCE_ERROR'), }; /* tslint:disable:max-classes-per-file */ /** - * An ngrx action to retrieve all the Notifications Broker source. + * An ngrx action to retrieve all the Quality Assurance source. */ export class RetrieveAllSourceAction implements Action { - type = NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE; + type = QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE; payload: { elementsPerPage: number; currentPage: number; @@ -45,20 +45,20 @@ export class RetrieveAllSourceAction implements Action { } /** - * An ngrx action for retrieving 'all Notifications Broker source' error. + * An ngrx action for retrieving 'all Quality Assurance source' error. */ export class RetrieveAllSourceErrorAction implements Action { - type = NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR; + type = QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR; } /** - * An ngrx action to load the Notifications Broker source objects. + * An ngrx action to load the Quality Assurance source objects. * Called by the ??? effect. */ export class AddSourceAction implements Action { - type = NotificationsBrokerSourceActionTypes.ADD_SOURCE; + type = QualityAssuranceSourceActionTypes.ADD_SOURCE; payload: { - source: NotificationsBrokerSourceObject[]; + source: QualityAssuranceSourceObject[]; totalPages: number; currentPage: number; totalElements: number; @@ -74,9 +74,9 @@ export class AddSourceAction implements Action { * @param currentPage * the current page * @param totalElements - * the total available Notifications Broker source + * the total available Quality Assurance source */ - constructor(source: NotificationsBrokerSourceObject[], totalPages: number, currentPage: number, totalElements: number) { + constructor(source: QualityAssuranceSourceObject[], totalPages: number, currentPage: number, totalElements: number) { this.payload = { source, totalPages, @@ -93,7 +93,7 @@ export class AddSourceAction implements Action { * Export a type alias of all actions in this action group * so that reducers can easily compose action types. */ -export type NotificationsBrokerSourceActions +export type QualityAssuranceSourceActions = RetrieveAllSourceAction |RetrieveAllSourceErrorAction |AddSourceAction; diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.html b/src/app/notifications/qa/source/quality-assurance-source.component.html similarity index 97% rename from src/app/notifications/broker/source/notifications-broker-source.component.html rename to src/app/notifications/qa/source/quality-assurance-source.component.html index a7e1e527483..5309098c555 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.component.html +++ b/src/app/notifications/qa/source/quality-assurance-source.component.html @@ -8,15 +8,15 @@

{{'notifications.broker.title'| translate}}

{{'notifications.broker.source'| translate}}

- + - + (paginationChange)="getQualityAssuranceSource()"> +
- + diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.scss b/src/app/notifications/qa/source/quality-assurance-source.component.scss similarity index 100% rename from src/app/notifications/broker/source/notifications-broker-source.component.scss rename to src/app/notifications/qa/source/quality-assurance-source.component.scss diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts b/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts similarity index 60% rename from src/app/notifications/broker/source/notifications-broker-source.component.spec.ts rename to src/app/notifications/qa/source/quality-assurance-source.component.spec.ts index 6c0ad42ce8a..ba3a903cc5e 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.component.spec.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts @@ -7,22 +7,22 @@ import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/t import { createTestComponent } from '../../../shared/testing/utils.test'; import { getMockNotificationsStateService, - notificationsBrokerSourceObjectMoreAbstract, - notificationsBrokerSourceObjectMorePid + qualityAssuranceSourceObjectMoreAbstract, + qualityAssuranceSourceObjectMorePid } from '../../../shared/mocks/notifications.mock'; -import { NotificationsBrokerSourceComponent } from './notifications-broker-source.component'; +import { QualityAssuranceSourceComponent } from './quality-assurance-source.component'; import { NotificationsStateService } from '../../notifications-state.service'; import { cold } from 'jasmine-marbles'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; -describe('NotificationsBrokerSourceComponent test suite', () => { - let fixture: ComponentFixture; - let comp: NotificationsBrokerSourceComponent; +describe('QualityAssuranceSourceComponent test suite', () => { + let fixture: ComponentFixture; + let comp: QualityAssuranceSourceComponent; let compAsAny: any; const mockNotificationsStateService = getMockNotificationsStateService(); const activatedRouteParams = { - notificationsBrokerSourceParams: { + qualityAssuranceSourceParams: { currentPage: 0, pageSize: 5 } @@ -36,27 +36,27 @@ describe('NotificationsBrokerSourceComponent test suite', () => { TranslateModule.forRoot(), ], declarations: [ - NotificationsBrokerSourceComponent, + QualityAssuranceSourceComponent, TestComponent, ], providers: [ { provide: NotificationsStateService, useValue: mockNotificationsStateService }, { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), params: observableOf({}) } }, { provide: PaginationService, useValue: paginationService }, - NotificationsBrokerSourceComponent + QualityAssuranceSourceComponent ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(() => { - mockNotificationsStateService.getNotificationsBrokerSource.and.returnValue(observableOf([ - notificationsBrokerSourceObjectMorePid, - notificationsBrokerSourceObjectMoreAbstract + mockNotificationsStateService.getQualityAssuranceSource.and.returnValue(observableOf([ + qualityAssuranceSourceObjectMorePid, + qualityAssuranceSourceObjectMoreAbstract ])); - mockNotificationsStateService.getNotificationsBrokerSourceTotalPages.and.returnValue(observableOf(1)); - mockNotificationsStateService.getNotificationsBrokerSourceCurrentPage.and.returnValue(observableOf(0)); - mockNotificationsStateService.getNotificationsBrokerSourceTotals.and.returnValue(observableOf(2)); - mockNotificationsStateService.isNotificationsBrokerSourceLoaded.and.returnValue(observableOf(true)); - mockNotificationsStateService.isNotificationsBrokerSourceLoading.and.returnValue(observableOf(false)); - mockNotificationsStateService.isNotificationsBrokerSourceProcessing.and.returnValue(observableOf(false)); + mockNotificationsStateService.getQualityAssuranceSourceTotalPages.and.returnValue(observableOf(1)); + mockNotificationsStateService.getQualityAssuranceSourceCurrentPage.and.returnValue(observableOf(0)); + mockNotificationsStateService.getQualityAssuranceSourceTotals.and.returnValue(observableOf(2)); + mockNotificationsStateService.isQualityAssuranceSourceLoaded.and.returnValue(observableOf(true)); + mockNotificationsStateService.isQualityAssuranceSourceLoading.and.returnValue(observableOf(false)); + mockNotificationsStateService.isQualityAssuranceSourceProcessing.and.returnValue(observableOf(false)); }); })); @@ -68,7 +68,7 @@ describe('NotificationsBrokerSourceComponent test suite', () => { // synchronous beforeEach beforeEach(() => { const html = ` - `; + `; testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; }); @@ -77,14 +77,14 @@ describe('NotificationsBrokerSourceComponent test suite', () => { testFixture.destroy(); }); - it('should create NotificationsBrokerSourceComponent', inject([NotificationsBrokerSourceComponent], (app: NotificationsBrokerSourceComponent) => { + it('should create QualityAssuranceSourceComponent', inject([QualityAssuranceSourceComponent], (app: QualityAssuranceSourceComponent) => { expect(app).toBeDefined(); })); }); describe('Main tests running with two Source', () => { beforeEach(() => { - fixture = TestBed.createComponent(NotificationsBrokerSourceComponent); + fixture = TestBed.createComponent(QualityAssuranceSourceComponent); comp = fixture.componentInstance; compAsAny = comp; @@ -102,8 +102,8 @@ describe('NotificationsBrokerSourceComponent test suite', () => { expect(comp.sources$).toBeObservable(cold('(a|)', { a: [ - notificationsBrokerSourceObjectMorePid, - notificationsBrokerSourceObjectMoreAbstract + qualityAssuranceSourceObjectMorePid, + qualityAssuranceSourceObjectMoreAbstract ] })); expect(comp.totalElements$).toBeObservable(cold('(a|)', { @@ -112,12 +112,12 @@ describe('NotificationsBrokerSourceComponent test suite', () => { }); it(('Should set data properly after the view init'), () => { - spyOn(compAsAny, 'getNotificationsBrokerSource'); + spyOn(compAsAny, 'getQualityAssuranceSource'); comp.ngAfterViewInit(); fixture.detectChanges(); - expect(compAsAny.getNotificationsBrokerSource).toHaveBeenCalled(); + expect(compAsAny.getQualityAssuranceSource).toHaveBeenCalled(); }); it(('isSourceLoading should return FALSE'), () => { @@ -132,12 +132,12 @@ describe('NotificationsBrokerSourceComponent test suite', () => { })); }); - it(('getNotificationsBrokerSource should call the service to dispatch a STATE change'), () => { + it(('getQualityAssuranceSource should call the service to dispatch a STATE change'), () => { comp.ngOnInit(); fixture.detectChanges(); - compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerSource(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage).and.callThrough(); - expect(compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerSource).toHaveBeenCalledWith(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage); + compAsAny.notificationsStateService.dispatchRetrieveQualityAssuranceSource(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage).and.callThrough(); + expect(compAsAny.notificationsStateService.dispatchRetrieveQualityAssuranceSource).toHaveBeenCalledWith(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage); }); }); }); diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.ts b/src/app/notifications/qa/source/quality-assurance-source.component.ts similarity index 64% rename from src/app/notifications/broker/source/notifications-broker-source.component.ts rename to src/app/notifications/qa/source/quality-assurance-source.component.ts index 070e03f396f..fde1afec436 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.component.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.component.ts @@ -3,18 +3,18 @@ import { PaginationService } from '../../../core/pagination/pagination.service'; import { Observable, Subscription } from 'rxjs'; import { distinctUntilChanged, take } from 'rxjs/operators'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; -import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { NotificationsStateService } from '../../notifications-state.service'; -import { AdminNotificationsBrokerSourcePageParams } from '../../../admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-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'; @Component({ - selector: 'ds-notifications-broker-source', - templateUrl: './notifications-broker-source.component.html', - styleUrls: ['./notifications-broker-source.component.scss'] + selector: 'ds-quality-assurance-source', + templateUrl: './quality-assurance-source.component.html', + styleUrls: ['./quality-assurance-source.component.scss'] }) -export class NotificationsBrokerSourceComponent implements OnInit { +export class QualityAssuranceSourceComponent implements OnInit { /** * The pagination system configuration for HTML listing. @@ -26,16 +26,16 @@ export class NotificationsBrokerSourceComponent implements OnInit { pageSizeOptions: [5, 10, 20, 40, 60] }); /** - * The Notifications Broker source list sort options. + * The Quality Assurance source list sort options. * @type {SortOptions} */ public paginationSortConfig: SortOptions; /** - * The Notifications Broker source list. + * The Quality Assurance source list. */ - public sources$: Observable; + public sources$: Observable; /** - * The total number of Notifications Broker sources. + * The total number of Quality Assurance sources. */ public totalElements$: Observable; /** @@ -58,51 +58,51 @@ export class NotificationsBrokerSourceComponent implements OnInit { * Component initialization. */ ngOnInit(): void { - this.sources$ = this.notificationsStateService.getNotificationsBrokerSource(); - this.totalElements$ = this.notificationsStateService.getNotificationsBrokerSourceTotals(); + this.sources$ = this.notificationsStateService.getQualityAssuranceSource(); + this.totalElements$ = this.notificationsStateService.getQualityAssuranceSourceTotals(); } /** - * First Notifications Broker source loading after view initialization. + * First Quality Assurance source loading after view initialization. */ ngAfterViewInit(): void { this.subs.push( - this.notificationsStateService.isNotificationsBrokerSourceLoaded().pipe( + this.notificationsStateService.isQualityAssuranceSourceLoaded().pipe( take(1) ).subscribe(() => { - this.getNotificationsBrokerSource(); + this.getQualityAssuranceSource(); }) ); } /** - * Returns the information about the loading status of the Notifications Broker source (if it's running or not). + * Returns the information about the loading status of the Quality Assurance source (if it's running or not). * * @return Observable * 'true' if the source are loading, 'false' otherwise. */ public isSourceLoading(): Observable { - return this.notificationsStateService.isNotificationsBrokerSourceLoading(); + return this.notificationsStateService.isQualityAssuranceSourceLoading(); } /** - * Returns the information about the processing status of the Notifications Broker source (if it's running or not). + * Returns the information about the processing status of the Quality Assurance source (if it's running or not). * * @return Observable * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. */ public isSourceProcessing(): Observable { - return this.notificationsStateService.isNotificationsBrokerSourceProcessing(); + return this.notificationsStateService.isQualityAssuranceSourceProcessing(); } /** - * Dispatch the Notifications Broker source retrival. + * Dispatch the Quality Assurance source retrival. */ - public getNotificationsBrokerSource(): void { + public getQualityAssuranceSource(): void { this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe( distinctUntilChanged(), ).subscribe((options: PaginationComponentOptions) => { - this.notificationsStateService.dispatchRetrieveNotificationsBrokerSource( + this.notificationsStateService.dispatchRetrieveQualityAssuranceSource( options.pageSize, options.currentPage ); @@ -114,7 +114,7 @@ export class NotificationsBrokerSourceComponent implements OnInit { * * @param eventsRouteParams */ - protected updatePaginationFromRouteParams(eventsRouteParams: AdminNotificationsBrokerSourcePageParams) { + protected updatePaginationFromRouteParams(eventsRouteParams: AdminQualityAssuranceSourcePageParams) { if (eventsRouteParams.currentPage) { this.paginationConfig.currentPage = eventsRouteParams.currentPage; } diff --git a/src/app/notifications/broker/source/notifications-broker-source.effects.ts b/src/app/notifications/qa/source/quality-assurance-source.effects.ts similarity index 59% rename from src/app/notifications/broker/source/notifications-broker-source.effects.ts rename to src/app/notifications/qa/source/quality-assurance-source.effects.ts index bd8b3f00cd9..6d8aa275d53 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.effects.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.effects.ts @@ -6,35 +6,35 @@ import { catchError, map, switchMap, tap, withLatestFrom } from 'rxjs/operators' import { of as observableOf } from 'rxjs'; import { AddSourceAction, - NotificationsBrokerSourceActionTypes, + QualityAssuranceSourceActionTypes, RetrieveAllSourceAction, RetrieveAllSourceErrorAction, -} from './notifications-broker-source.actions'; +} from './quality-assurance-source.actions'; -import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; -import { NotificationsBrokerSourceService } from './notifications-broker-source.service'; +import { QualityAssuranceSourceService } from './quality-assurance-source.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; -import { NotificationsBrokerSourceRestService } from '../../../core/notifications/broker/source/notifications-broker-source-rest.service'; +import { QualityAssuranceSourceRestService } from '../../../core/notifications/qa/source/quality-assurance-source-rest.service'; /** - * Provides effect methods for the Notifications Broker source actions. + * Provides effect methods for the Quality Assurance source actions. */ @Injectable() -export class NotificationsBrokerSourceEffects { +export class QualityAssuranceSourceEffects { /** - * Retrieve all Notifications Broker source managing pagination and errors. + * Retrieve all Quality Assurance source managing pagination and errors. */ @Effect() retrieveAllSource$ = this.actions$.pipe( - ofType(NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE), + ofType(QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE), withLatestFrom(this.store$), switchMap(([action, currentState]: [RetrieveAllSourceAction, any]) => { - return this.notificationsBrokerSourceService.getSources( + return this.qualityAssuranceSourceService.getSources( action.payload.elementsPerPage, action.payload.currentPage ).pipe( - map((sources: PaginatedList) => + map((sources: PaginatedList) => new AddSourceAction(sources.page, sources.totalPages, sources.currentPage, sources.totalElements) ), catchError((error: Error) => { @@ -51,7 +51,7 @@ export class NotificationsBrokerSourceEffects { * Show a notification on error. */ @Effect({ dispatch: false }) retrieveAllSourceErrorAction$ = this.actions$.pipe( - ofType(NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR), + ofType(QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR), tap(() => { this.notificationsService.error(null, this.translate.get('notifications.broker.source.error.service.retrieve')); }) @@ -61,9 +61,9 @@ export class NotificationsBrokerSourceEffects { * Clear find all source requests from cache. */ @Effect({ dispatch: false }) addSourceAction$ = this.actions$.pipe( - ofType(NotificationsBrokerSourceActionTypes.ADD_SOURCE), + ofType(QualityAssuranceSourceActionTypes.ADD_SOURCE), tap(() => { - this.notificationsBrokerSourceDataService.clearFindAllSourceRequests(); + this.qualityAssuranceSourceDataService.clearFindAllSourceRequests(); }) ); @@ -73,15 +73,15 @@ export class NotificationsBrokerSourceEffects { * @param {Store} store$ * @param {TranslateService} translate * @param {NotificationsService} notificationsService - * @param {NotificationsBrokerSourceService} notificationsBrokerSourceService - * @param {NotificationsBrokerSourceRestService} notificationsBrokerSourceDataService + * @param {QualityAssuranceSourceService} qualityAssuranceSourceService + * @param {QualityAssuranceSourceRestService} qualityAssuranceSourceDataService */ constructor( private actions$: Actions, private store$: Store, private translate: TranslateService, private notificationsService: NotificationsService, - private notificationsBrokerSourceService: NotificationsBrokerSourceService, - private notificationsBrokerSourceDataService: NotificationsBrokerSourceRestService + private qualityAssuranceSourceService: QualityAssuranceSourceService, + private qualityAssuranceSourceDataService: QualityAssuranceSourceRestService ) { } } diff --git a/src/app/notifications/broker/source/notifications-broker-source.reducer.spec.ts b/src/app/notifications/qa/source/quality-assurance-source.reducer.spec.ts similarity index 52% rename from src/app/notifications/broker/source/notifications-broker-source.reducer.spec.ts rename to src/app/notifications/qa/source/quality-assurance-source.reducer.spec.ts index 74bc77d3ec4..fcb717067d5 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.reducer.spec.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.reducer.spec.ts @@ -2,20 +2,20 @@ import { AddSourceAction, RetrieveAllSourceAction, RetrieveAllSourceErrorAction - } from './notifications-broker-source.actions'; - import { notificationsBrokerSourceReducer, NotificationsBrokerSourceState } from './notifications-broker-source.reducer'; + } from './quality-assurance-source.actions'; + import { qualityAssuranceSourceReducer, QualityAssuranceSourceState } from './quality-assurance-source.reducer'; import { - notificationsBrokerSourceObjectMoreAbstract, - notificationsBrokerSourceObjectMorePid + qualityAssuranceSourceObjectMoreAbstract, + qualityAssuranceSourceObjectMorePid } from '../../../shared/mocks/notifications.mock'; - describe('notificationsBrokerSourceReducer test suite', () => { - let notificationsBrokerSourceInitialState: NotificationsBrokerSourceState; + describe('qualityAssuranceSourceReducer test suite', () => { + let qualityAssuranceSourceInitialState: QualityAssuranceSourceState; const elementPerPage = 3; const currentPage = 0; beforeEach(() => { - notificationsBrokerSourceInitialState = { + qualityAssuranceSourceInitialState = { source: [], processing: false, loaded: false, @@ -26,30 +26,30 @@ import { }); it('Action RETRIEVE_ALL_SOURCE should set the State property "processing" to TRUE', () => { - const expectedState = notificationsBrokerSourceInitialState; + const expectedState = qualityAssuranceSourceInitialState; expectedState.processing = true; const action = new RetrieveAllSourceAction(elementPerPage, currentPage); - const newState = notificationsBrokerSourceReducer(notificationsBrokerSourceInitialState, action); + const newState = qualityAssuranceSourceReducer(qualityAssuranceSourceInitialState, action); expect(newState).toEqual(expectedState); }); it('Action RETRIEVE_ALL_SOURCE_ERROR should change the State to initial State but processing, loaded, and currentPage', () => { - const expectedState = notificationsBrokerSourceInitialState; + const expectedState = qualityAssuranceSourceInitialState; expectedState.processing = false; expectedState.loaded = true; expectedState.currentPage = 0; const action = new RetrieveAllSourceErrorAction(); - const newState = notificationsBrokerSourceReducer(notificationsBrokerSourceInitialState, action); + const newState = qualityAssuranceSourceReducer(qualityAssuranceSourceInitialState, action); expect(newState).toEqual(expectedState); }); - it('Action ADD_SOURCE should populate the State with Notifications Broker source', () => { + it('Action ADD_SOURCE should populate the State with Quality Assurance source', () => { const expectedState = { - source: [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ], + source: [ qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract ], processing: false, loaded: true, totalPages: 1, @@ -58,10 +58,10 @@ import { }; const action = new AddSourceAction( - [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ], + [ qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract ], 1, 0, 2 ); - const newState = notificationsBrokerSourceReducer(notificationsBrokerSourceInitialState, action); + const newState = qualityAssuranceSourceReducer(qualityAssuranceSourceInitialState, action); expect(newState).toEqual(expectedState); }); diff --git a/src/app/notifications/qa/source/quality-assurance-source.reducer.ts b/src/app/notifications/qa/source/quality-assurance-source.reducer.ts new file mode 100644 index 00000000000..08e26a177ac --- /dev/null +++ b/src/app/notifications/qa/source/quality-assurance-source.reducer.ts @@ -0,0 +1,72 @@ +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceActionTypes, QualityAssuranceSourceActions } from './quality-assurance-source.actions'; + +/** + * The interface representing the Quality Assurance source state. + */ +export interface QualityAssuranceSourceState { + source: QualityAssuranceSourceObject[]; + processing: boolean; + loaded: boolean; + totalPages: number; + currentPage: number; + totalElements: number; +} + +/** + * Used for the Quality Assurance source state initialization. + */ +const qualityAssuranceSourceInitialState: QualityAssuranceSourceState = { + source: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0 +}; + +/** + * The Quality Assurance Source Reducer + * + * @param state + * the current state initialized with qualityAssuranceSourceInitialState + * @param action + * the action to perform on the state + * @return QualityAssuranceSourceState + * the new state + */ +export function qualityAssuranceSourceReducer(state = qualityAssuranceSourceInitialState, action: QualityAssuranceSourceActions): QualityAssuranceSourceState { + switch (action.type) { + case QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE: { + return Object.assign({}, state, { + source: [], + processing: true + }); + } + + case QualityAssuranceSourceActionTypes.ADD_SOURCE: { + return Object.assign({}, state, { + source: action.payload.source, + processing: false, + loaded: true, + totalPages: action.payload.totalPages, + currentPage: state.currentPage, + totalElements: action.payload.totalElements + }); + } + + case QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR: { + return Object.assign({}, state, { + processing: false, + loaded: true, + totalPages: 0, + currentPage: 0, + totalElements: 0 + }); + } + + default: { + return state; + } + } +} diff --git a/src/app/notifications/broker/source/notifications-broker-source.service.spec.ts b/src/app/notifications/qa/source/quality-assurance-source.service.spec.ts similarity index 56% rename from src/app/notifications/broker/source/notifications-broker-source.service.spec.ts rename to src/app/notifications/qa/source/quality-assurance-source.service.spec.ts index e94804cbf68..06f020be1d2 100644 --- a/src/app/notifications/broker/source/notifications-broker-source.service.spec.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.service.spec.ts @@ -1,28 +1,28 @@ import { TestBed } from '@angular/core/testing'; import { of as observableOf } from 'rxjs'; -import { NotificationsBrokerSourceService } from './notifications-broker-source.service'; +import { QualityAssuranceSourceService } from './quality-assurance-source.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { PageInfo } from '../../../core/shared/page-info.model'; -import { FindListOptions } from '../../../core/data/request.models'; import { - getMockNotificationsBrokerSourceRestService, - notificationsBrokerSourceObjectMoreAbstract, - notificationsBrokerSourceObjectMorePid + getMockQualityAssuranceSourceRestService, + qualityAssuranceSourceObjectMoreAbstract, + qualityAssuranceSourceObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; import { cold } from 'jasmine-marbles'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; -import { NotificationsBrokerSourceRestService } from '../../../core/notifications/broker/source/notifications-broker-source-rest.service'; +import { QualityAssuranceSourceRestService } from '../../../core/notifications/qa/source/quality-assurance-source-rest.service'; import { RequestParam } from '../../../core/cache/models/request-param.model'; +import {FindListOptions} from '../../../core/data/find-list-options.model'; -describe('NotificationsBrokerSourceService', () => { - let service: NotificationsBrokerSourceService; - let restService: NotificationsBrokerSourceRestService; +describe('QualityAssuranceSourceService', () => { + let service: QualityAssuranceSourceService; + let restService: QualityAssuranceSourceRestService; let serviceAsAny: any; let restServiceAsAny: any; const pageInfo = new PageInfo(); - const array = [ notificationsBrokerSourceObjectMorePid, notificationsBrokerSourceObjectMoreAbstract ]; + const array = [ qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); const elementsPerPage = 3; @@ -31,22 +31,22 @@ describe('NotificationsBrokerSourceService', () => { beforeEach(async () => { TestBed.configureTestingModule({ providers: [ - { provide: NotificationsBrokerSourceRestService, useClass: getMockNotificationsBrokerSourceRestService }, - { provide: NotificationsBrokerSourceService, useValue: service } + { provide: QualityAssuranceSourceRestService, useClass: getMockQualityAssuranceSourceRestService }, + { provide: QualityAssuranceSourceService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { - restService = TestBed.get(NotificationsBrokerSourceRestService); + restService = TestBed.get(QualityAssuranceSourceRestService); restServiceAsAny = restService; restServiceAsAny.getSources.and.returnValue(observableOf(paginatedListRD)); - service = new NotificationsBrokerSourceService(restService); + service = new QualityAssuranceSourceService(restService); serviceAsAny = service; }); describe('getSources', () => { - it('Should proxy the call to notificationsBrokerSourceRestService.getSources', () => { + it('Should proxy the call to qualityAssuranceSourceRestService.getSources', () => { const sortOptions = new SortOptions('name', SortDirection.ASC); const findListOptions: FindListOptions = { elementsPerPage: elementsPerPage, @@ -54,10 +54,10 @@ describe('NotificationsBrokerSourceService', () => { sort: sortOptions }; const result = service.getSources(elementsPerPage, currentPage); - expect((service as any).notificationsBrokerSourceRestService.getSources).toHaveBeenCalledWith(findListOptions); + expect((service as any).qualityAssuranceSourceRestService.getSources).toHaveBeenCalledWith(findListOptions); }); - it('Should return a paginated list of Notifications Broker Source', () => { + it('Should return a paginated list of Quality Assurance Source', () => { const expected = cold('(a|)', { a: paginatedList }); diff --git a/src/app/notifications/qa/source/quality-assurance-source.service.ts b/src/app/notifications/qa/source/quality-assurance-source.service.ts new file mode 100644 index 00000000000..30a889d3e2f --- /dev/null +++ b/src/app/notifications/qa/source/quality-assurance-source.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { find, map } from 'rxjs/operators'; +import { QualityAssuranceSourceRestService } from '../../../core/notifications/qa/source/quality-assurance-source-rest.service'; +import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; +import { RemoteData } from '../../../core/data/remote-data'; +import { PaginatedList } from '../../../core/data/paginated-list.model'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; +import {FindListOptions} from '../../../core/data/find-list-options.model'; + +/** + * The service handling all Quality Assurance source requests to the REST service. + */ +@Injectable() +export class QualityAssuranceSourceService { + + /** + * Initialize the service variables. + * @param {QualityAssuranceSourceRestService} qualityAssuranceSourceRestService + */ + constructor( + private qualityAssuranceSourceRestService: QualityAssuranceSourceRestService + ) { } + + /** + * Return the list of Quality Assurance source managing pagination and errors. + * + * @param elementsPerPage + * The number of the source per page + * @param currentPage + * The page number to retrieve + * @return Observable> + * The list of Quality Assurance source. + */ + public getSources(elementsPerPage, currentPage): Observable> { + const sortOptions = new SortOptions('name', SortDirection.ASC); + + const findListOptions: FindListOptions = { + elementsPerPage: elementsPerPage, + currentPage: currentPage, + sort: sortOptions + }; + + return this.qualityAssuranceSourceRestService.getSources(findListOptions).pipe( + find((rd: RemoteData>) => !rd.isResponsePending), + map((rd: RemoteData>) => { + if (rd.hasSucceeded) { + return rd.payload; + } else { + throw new Error('Can\'t retrieve Quality Assurance source from the Broker source REST service'); + } + }) + ); + } +} diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.actions.ts b/src/app/notifications/qa/topics/quality-assurance-topics.actions.ts similarity index 62% rename from src/app/notifications/broker/topics/notifications-broker-topics.actions.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.actions.ts index 622ecc81414..0506806587d 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.actions.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.actions.ts @@ -1,6 +1,6 @@ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; /** * For each action type in an action group, make a simple @@ -10,19 +10,19 @@ import { NotificationsBrokerTopicObject } from '../../../core/notifications/brok * literal types and runs a simple check to guarantee all * action types in the application are unique. */ -export const NotificationsBrokerTopicActionTypes = { - ADD_TOPICS: type('dspace/integration/notifications/broker/topic/ADD_TOPICS'), - RETRIEVE_ALL_TOPICS: type('dspace/integration/notifications/broker/topic/RETRIEVE_ALL_TOPICS'), - RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/notifications/broker/topic/RETRIEVE_ALL_TOPICS_ERROR'), +export const QualityAssuranceTopicActionTypes = { + ADD_TOPICS: type('dspace/integration/notifications/qa/topic/ADD_TOPICS'), + RETRIEVE_ALL_TOPICS: type('dspace/integration/notifications/qa/topic/RETRIEVE_ALL_TOPICS'), + RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/notifications/qa/topic/RETRIEVE_ALL_TOPICS_ERROR'), }; /* tslint:disable:max-classes-per-file */ /** - * An ngrx action to retrieve all the Notifications Broker topics. + * An ngrx action to retrieve all the Quality Assurance topics. */ export class RetrieveAllTopicsAction implements Action { - type = NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS; + type = QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS; payload: { elementsPerPage: number; currentPage: number; @@ -45,20 +45,20 @@ export class RetrieveAllTopicsAction implements Action { } /** - * An ngrx action for retrieving 'all Notifications Broker topics' error. + * An ngrx action for retrieving 'all Quality Assurance topics' error. */ export class RetrieveAllTopicsErrorAction implements Action { - type = NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR; + type = QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR; } /** - * An ngrx action to load the Notifications Broker topic objects. + * An ngrx action to load the Quality Assurance topic objects. * Called by the ??? effect. */ export class AddTopicsAction implements Action { - type = NotificationsBrokerTopicActionTypes.ADD_TOPICS; + type = QualityAssuranceTopicActionTypes.ADD_TOPICS; payload: { - topics: NotificationsBrokerTopicObject[]; + topics: QualityAssuranceTopicObject[]; totalPages: number; currentPage: number; totalElements: number; @@ -74,9 +74,9 @@ export class AddTopicsAction implements Action { * @param currentPage * the current page * @param totalElements - * the total available Notifications Broker topics + * the total available Quality Assurance topics */ - constructor(topics: NotificationsBrokerTopicObject[], totalPages: number, currentPage: number, totalElements: number) { + constructor(topics: QualityAssuranceTopicObject[], totalPages: number, currentPage: number, totalElements: number) { this.payload = { topics, totalPages, @@ -93,7 +93,7 @@ export class AddTopicsAction implements Action { * Export a type alias of all actions in this action group * so that reducers can easily compose action types. */ -export type NotificationsBrokerTopicsActions +export type QualityAssuranceTopicsActions = AddTopicsAction |RetrieveAllTopicsAction |RetrieveAllTopicsErrorAction; diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.html b/src/app/notifications/qa/topics/quality-assurance-topics.component.html similarity index 97% rename from src/app/notifications/broker/topics/notifications-broker-topics.component.html rename to src/app/notifications/qa/topics/quality-assurance-topics.component.html index 8b27778ee94..b563a355f57 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.component.html +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.html @@ -15,7 +15,7 @@

{{'notifications.broker.topics'| translate}}

[collectionSize]="(totalElements$ | async)" [hideGear]="false" [hideSortOptions]="true" - (paginationChange)="getNotificationsBrokerTopics()"> + (paginationChange)="getQualityAssuranceTopics()"> diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.scss b/src/app/notifications/qa/topics/quality-assurance-topics.component.scss similarity index 100% rename from src/app/notifications/broker/topics/notifications-broker-topics.component.scss rename to src/app/notifications/qa/topics/quality-assurance-topics.component.scss diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts b/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts similarity index 59% rename from src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts index dbb81373211..8e154eca990 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts @@ -7,23 +7,23 @@ import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/t import { createTestComponent } from '../../../shared/testing/utils.test'; import { getMockNotificationsStateService, - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMorePid + qualityAssuranceTopicObjectMoreAbstract, + qualityAssuranceTopicObjectMorePid } from '../../../shared/mocks/notifications.mock'; -import { NotificationsBrokerTopicsComponent } from './notifications-broker-topics.component'; +import { QualityAssuranceTopicsComponent } from './quality-assurance-topics.component'; import { NotificationsStateService } from '../../notifications-state.service'; import { cold } from 'jasmine-marbles'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; -import { NotificationsBrokerTopicsService } from './notifications-broker-topics.service'; +import { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; -describe('NotificationsBrokerTopicsComponent test suite', () => { - let fixture: ComponentFixture; - let comp: NotificationsBrokerTopicsComponent; +describe('QualityAssuranceTopicsComponent test suite', () => { + let fixture: ComponentFixture; + let comp: QualityAssuranceTopicsComponent; let compAsAny: any; const mockNotificationsStateService = getMockNotificationsStateService(); const activatedRouteParams = { - notificationsBrokerTopicsParams: { + qualityAssuranceTopicsParams: { currentPage: 0, pageSize: 5 } @@ -37,7 +37,7 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { TranslateModule.forRoot(), ], declarations: [ - NotificationsBrokerTopicsComponent, + QualityAssuranceTopicsComponent, TestComponent, ], providers: [ @@ -48,22 +48,22 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { }, }}}, { provide: PaginationService, useValue: paginationService }, - NotificationsBrokerTopicsComponent, + QualityAssuranceTopicsComponent, // tslint:disable-next-line: no-empty - { provide: NotificationsBrokerTopicsService, useValue: { setSourceId: (sourceId: string) => { } }} + { provide: QualityAssuranceTopicsService, useValue: { setSourceId: (sourceId: string) => { } }} ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(() => { - mockNotificationsStateService.getNotificationsBrokerTopics.and.returnValue(observableOf([ - notificationsBrokerTopicObjectMorePid, - notificationsBrokerTopicObjectMoreAbstract + mockNotificationsStateService.getQualityAssuranceTopics.and.returnValue(observableOf([ + qualityAssuranceTopicObjectMorePid, + qualityAssuranceTopicObjectMoreAbstract ])); - mockNotificationsStateService.getNotificationsBrokerTopicsTotalPages.and.returnValue(observableOf(1)); - mockNotificationsStateService.getNotificationsBrokerTopicsCurrentPage.and.returnValue(observableOf(0)); - mockNotificationsStateService.getNotificationsBrokerTopicsTotals.and.returnValue(observableOf(2)); - mockNotificationsStateService.isNotificationsBrokerTopicsLoaded.and.returnValue(observableOf(true)); - mockNotificationsStateService.isNotificationsBrokerTopicsLoading.and.returnValue(observableOf(false)); - mockNotificationsStateService.isNotificationsBrokerTopicsProcessing.and.returnValue(observableOf(false)); + mockNotificationsStateService.getQualityAssuranceTopicsTotalPages.and.returnValue(observableOf(1)); + mockNotificationsStateService.getQualityAssuranceTopicsCurrentPage.and.returnValue(observableOf(0)); + mockNotificationsStateService.getQualityAssuranceTopicsTotals.and.returnValue(observableOf(2)); + mockNotificationsStateService.isQualityAssuranceTopicsLoaded.and.returnValue(observableOf(true)); + mockNotificationsStateService.isQualityAssuranceTopicsLoading.and.returnValue(observableOf(false)); + mockNotificationsStateService.isQualityAssuranceTopicsProcessing.and.returnValue(observableOf(false)); }); })); @@ -75,7 +75,7 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { // synchronous beforeEach beforeEach(() => { const html = ` - `; + `; testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; }); @@ -84,14 +84,14 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { testFixture.destroy(); }); - it('should create NotificationsBrokerTopicsComponent', inject([NotificationsBrokerTopicsComponent], (app: NotificationsBrokerTopicsComponent) => { + it('should create QualityAssuranceTopicsComponent', inject([QualityAssuranceTopicsComponent], (app: QualityAssuranceTopicsComponent) => { expect(app).toBeDefined(); })); }); describe('Main tests running with two topics', () => { beforeEach(() => { - fixture = TestBed.createComponent(NotificationsBrokerTopicsComponent); + fixture = TestBed.createComponent(QualityAssuranceTopicsComponent); comp = fixture.componentInstance; compAsAny = comp; @@ -109,8 +109,8 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { expect(comp.topics$).toBeObservable(cold('(a|)', { a: [ - notificationsBrokerTopicObjectMorePid, - notificationsBrokerTopicObjectMoreAbstract + qualityAssuranceTopicObjectMorePid, + qualityAssuranceTopicObjectMoreAbstract ] })); expect(comp.totalElements$).toBeObservable(cold('(a|)', { @@ -119,12 +119,12 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { }); it(('Should set data properly after the view init'), () => { - spyOn(compAsAny, 'getNotificationsBrokerTopics'); + spyOn(compAsAny, 'getQualityAssuranceTopics'); comp.ngAfterViewInit(); fixture.detectChanges(); - expect(compAsAny.getNotificationsBrokerTopics).toHaveBeenCalled(); + expect(compAsAny.getQualityAssuranceTopics).toHaveBeenCalled(); }); it(('isTopicsLoading should return FALSE'), () => { @@ -139,12 +139,12 @@ describe('NotificationsBrokerTopicsComponent test suite', () => { })); }); - it(('getNotificationsBrokerTopics should call the service to dispatch a STATE change'), () => { + it(('getQualityAssuranceTopics should call the service to dispatch a STATE change'), () => { comp.ngOnInit(); fixture.detectChanges(); - compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerTopics(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage).and.callThrough(); - expect(compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerTopics).toHaveBeenCalledWith(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage); + compAsAny.notificationsStateService.dispatchRetrieveQualityAssuranceTopics(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage).and.callThrough(); + expect(compAsAny.notificationsStateService.dispatchRetrieveQualityAssuranceTopics).toHaveBeenCalledWith(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage); }); }); }); diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.component.ts b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts similarity index 63% rename from src/app/notifications/broker/topics/notifications-broker-topics.component.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.component.ts index a740ca5c1ee..f825358f3bf 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.component.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts @@ -4,24 +4,24 @@ import { Observable, Subscription } from 'rxjs'; import { distinctUntilChanged, map, take } from 'rxjs/operators'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; -import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; import { hasValue } from '../../../shared/empty.util'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { NotificationsStateService } from '../../notifications-state.service'; -import { AdminNotificationsBrokerTopicsPageParams } from '../../../admin/admin-notifications/admin-notifications-broker-topics-page/admin-notifications-broker-topics-page-resolver.service'; +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 { NotificationsBrokerTopicsService } from './notifications-broker-topics.service'; +import { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; /** - * Component to display the Notifications Broker topic list. + * Component to display the Quality Assurance topic list. */ @Component({ - selector: 'ds-notifications-broker-topic', - templateUrl: './notifications-broker-topics.component.html', - styleUrls: ['./notifications-broker-topics.component.scss'], + selector: 'ds-quality-assurance-topic', + templateUrl: './quality-assurance-topics.component.html', + styleUrls: ['./quality-assurance-topics.component.scss'], }) -export class NotificationsBrokerTopicsComponent implements OnInit { +export class QualityAssuranceTopicsComponent implements OnInit { /** * The pagination system configuration for HTML listing. * @type {PaginationComponentOptions} @@ -32,16 +32,16 @@ export class NotificationsBrokerTopicsComponent implements OnInit { pageSizeOptions: [5, 10, 20, 40, 60] }); /** - * The Notifications Broker topic list sort options. + * The Quality Assurance topic list sort options. * @type {SortOptions} */ public paginationSortConfig: SortOptions; /** - * The Notifications Broker topic list. + * The Quality Assurance topic list. */ - public topics$: Observable; + public topics$: Observable; /** - * The total number of Notifications Broker topics. + * The total number of Quality Assurance topics. */ public totalElements$: Observable; /** @@ -65,7 +65,7 @@ export class NotificationsBrokerTopicsComponent implements OnInit { private paginationService: PaginationService, private activatedRoute: ActivatedRoute, private notificationsStateService: NotificationsStateService, - private notificationsBrokerTopicsService: NotificationsBrokerTopicsService + private qualityAssuranceTopicsService: QualityAssuranceTopicsService ) { } @@ -74,52 +74,52 @@ export class NotificationsBrokerTopicsComponent implements OnInit { */ ngOnInit(): void { this.sourceId = this.activatedRoute.snapshot.paramMap.get('sourceId'); - this.notificationsBrokerTopicsService.setSourceId(this.sourceId); - this.topics$ = this.notificationsStateService.getNotificationsBrokerTopics(); - this.totalElements$ = this.notificationsStateService.getNotificationsBrokerTopicsTotals(); + this.qualityAssuranceTopicsService.setSourceId(this.sourceId); + this.topics$ = this.notificationsStateService.getQualityAssuranceTopics(); + this.totalElements$ = this.notificationsStateService.getQualityAssuranceTopicsTotals(); } /** - * First Notifications Broker topics loading after view initialization. + * First Quality Assurance topics loading after view initialization. */ ngAfterViewInit(): void { this.subs.push( - this.notificationsStateService.isNotificationsBrokerTopicsLoaded().pipe( + this.notificationsStateService.isQualityAssuranceTopicsLoaded().pipe( take(1) ).subscribe(() => { - this.getNotificationsBrokerTopics(); + this.getQualityAssuranceTopics(); }) ); } /** - * Returns the information about the loading status of the Notifications Broker topics (if it's running or not). + * Returns the information about the loading status of the Quality Assurance topics (if it's running or not). * * @return Observable * 'true' if the topics are loading, 'false' otherwise. */ public isTopicsLoading(): Observable { - return this.notificationsStateService.isNotificationsBrokerTopicsLoading(); + return this.notificationsStateService.isQualityAssuranceTopicsLoading(); } /** - * Returns the information about the processing status of the Notifications Broker topics (if it's running or not). + * Returns the information about the processing status of the Quality Assurance topics (if it's running or not). * * @return Observable * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. */ public isTopicsProcessing(): Observable { - return this.notificationsStateService.isNotificationsBrokerTopicsProcessing(); + return this.notificationsStateService.isQualityAssuranceTopicsProcessing(); } /** - * Dispatch the Notifications Broker topics retrival. + * Dispatch the Quality Assurance topics retrival. */ - public getNotificationsBrokerTopics(): void { + public getQualityAssuranceTopics(): void { this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe( distinctUntilChanged(), ).subscribe((options: PaginationComponentOptions) => { - this.notificationsStateService.dispatchRetrieveNotificationsBrokerTopics( + this.notificationsStateService.dispatchRetrieveQualityAssuranceTopics( options.pageSize, options.currentPage ); @@ -131,7 +131,7 @@ export class NotificationsBrokerTopicsComponent implements OnInit { * * @param eventsRouteParams */ - protected updatePaginationFromRouteParams(eventsRouteParams: AdminNotificationsBrokerTopicsPageParams) { + protected updatePaginationFromRouteParams(eventsRouteParams: AdminQualityAssuranceTopicsPageParams) { if (eventsRouteParams.currentPage) { this.paginationConfig.currentPage = eventsRouteParams.currentPage; } diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.effects.ts b/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts similarity index 59% rename from src/app/notifications/broker/topics/notifications-broker-topics.effects.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.effects.ts index e3e1e16098f..14c0dacc238 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.effects.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts @@ -6,35 +6,35 @@ import { catchError, map, switchMap, tap, withLatestFrom } from 'rxjs/operators' import { of as observableOf } from 'rxjs'; import { AddTopicsAction, - NotificationsBrokerTopicActionTypes, + QualityAssuranceTopicActionTypes, RetrieveAllTopicsAction, RetrieveAllTopicsErrorAction, -} from './notifications-broker-topics.actions'; +} from './quality-assurance-topics.actions'; -import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; -import { NotificationsBrokerTopicsService } from './notifications-broker-topics.service'; +import { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; -import { NotificationsBrokerTopicRestService } from '../../../core/notifications/broker/topics/notifications-broker-topic-rest.service'; +import { QualityAssuranceTopicRestService } from '../../../core/notifications/qa/topics/quality-assurance-topic-rest.service'; /** - * Provides effect methods for the Notifications Broker topics actions. + * Provides effect methods for the Quality Assurance topics actions. */ @Injectable() -export class NotificationsBrokerTopicsEffects { +export class QualityAssuranceTopicsEffects { /** - * Retrieve all Notifications Broker topics managing pagination and errors. + * Retrieve all Quality Assurance topics managing pagination and errors. */ @Effect() retrieveAllTopics$ = this.actions$.pipe( - ofType(NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS), + ofType(QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS), withLatestFrom(this.store$), switchMap(([action, currentState]: [RetrieveAllTopicsAction, any]) => { - return this.notificationsBrokerTopicService.getTopics( + return this.qualityAssuranceTopicService.getTopics( action.payload.elementsPerPage, action.payload.currentPage ).pipe( - map((topics: PaginatedList) => + map((topics: PaginatedList) => new AddTopicsAction(topics.page, topics.totalPages, topics.currentPage, topics.totalElements) ), catchError((error: Error) => { @@ -51,7 +51,7 @@ export class NotificationsBrokerTopicsEffects { * Show a notification on error. */ @Effect({ dispatch: false }) retrieveAllTopicsErrorAction$ = this.actions$.pipe( - ofType(NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR), + ofType(QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR), tap(() => { this.notificationsService.error(null, this.translate.get('notifications.broker.topic.error.service.retrieve')); }) @@ -61,9 +61,9 @@ export class NotificationsBrokerTopicsEffects { * Clear find all topics requests from cache. */ @Effect({ dispatch: false }) addTopicsAction$ = this.actions$.pipe( - ofType(NotificationsBrokerTopicActionTypes.ADD_TOPICS), + ofType(QualityAssuranceTopicActionTypes.ADD_TOPICS), tap(() => { - this.notificationsBrokerTopicDataService.clearFindAllTopicsRequests(); + this.qualityAssuranceTopicDataService.clearFindAllTopicsRequests(); }) ); @@ -73,15 +73,15 @@ export class NotificationsBrokerTopicsEffects { * @param {Store} store$ * @param {TranslateService} translate * @param {NotificationsService} notificationsService - * @param {NotificationsBrokerTopicsService} notificationsBrokerTopicService - * @param {NotificationsBrokerTopicRestService} notificationsBrokerTopicDataService + * @param {QualityAssuranceTopicsService} qualityAssuranceTopicService + * @param {QualityAssuranceTopicRestService} qualityAssuranceTopicDataService */ constructor( private actions$: Actions, private store$: Store, private translate: TranslateService, private notificationsService: NotificationsService, - private notificationsBrokerTopicService: NotificationsBrokerTopicsService, - private notificationsBrokerTopicDataService: NotificationsBrokerTopicRestService + private qualityAssuranceTopicService: QualityAssuranceTopicsService, + private qualityAssuranceTopicDataService: QualityAssuranceTopicRestService ) { } } diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.reducer.spec.ts b/src/app/notifications/qa/topics/quality-assurance-topics.reducer.spec.ts similarity index 51% rename from src/app/notifications/broker/topics/notifications-broker-topics.reducer.spec.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.reducer.spec.ts index 523fac95508..a1c002d3f25 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.reducer.spec.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.reducer.spec.ts @@ -2,20 +2,20 @@ import { AddTopicsAction, RetrieveAllTopicsAction, RetrieveAllTopicsErrorAction -} from './notifications-broker-topics.actions'; -import { notificationsBrokerTopicsReducer, NotificationsBrokerTopicState } from './notifications-broker-topics.reducer'; +} from './quality-assurance-topics.actions'; +import { qualityAssuranceTopicsReducer, QualityAssuranceTopicState } from './quality-assurance-topics.reducer'; import { - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMorePid + qualityAssuranceTopicObjectMoreAbstract, + qualityAssuranceTopicObjectMorePid } from '../../../shared/mocks/notifications.mock'; -describe('notificationsBrokerTopicsReducer test suite', () => { - let notificationsBrokerTopicInitialState: NotificationsBrokerTopicState; +describe('qualityAssuranceTopicsReducer test suite', () => { + let qualityAssuranceTopicInitialState: QualityAssuranceTopicState; const elementPerPage = 3; const currentPage = 0; beforeEach(() => { - notificationsBrokerTopicInitialState = { + qualityAssuranceTopicInitialState = { topics: [], processing: false, loaded: false, @@ -26,30 +26,30 @@ describe('notificationsBrokerTopicsReducer test suite', () => { }); it('Action RETRIEVE_ALL_TOPICS should set the State property "processing" to TRUE', () => { - const expectedState = notificationsBrokerTopicInitialState; + const expectedState = qualityAssuranceTopicInitialState; expectedState.processing = true; const action = new RetrieveAllTopicsAction(elementPerPage, currentPage); - const newState = notificationsBrokerTopicsReducer(notificationsBrokerTopicInitialState, action); + const newState = qualityAssuranceTopicsReducer(qualityAssuranceTopicInitialState, action); expect(newState).toEqual(expectedState); }); it('Action RETRIEVE_ALL_TOPICS_ERROR should change the State to initial State but processing, loaded, and currentPage', () => { - const expectedState = notificationsBrokerTopicInitialState; + const expectedState = qualityAssuranceTopicInitialState; expectedState.processing = false; expectedState.loaded = true; expectedState.currentPage = 0; const action = new RetrieveAllTopicsErrorAction(); - const newState = notificationsBrokerTopicsReducer(notificationsBrokerTopicInitialState, action); + const newState = qualityAssuranceTopicsReducer(qualityAssuranceTopicInitialState, action); expect(newState).toEqual(expectedState); }); - it('Action ADD_TOPICS should populate the State with Notifications Broker topics', () => { + it('Action ADD_TOPICS should populate the State with Quality Assurance topics', () => { const expectedState = { - topics: [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ], + topics: [ qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract ], processing: false, loaded: true, totalPages: 1, @@ -58,10 +58,10 @@ describe('notificationsBrokerTopicsReducer test suite', () => { }; const action = new AddTopicsAction( - [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ], + [ qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract ], 1, 0, 2 ); - const newState = notificationsBrokerTopicsReducer(notificationsBrokerTopicInitialState, action); + const newState = qualityAssuranceTopicsReducer(qualityAssuranceTopicInitialState, action); expect(newState).toEqual(expectedState); }); diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts b/src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts new file mode 100644 index 00000000000..ff94f1b8bb1 --- /dev/null +++ b/src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts @@ -0,0 +1,72 @@ +import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicActionTypes, QualityAssuranceTopicsActions } from './quality-assurance-topics.actions'; + +/** + * The interface representing the Quality Assurance topic state. + */ +export interface QualityAssuranceTopicState { + topics: QualityAssuranceTopicObject[]; + processing: boolean; + loaded: boolean; + totalPages: number; + currentPage: number; + totalElements: number; +} + +/** + * Used for the Quality Assurance topic state initialization. + */ +const qualityAssuranceTopicInitialState: QualityAssuranceTopicState = { + topics: [], + processing: false, + loaded: false, + totalPages: 0, + currentPage: 0, + totalElements: 0 +}; + +/** + * The Quality Assurance Topic Reducer + * + * @param state + * the current state initialized with qualityAssuranceTopicInitialState + * @param action + * the action to perform on the state + * @return QualityAssuranceTopicState + * the new state + */ +export function qualityAssuranceTopicsReducer(state = qualityAssuranceTopicInitialState, action: QualityAssuranceTopicsActions): QualityAssuranceTopicState { + switch (action.type) { + case QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS: { + return Object.assign({}, state, { + topics: [], + processing: true + }); + } + + case QualityAssuranceTopicActionTypes.ADD_TOPICS: { + return Object.assign({}, state, { + topics: action.payload.topics, + processing: false, + loaded: true, + totalPages: action.payload.totalPages, + currentPage: state.currentPage, + totalElements: action.payload.totalElements + }); + } + + case QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR: { + return Object.assign({}, state, { + processing: false, + loaded: true, + totalPages: 0, + currentPage: 0, + totalElements: 0 + }); + } + + default: { + return state; + } + } +} diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts b/src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts similarity index 58% rename from src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts index e5616df3208..6d945446b2f 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts @@ -1,28 +1,28 @@ import { TestBed } from '@angular/core/testing'; import { of as observableOf } from 'rxjs'; -import { NotificationsBrokerTopicsService } from './notifications-broker-topics.service'; +import { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; -import { NotificationsBrokerTopicRestService } from '../../../core/notifications/broker/topics/notifications-broker-topic-rest.service'; +import { QualityAssuranceTopicRestService } from '../../../core/notifications/qa/topics/quality-assurance-topic-rest.service'; import { PageInfo } from '../../../core/shared/page-info.model'; -import { FindListOptions } from '../../../core/data/request.models'; import { - getMockNotificationsBrokerTopicRestService, - notificationsBrokerTopicObjectMoreAbstract, - notificationsBrokerTopicObjectMorePid + getMockQualityAssuranceTopicRestService, + qualityAssuranceTopicObjectMoreAbstract, + qualityAssuranceTopicObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; import { cold } from 'jasmine-marbles'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; import { RequestParam } from '../../../core/cache/models/request-param.model'; +import {FindListOptions} from '../../../core/data/find-list-options.model'; -describe('NotificationsBrokerTopicsService', () => { - let service: NotificationsBrokerTopicsService; - let restService: NotificationsBrokerTopicRestService; +describe('QualityAssuranceTopicsService', () => { + let service: QualityAssuranceTopicsService; + let restService: QualityAssuranceTopicRestService; let serviceAsAny: any; let restServiceAsAny: any; const pageInfo = new PageInfo(); - const array = [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ]; + const array = [ qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); const elementsPerPage = 3; @@ -31,22 +31,22 @@ describe('NotificationsBrokerTopicsService', () => { beforeEach(async () => { TestBed.configureTestingModule({ providers: [ - { provide: NotificationsBrokerTopicRestService, useClass: getMockNotificationsBrokerTopicRestService }, - { provide: NotificationsBrokerTopicsService, useValue: service } + { provide: QualityAssuranceTopicRestService, useClass: getMockQualityAssuranceTopicRestService }, + { provide: QualityAssuranceTopicsService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { - restService = TestBed.get(NotificationsBrokerTopicRestService); + restService = TestBed.get(QualityAssuranceTopicRestService); restServiceAsAny = restService; restServiceAsAny.getTopics.and.returnValue(observableOf(paginatedListRD)); - service = new NotificationsBrokerTopicsService(restService); + service = new QualityAssuranceTopicsService(restService); serviceAsAny = service; }); describe('getTopics', () => { - it('Should proxy the call to notificationsBrokerTopicRestService.getTopics', () => { + it('Should proxy the call to qualityAssuranceTopicRestService.getTopics', () => { const sortOptions = new SortOptions('name', SortDirection.ASC); const findListOptions: FindListOptions = { elementsPerPage: elementsPerPage, @@ -56,10 +56,10 @@ describe('NotificationsBrokerTopicsService', () => { }; service.setSourceId('ENRICH!MORE!ABSTRACT'); const result = service.getTopics(elementsPerPage, currentPage); - expect((service as any).notificationsBrokerTopicRestService.getTopics).toHaveBeenCalledWith(findListOptions); + expect((service as any).qualityAssuranceTopicRestService.getTopics).toHaveBeenCalledWith(findListOptions); }); - it('Should return a paginated list of Notifications Broker topics', () => { + it('Should return a paginated list of Quality Assurance topics', () => { const expected = cold('(a|)', { a: paginatedList }); diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.service.ts b/src/app/notifications/qa/topics/quality-assurance-topics.service.ts similarity index 51% rename from src/app/notifications/broker/topics/notifications-broker-topics.service.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.service.ts index 80c52a70a96..c09a0750e01 100644 --- a/src/app/notifications/broker/topics/notifications-broker-topics.service.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.service.ts @@ -1,26 +1,26 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { find, map } from 'rxjs/operators'; -import { NotificationsBrokerTopicRestService } from '../../../core/notifications/broker/topics/notifications-broker-topic-rest.service'; +import { QualityAssuranceTopicRestService } from '../../../core/notifications/qa/topics/quality-assurance-topic-rest.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; -import { FindListOptions } from '../../../core/data/request.models'; import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list.model'; -import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; import { RequestParam } from '../../../core/cache/models/request-param.model'; +import {FindListOptions} from '../../../core/data/find-list-options.model'; /** - * The service handling all Notifications Broker topic requests to the REST service. + * The service handling all Quality Assurance topic requests to the REST service. */ @Injectable() -export class NotificationsBrokerTopicsService { +export class QualityAssuranceTopicsService { /** * Initialize the service variables. - * @param {NotificationsBrokerTopicRestService} notificationsBrokerTopicRestService + * @param {QualityAssuranceTopicRestService} qualityAssuranceTopicRestService */ constructor( - private notificationsBrokerTopicRestService: NotificationsBrokerTopicRestService + private qualityAssuranceTopicRestService: QualityAssuranceTopicRestService ) { } /** @@ -29,16 +29,16 @@ export class NotificationsBrokerTopicsService { sourceId: string; /** - * Return the list of Notifications Broker topics managing pagination and errors. + * Return the list of Quality Assurance topics managing pagination and errors. * * @param elementsPerPage * The number of the topics per page * @param currentPage * The page number to retrieve - * @return Observable> - * The list of Notifications Broker topics. + * @return Observable> + * The list of Quality Assurance topics. */ - public getTopics(elementsPerPage, currentPage): Observable> { + public getTopics(elementsPerPage, currentPage): Observable> { const sortOptions = new SortOptions('name', SortDirection.ASC); const findListOptions: FindListOptions = { @@ -48,13 +48,13 @@ export class NotificationsBrokerTopicsService { searchParams: [new RequestParam('source', this.sourceId)] }; - return this.notificationsBrokerTopicRestService.getTopics(findListOptions).pipe( - find((rd: RemoteData>) => !rd.isResponsePending), - map((rd: RemoteData>) => { + return this.qualityAssuranceTopicRestService.getTopics(findListOptions).pipe( + find((rd: RemoteData>) => !rd.isResponsePending), + map((rd: RemoteData>) => { if (rd.hasSucceeded) { return rd.payload; } else { - throw new Error('Can\'t retrieve Notifications Broker topics from the Broker topics REST service'); + throw new Error('Can\'t retrieve Quality Assurance topics from the Broker topics REST service'); } }) ); diff --git a/src/app/notifications/selectors.ts b/src/app/notifications/selectors.ts index 0436a35eb30..3ab769aa95e 100644 --- a/src/app/notifications/selectors.ts +++ b/src/app/notifications/selectors.ts @@ -1,10 +1,10 @@ import { createSelector, MemoizedSelector } from '@ngrx/store'; import { subStateSelector } from '../shared/selector.util'; import { notificationsSelector, NotificationsState } from './notifications.reducer'; -import { NotificationsBrokerTopicObject } from '../core/notifications/broker/models/notifications-broker-topic.model'; -import { NotificationsBrokerTopicState } from './broker/topics/notifications-broker-topics.reducer'; -import { NotificationsBrokerSourceState } from './broker/source/notifications-broker-source.reducer'; -import { NotificationsBrokerSourceObject } from '../core/notifications/broker/models/notifications-broker-source.model'; +import { QualityAssuranceTopicObject } from '../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicState } from './qa/topics/quality-assurance-topics.reducer'; +import { QualityAssuranceSourceState } from './qa/source/quality-assurance-source.reducer'; +import { QualityAssuranceSourceObject } from '../core/notifications/qa/models/quality-assurance-source.model'; /** * Returns the Notifications state. @@ -14,33 +14,33 @@ import { NotificationsBrokerSourceObject } from '../core/notifications/broker/mo */ const _getNotificationsState = (state: any) => state.notifications; -// Notifications Broker topics +// Quality Assurance topics // ---------------------------------------------------------------------------- /** - * Returns the Notifications Broker topics State. - * @function notificationsBrokerTopicsStateSelector - * @return {NotificationsBrokerTopicState} + * Returns the Quality Assurance topics State. + * @function qualityAssuranceTopicsStateSelector + * @return {QualityAssuranceTopicState} */ -export function notificationsBrokerTopicsStateSelector(): MemoizedSelector { - return subStateSelector(notificationsSelector, 'brokerTopic'); +export function qualityAssuranceTopicsStateSelector(): MemoizedSelector { + return subStateSelector(notificationsSelector, 'brokerTopic'); } /** - * Returns the Notifications Broker topics list. - * @function notificationsBrokerTopicsObjectSelector - * @return {NotificationsBrokerTopicObject[]} + * Returns the Quality Assurance topics list. + * @function qualityAssuranceTopicsObjectSelector + * @return {QualityAssuranceTopicObject[]} */ -export function notificationsBrokerTopicsObjectSelector(): MemoizedSelector { - return subStateSelector(notificationsBrokerTopicsStateSelector(), 'topics'); +export function qualityAssuranceTopicsObjectSelector(): MemoizedSelector { + return subStateSelector(qualityAssuranceTopicsStateSelector(), 'topics'); } /** - * Returns true if the Notifications Broker topics are loaded. - * @function isNotificationsBrokerTopicsLoadedSelector + * Returns true if the Quality Assurance topics are loaded. + * @function isQualityAssuranceTopicsLoadedSelector * @return {boolean} */ -export const isNotificationsBrokerTopicsLoadedSelector = createSelector(_getNotificationsState, +export const isQualityAssuranceTopicsLoadedSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerTopic.loaded ); @@ -49,64 +49,64 @@ export const isNotificationsBrokerTopicsLoadedSelector = createSelector(_getNoti * @function isDeduplicationSetsProcessingSelector * @return {boolean} */ -export const isNotificationsBrokerTopicsProcessingSelector = createSelector(_getNotificationsState, +export const isQualityAssuranceTopicsProcessingSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerTopic.processing ); /** - * Returns the total available pages of Notifications Broker topics. - * @function getNotificationsBrokerTopicsTotalPagesSelector + * Returns the total available pages of Quality Assurance topics. + * @function getQualityAssuranceTopicsTotalPagesSelector * @return {number} */ -export const getNotificationsBrokerTopicsTotalPagesSelector = createSelector(_getNotificationsState, +export const getQualityAssuranceTopicsTotalPagesSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerTopic.totalPages ); /** - * Returns the current page of Notifications Broker topics. - * @function getNotificationsBrokerTopicsCurrentPageSelector + * Returns the current page of Quality Assurance topics. + * @function getQualityAssuranceTopicsCurrentPageSelector * @return {number} */ -export const getNotificationsBrokerTopicsCurrentPageSelector = createSelector(_getNotificationsState, +export const getQualityAssuranceTopicsCurrentPageSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerTopic.currentPage ); /** - * Returns the total number of Notifications Broker topics. - * @function getNotificationsBrokerTopicsTotalsSelector + * Returns the total number of Quality Assurance topics. + * @function getQualityAssuranceTopicsTotalsSelector * @return {number} */ -export const getNotificationsBrokerTopicsTotalsSelector = createSelector(_getNotificationsState, +export const getQualityAssuranceTopicsTotalsSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerTopic.totalElements ); -// Notifications Broker source +// Quality Assurance source // ---------------------------------------------------------------------------- /** - * Returns the Notifications Broker source State. - * @function notificationsBrokerSourceStateSelector - * @return {NotificationsBrokerSourceState} + * Returns the Quality Assurance source State. + * @function qualityAssuranceSourceStateSelector + * @return {QualityAssuranceSourceState} */ - export function notificationsBrokerSourceStateSelector(): MemoizedSelector { - return subStateSelector(notificationsSelector, 'brokerSource'); + export function qualityAssuranceSourceStateSelector(): MemoizedSelector { + return subStateSelector(notificationsSelector, 'brokerSource'); } /** - * Returns the Notifications Broker source list. - * @function notificationsBrokerSourceObjectSelector - * @return {NotificationsBrokerSourceObject[]} + * Returns the Quality Assurance source list. + * @function qualityAssuranceSourceObjectSelector + * @return {QualityAssuranceSourceObject[]} */ -export function notificationsBrokerSourceObjectSelector(): MemoizedSelector { - return subStateSelector(notificationsBrokerSourceStateSelector(), 'source'); +export function qualityAssuranceSourceObjectSelector(): MemoizedSelector { + return subStateSelector(qualityAssuranceSourceStateSelector(), 'source'); } /** - * Returns true if the Notifications Broker source are loaded. - * @function isNotificationsBrokerSourceLoadedSelector + * Returns true if the Quality Assurance source are loaded. + * @function isQualityAssuranceSourceLoadedSelector * @return {boolean} */ -export const isNotificationsBrokerSourceLoadedSelector = createSelector(_getNotificationsState, +export const isQualityAssuranceSourceLoadedSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerSource.loaded ); @@ -115,33 +115,33 @@ export const isNotificationsBrokerSourceLoadedSelector = createSelector(_getNoti * @function isDeduplicationSetsProcessingSelector * @return {boolean} */ -export const isNotificationsBrokerSourceProcessingSelector = createSelector(_getNotificationsState, +export const isQualityAssuranceSourceProcessingSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerSource.processing ); /** - * Returns the total available pages of Notifications Broker source. - * @function getNotificationsBrokerSourceTotalPagesSelector + * Returns the total available pages of Quality Assurance source. + * @function getQualityAssuranceSourceTotalPagesSelector * @return {number} */ -export const getNotificationsBrokerSourceTotalPagesSelector = createSelector(_getNotificationsState, +export const getQualityAssuranceSourceTotalPagesSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerSource.totalPages ); /** - * Returns the current page of Notifications Broker source. - * @function getNotificationsBrokerSourceCurrentPageSelector + * Returns the current page of Quality Assurance source. + * @function getQualityAssuranceSourceCurrentPageSelector * @return {number} */ -export const getNotificationsBrokerSourceCurrentPageSelector = createSelector(_getNotificationsState, +export const getQualityAssuranceSourceCurrentPageSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerSource.currentPage ); /** - * Returns the total number of Notifications Broker source. - * @function getNotificationsBrokerSourceTotalsSelector + * Returns the total number of Quality Assurance source. + * @function getQualityAssuranceSourceTotalsSelector * @return {number} */ -export const getNotificationsBrokerSourceTotalsSelector = createSelector(_getNotificationsState, +export const getQualityAssuranceSourceTotalsSelector = createSelector(_getNotificationsState, (state: NotificationsState) => state.brokerSource.totalElements ); diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index 8af034ea323..845c13a4cee 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -1,9 +1,9 @@ import { of as observableOf } from 'rxjs'; import { ResourceType } from '../../core/shared/resource-type'; -import { NotificationsBrokerTopicObject } from '../../core/notifications/broker/models/notifications-broker-topic.model'; -import { NotificationsBrokerEventObject } from '../../core/notifications/broker/models/notifications-broker-event.model'; -import { NotificationsBrokerTopicRestService } from '../../core/notifications/broker/topics/notifications-broker-topic-rest.service'; -import { NotificationsBrokerEventRestService } from '../../core/notifications/broker/events/notifications-broker-event-rest.service'; +import { QualityAssuranceTopicObject } from '../../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceEventObject } from '../../core/notifications/qa/models/quality-assurance-event.model'; +import { QualityAssuranceTopicRestService } from '../../core/notifications/qa/topics/quality-assurance-topic-rest.service'; +import { QualityAssuranceEventRestService } from '../../core/notifications/qa/events/quality-assurance-event-rest.service'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { NotificationsStateService } from '../../notifications/notifications-state.service'; import { Item } from '../../core/shared/item.model'; @@ -13,7 +13,7 @@ import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { SearchResult } from '../search/models/search-result.model'; -import { NotificationsBrokerSourceObject } from '../../core/notifications/broker/models/notifications-broker-source.model'; +import { QualityAssuranceSourceObject } from '../../core/notifications/qa/models/quality-assurance-source.model'; // REST Mock --------------------------------------------------------------------- // ------------------------------------------------------------------------------- @@ -1333,7 +1333,7 @@ export const NotificationsMockDspaceObject: SearchResult = Object. // Sources // ------------------------------------------------------------------------------- -export const notificationsBrokerSourceObjectMorePid: NotificationsBrokerSourceObject = { +export const qualityAssuranceSourceObjectMorePid: QualityAssuranceSourceObject = { type: new ResourceType('nbsource'), id: 'ENRICH!MORE!PID', lastEvent: '2020/10/09 10:11 UTC', @@ -1345,7 +1345,7 @@ export const notificationsBrokerSourceObjectMorePid: NotificationsBrokerSourceOb } }; -export const notificationsBrokerSourceObjectMoreAbstract: NotificationsBrokerSourceObject = { +export const qualityAssuranceSourceObjectMoreAbstract: QualityAssuranceSourceObject = { type: new ResourceType('nbsource'), id: 'ENRICH!MORE!ABSTRACT', lastEvent: '2020/09/08 21:14 UTC', @@ -1357,7 +1357,7 @@ export const notificationsBrokerSourceObjectMoreAbstract: NotificationsBrokerSou } }; -export const notificationsBrokerSourceObjectMissingPid: NotificationsBrokerSourceObject = { +export const qualityAssuranceSourceObjectMissingPid: QualityAssuranceSourceObject = { type: new ResourceType('nbsource'), id: 'ENRICH!MISSING!PID', lastEvent: '2020/10/01 07:36 UTC', @@ -1372,7 +1372,7 @@ export const notificationsBrokerSourceObjectMissingPid: NotificationsBrokerSourc // Topics // ------------------------------------------------------------------------------- -export const notificationsBrokerTopicObjectMorePid: NotificationsBrokerTopicObject = { +export const qualityAssuranceTopicObjectMorePid: QualityAssuranceTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MORE!PID', name: 'ENRICH/MORE/PID', @@ -1385,7 +1385,7 @@ export const notificationsBrokerTopicObjectMorePid: NotificationsBrokerTopicObje } }; -export const notificationsBrokerTopicObjectMoreAbstract: NotificationsBrokerTopicObject = { +export const qualityAssuranceTopicObjectMoreAbstract: QualityAssuranceTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MORE!ABSTRACT', name: 'ENRICH/MORE/ABSTRACT', @@ -1398,7 +1398,7 @@ export const notificationsBrokerTopicObjectMoreAbstract: NotificationsBrokerTopi } }; -export const notificationsBrokerTopicObjectMissingPid: NotificationsBrokerTopicObject = { +export const qualityAssuranceTopicObjectMissingPid: QualityAssuranceTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!PID', name: 'ENRICH/MISSING/PID', @@ -1411,7 +1411,7 @@ export const notificationsBrokerTopicObjectMissingPid: NotificationsBrokerTopicO } }; -export const notificationsBrokerTopicObjectMissingAbstract: NotificationsBrokerTopicObject = { +export const qualityAssuranceTopicObjectMissingAbstract: QualityAssuranceTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!ABSTRACT', name: 'ENRICH/MISSING/ABSTRACT', @@ -1424,7 +1424,7 @@ export const notificationsBrokerTopicObjectMissingAbstract: NotificationsBrokerT } }; -export const notificationsBrokerTopicObjectMissingAcm: NotificationsBrokerTopicObject = { +export const qualityAssuranceTopicObjectMissingAcm: QualityAssuranceTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!SUBJECT!ACM', name: 'ENRICH/MISSING/SUBJECT/ACM', @@ -1437,7 +1437,7 @@ export const notificationsBrokerTopicObjectMissingAcm: NotificationsBrokerTopicO } }; -export const notificationsBrokerTopicObjectMissingProject: NotificationsBrokerTopicObject = { +export const qualityAssuranceTopicObjectMissingProject: QualityAssuranceTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!PROJECT', name: 'ENRICH/MISSING/PROJECT', @@ -1453,7 +1453,7 @@ export const notificationsBrokerTopicObjectMissingProject: NotificationsBrokerTo // Events // ------------------------------------------------------------------------------- -export const notificationsBrokerEventObjectMissingPid: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingPid: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174001', uuid: '123e4567-e89b-12d3-a456-426614174001', type: new ResourceType('nbevent'), @@ -1489,10 +1489,10 @@ export const notificationsBrokerEventObjectMissingPid: NotificationsBrokerEventO related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const notificationsBrokerEventObjectMissingPid2: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingPid2: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174004', uuid: '123e4567-e89b-12d3-a456-426614174004', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/21486', title: 'UNA NUOVA RILETTURA DELL\u0027 ARISTOTELE DI FRANZ BRENTANO ALLA LUCE DI ALCUNI INEDITI', trust: 1.0, @@ -1525,10 +1525,10 @@ export const notificationsBrokerEventObjectMissingPid2: NotificationsBrokerEvent related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const notificationsBrokerEventObjectMissingPid3: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingPid3: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174005', uuid: '123e4567-e89b-12d3-a456-426614174005', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/554', title: 'Sustainable development', trust: 0.375, @@ -1561,10 +1561,10 @@ export const notificationsBrokerEventObjectMissingPid3: NotificationsBrokerEvent related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const notificationsBrokerEventObjectMissingPid4: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingPid4: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174006', uuid: '123e4567-e89b-12d3-a456-426614174006', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/10787', title: 'Reply to Critics', trust: 1.0, @@ -1597,10 +1597,10 @@ export const notificationsBrokerEventObjectMissingPid4: NotificationsBrokerEvent related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const notificationsBrokerEventObjectMissingPid5: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingPid5: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174007', uuid: '123e4567-e89b-12d3-a456-426614174007', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/11339', title: 'PROGETTAZIONE, SINTESI E VALUTAZIONE DELL\u0027ATTIVITA\u0027 ANTIMICOBATTERICA ED ANTIFUNGINA DI NUOVI DERIVATI ETEROCICLICI', trust: 0.375, @@ -1633,10 +1633,10 @@ export const notificationsBrokerEventObjectMissingPid5: NotificationsBrokerEvent related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const notificationsBrokerEventObjectMissingPid6: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingPid6: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174008', uuid: '123e4567-e89b-12d3-a456-426614174008', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/29860', title: 'Donald Davidson', trust: 0.375, @@ -1669,10 +1669,10 @@ export const notificationsBrokerEventObjectMissingPid6: NotificationsBrokerEvent related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const notificationsBrokerEventObjectMissingAbstract: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingAbstract: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174009', uuid: '123e4567-e89b-12d3-a456-426614174009', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/21110', title: 'Missing abstract article', trust: 0.751, @@ -1705,10 +1705,10 @@ export const notificationsBrokerEventObjectMissingAbstract: NotificationsBrokerE related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const notificationsBrokerEventObjectMissingProjectFound: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingProjectFound: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174002', uuid: '123e4567-e89b-12d3-a456-426614174002', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/21838', title: 'Egypt, crossroad of translations and literary interweavings (3rd-6th centuries). A reconsideration of earlier Coptic literature', trust: 1.0, @@ -1741,10 +1741,10 @@ export const notificationsBrokerEventObjectMissingProjectFound: NotificationsBro related: createSuccessfulRemoteDataObject$(ItemMockPid10) }; -export const notificationsBrokerEventObjectMissingProjectNotFound: NotificationsBrokerEventObject = { +export const qualityAssuranceEventObjectMissingProjectNotFound: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174003', uuid: '123e4567-e89b-12d3-a456-426614174003', - type: new ResourceType('notificationsBrokerEvent'), + type: new ResourceType('qualityAssuranceEvent'), originalId: 'oai:www.openstarts.units.it:10077/21838', title: 'Morocco, crossroad of translations and literary interweavings (3rd-6th centuries). A reconsideration of earlier Coptic literature', trust: 1.0, @@ -1785,51 +1785,51 @@ export const notificationsBrokerEventObjectMissingProjectNotFound: Notifications */ export function getMockNotificationsStateService(): any { return jasmine.createSpyObj('NotificationsStateService', { - getNotificationsBrokerTopics: jasmine.createSpy('getNotificationsBrokerTopics'), - isNotificationsBrokerTopicsLoading: jasmine.createSpy('isNotificationsBrokerTopicsLoading'), - isNotificationsBrokerTopicsLoaded: jasmine.createSpy('isNotificationsBrokerTopicsLoaded'), - isNotificationsBrokerTopicsProcessing: jasmine.createSpy('isNotificationsBrokerTopicsProcessing'), - getNotificationsBrokerTopicsTotalPages: jasmine.createSpy('getNotificationsBrokerTopicsTotalPages'), - getNotificationsBrokerTopicsCurrentPage: jasmine.createSpy('getNotificationsBrokerTopicsCurrentPage'), - getNotificationsBrokerTopicsTotals: jasmine.createSpy('getNotificationsBrokerTopicsTotals'), - dispatchRetrieveNotificationsBrokerTopics: jasmine.createSpy('dispatchRetrieveNotificationsBrokerTopics'), - getNotificationsBrokerSource: jasmine.createSpy('getNotificationsBrokerSource'), - isNotificationsBrokerSourceLoading: jasmine.createSpy('isNotificationsBrokerSourceLoading'), - isNotificationsBrokerSourceLoaded: jasmine.createSpy('isNotificationsBrokerSourceLoaded'), - isNotificationsBrokerSourceProcessing: jasmine.createSpy('isNotificationsBrokerSourceProcessing'), - getNotificationsBrokerSourceTotalPages: jasmine.createSpy('getNotificationsBrokerSourceTotalPages'), - getNotificationsBrokerSourceCurrentPage: jasmine.createSpy('getNotificationsBrokerSourceCurrentPage'), - getNotificationsBrokerSourceTotals: jasmine.createSpy('getNotificationsBrokerSourceTotals'), - dispatchRetrieveNotificationsBrokerSource: jasmine.createSpy('dispatchRetrieveNotificationsBrokerSource'), + getQualityAssuranceTopics: jasmine.createSpy('getQualityAssuranceTopics'), + isQualityAssuranceTopicsLoading: jasmine.createSpy('isQualityAssuranceTopicsLoading'), + isQualityAssuranceTopicsLoaded: jasmine.createSpy('isQualityAssuranceTopicsLoaded'), + isQualityAssuranceTopicsProcessing: jasmine.createSpy('isQualityAssuranceTopicsProcessing'), + getQualityAssuranceTopicsTotalPages: jasmine.createSpy('getQualityAssuranceTopicsTotalPages'), + getQualityAssuranceTopicsCurrentPage: jasmine.createSpy('getQualityAssuranceTopicsCurrentPage'), + getQualityAssuranceTopicsTotals: jasmine.createSpy('getQualityAssuranceTopicsTotals'), + dispatchRetrieveQualityAssuranceTopics: jasmine.createSpy('dispatchRetrieveQualityAssuranceTopics'), + getQualityAssuranceSource: jasmine.createSpy('getQualityAssuranceSource'), + isQualityAssuranceSourceLoading: jasmine.createSpy('isQualityAssuranceSourceLoading'), + isQualityAssuranceSourceLoaded: jasmine.createSpy('isQualityAssuranceSourceLoaded'), + isQualityAssuranceSourceProcessing: jasmine.createSpy('isQualityAssuranceSourceProcessing'), + getQualityAssuranceSourceTotalPages: jasmine.createSpy('getQualityAssuranceSourceTotalPages'), + getQualityAssuranceSourceCurrentPage: jasmine.createSpy('getQualityAssuranceSourceCurrentPage'), + getQualityAssuranceSourceTotals: jasmine.createSpy('getQualityAssuranceSourceTotals'), + dispatchRetrieveQualityAssuranceSource: jasmine.createSpy('dispatchRetrieveQualityAssuranceSource'), dispatchMarkUserSuggestionsAsVisitedAction: jasmine.createSpy('dispatchMarkUserSuggestionsAsVisitedAction') }); } /** - * Mock for [[NotificationsBrokerSourceRestService]] + * Mock for [[QualityAssuranceSourceRestService]] */ - export function getMockNotificationsBrokerSourceRestService(): NotificationsBrokerTopicRestService { - return jasmine.createSpyObj('NotificationsBrokerSourceRestService', { + export function getMockQualityAssuranceSourceRestService(): QualityAssuranceTopicRestService { + return jasmine.createSpyObj('QualityAssuranceSourceRestService', { getSources: jasmine.createSpy('getSources'), getSource: jasmine.createSpy('getSource'), }); } /** - * Mock for [[NotificationsBrokerTopicRestService]] + * Mock for [[QualityAssuranceTopicRestService]] */ -export function getMockNotificationsBrokerTopicRestService(): NotificationsBrokerTopicRestService { - return jasmine.createSpyObj('NotificationsBrokerTopicRestService', { +export function getMockQualityAssuranceTopicRestService(): QualityAssuranceTopicRestService { + return jasmine.createSpyObj('QualityAssuranceTopicRestService', { getTopics: jasmine.createSpy('getTopics'), getTopic: jasmine.createSpy('getTopic'), }); } /** - * Mock for [[NotificationsBrokerEventRestService]] + * Mock for [[QualityAssuranceEventRestService]] */ -export function getMockNotificationsBrokerEventRestService(): NotificationsBrokerEventRestService { - return jasmine.createSpyObj('NotificationsBrokerEventRestService', { +export function getMockQualityAssuranceEventRestService(): QualityAssuranceEventRestService { + return jasmine.createSpyObj('QualityAssuranceEventRestService', { getEventsByTopic: jasmine.createSpy('getEventsByTopic'), getEvent: jasmine.createSpy('getEvent'), patchEvent: jasmine.createSpy('patchEvent'), @@ -1840,7 +1840,7 @@ export function getMockNotificationsBrokerEventRestService(): NotificationsBroke } /** - * Mock for [[NotificationsBrokerEventRestService]] + * Mock for [[QualityAssuranceEventRestService]] */ export function getMockSuggestionsService(): any { return jasmine.createSpyObj('SuggestionsService', { diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index d092e4f2c81..0f5db4eb5be 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -499,13 +499,13 @@ "admin.access-control.groups.form.return": "Back", - "admin.notifications.broker.breadcrumbs": "Notifications Broker", + "admin.notifications.broker.breadcrumbs": "Quality Assurance", "admin.notifications.event.breadcrumbs": "Broker Suggestions", "admin.notifications.event.page.title": "Broker Suggestions", - "admin.notifications.broker.page.title": "Notifications Broker", + "admin.notifications.broker.page.title": "Quality Assurance", "admin.notifications.source.breadcrumbs": "Notifications Source", @@ -2687,7 +2687,7 @@ "menu.section.notifications": "Notifications", - "menu.section.notifications_broker": "Notifications Broker", + "menu.section.notifications_broker": "Quality Assurance", "menu.section.notifications_reciter": "Publication Claim", @@ -2889,9 +2889,9 @@ "notifications.events.title": "Broker Suggestions", - "notifications.broker.topic.error.service.retrieve": "An error occurred while loading the Notifications Broker topics", + "notifications.broker.topic.error.service.retrieve": "An error occurred while loading the Quality Assurance topics", - "notifications.broker.source.error.service.retrieve": "An error occurred while loading the Notifications Broker source", + "notifications.broker.source.error.service.retrieve": "An error occurred while loading the Quality Assurance source", "notifications.broker.events.description": "Below the list of all the suggestions for the selected topic.", From a355a154599a1b7b1860197626301bbb40006a31 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 5 Jul 2022 17:28:14 +0200 Subject: [PATCH 008/196] [CST-5249] Fix deprecated selector creation --- src/app/notifications/selectors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/notifications/selectors.ts b/src/app/notifications/selectors.ts index 3ab769aa95e..2b78b947f83 100644 --- a/src/app/notifications/selectors.ts +++ b/src/app/notifications/selectors.ts @@ -1,4 +1,4 @@ -import { createSelector, MemoizedSelector } from '@ngrx/store'; +import { createFeatureSelector, createSelector, MemoizedSelector } from '@ngrx/store'; import { subStateSelector } from '../shared/selector.util'; import { notificationsSelector, NotificationsState } from './notifications.reducer'; import { QualityAssuranceTopicObject } from '../core/notifications/qa/models/quality-assurance-topic.model'; @@ -12,7 +12,7 @@ import { QualityAssuranceSourceObject } from '../core/notifications/qa/models/qu * @param {AppState} state Top level state. * @return {NotificationsState} */ -const _getNotificationsState = (state: any) => state.notifications; +const _getNotificationsState = createFeatureSelector('notifications'); // Quality Assurance topics // ---------------------------------------------------------------------------- From a7d2278d993212d60cb8c43fdfe1da000d6f3e5c Mon Sep 17 00:00:00 2001 From: Luca Giamminonni Date: Wed, 6 Jul 2022 17:14:12 +0200 Subject: [PATCH 009/196] [CST-5249] Renamed nbevent and nbtopics --- .../admin-notifications-routing.module.ts | 10 +- ...quality-assurance-topics-page.component.ts | 2 +- ...ality-assurance-event-rest.service.spec.ts | 18 +-- .../quality-assurance-event-rest.service.ts | 2 +- ...ty-assurance-event-object.resource-type.ts | 2 +- .../models/quality-assurance-event.model.ts | 20 +-- ...y-assurance-source-object.resource-type.ts | 2 +- ...ty-assurance-topic-object.resource-type.ts | 2 +- ...lity-assurance-source-rest.service.spec.ts | 8 +- .../quality-assurance-source-rest.service.ts | 8 +- ...ality-assurance-topic-rest.service.spec.ts | 8 +- .../quality-assurance-topic-rest.service.ts | 8 +- src/app/menu.resolver.ts | 23 +++ .../notifications-state.service.spec.ts | 8 +- .../notifications/notifications.reducer.ts | 8 +- .../quality-assurance-events.component.html | 86 +++++------ .../quality-assurance-events.component.ts | 20 +-- .../project-entry-import-modal.component.ts | 6 +- .../quality-assurance-source.component.html | 20 +-- .../quality-assurance-source.effects.ts | 2 +- .../quality-assurance-topics.component.html | 20 +-- .../quality-assurance-topics.effects.ts | 2 +- src/app/notifications/selectors.ts | 24 +-- src/app/shared/mocks/notifications.mock.ts | 92 ++++++------ src/app/shared/selector.util.ts | 4 +- src/assets/i18n/en.json5 | 142 +++++++++--------- 26 files changed, 285 insertions(+), 262 deletions(-) diff --git a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts index c9cca6d8d80..dc0d82c1d99 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -23,11 +23,11 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerTopicsParams: AdminQualityAssuranceTopicsPageResolver + openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver }, data: { - title: 'admin.notifications.broker.page.title', - breadcrumbKey: 'admin.notifications.broker', + title: 'admin.quality-assurance.page.title', + breadcrumbKey: 'admin.quality-assurance', showBreadcrumbsFluid: false } }, @@ -38,7 +38,7 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerSourceParams: AdminQualityAssuranceSourcePageResolver, + openaireQualityAssuranceSourceParams: AdminQualityAssuranceSourcePageResolver, sourceData: SourceDataResolver }, data: { @@ -54,7 +54,7 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon pathMatch: 'full', resolve: { breadcrumb: I18nBreadcrumbResolver, - openaireBrokerEventsParams: AdminQualityAssuranceEventsPageResolver + openaireQualityAssuranceEventsParams: AdminQualityAssuranceEventsPageResolver }, data: { title: 'admin.notifications.event.page.title', diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts index 53f951ba541..1b4f1d70aa8 100644 --- a/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'ds-notification-broker-page', + selector: 'ds-notification-qa-page', templateUrl: './admin-quality-assurance-topics-page.component.html' }) export class AdminQualityAssuranceTopicsPageComponent { diff --git a/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts index 556665adbd7..3734ae0dd2c 100644 --- a/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts +++ b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts @@ -38,15 +38,15 @@ describe('QualityAssuranceEventRestService', () => { let http: HttpClient; let comparator: any; - const endpointURL = 'https://rest.api/rest/api/integration/nbtopics'; + const endpointURL = 'https://rest.api/rest/api/integration/qatopics'; const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const topic = 'ENRICH!MORE!PID'; const pageInfo = new PageInfo(); const array = [ qualityAssuranceEventObjectMissingPid, qualityAssuranceEventObjectMissingPid2 ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerEventObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingPid); - const brokerEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingProjectFound); + const qaEventObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingPid); + const qaEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingProjectFound); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); const status = 'ACCEPTED'; @@ -82,7 +82,7 @@ describe('QualityAssuranceEventRestService', () => { rdbService = jasmine.createSpyObj('rdbService', { buildSingle: cold('(a)', { - a: brokerEventObjectRD + a: qaEventObjectRD }), buildList: cold('(a)', { a: paginatedListRD @@ -122,7 +122,7 @@ describe('QualityAssuranceEventRestService', () => { beforeEach(() => { serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntry)); serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntry)); - serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectRD)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectRD)); }); it('should proxy the call to dataservice.searchBy', () => { @@ -151,7 +151,7 @@ describe('QualityAssuranceEventRestService', () => { beforeEach(() => { serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntry)); serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntry)); - serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectRD)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectRD)); }); it('should proxy the call to dataservice.findById', () => { @@ -165,7 +165,7 @@ describe('QualityAssuranceEventRestService', () => { it('should return a RemoteData for the object with the given URL', () => { const result = service.getEvent(qualityAssuranceEventObjectMissingPid.id); const expected = cold('(a)', { - a: brokerEventObjectRD + a: qaEventObjectRD }); expect(result).toBeObservable(expected); }); @@ -175,7 +175,7 @@ describe('QualityAssuranceEventRestService', () => { beforeEach(() => { serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntry)); serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntry)); - serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectRD)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectRD)); }); it('should proxy the call to dataservice.patch', () => { @@ -199,7 +199,7 @@ describe('QualityAssuranceEventRestService', () => { beforeEach(() => { serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntryB)); serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntryB)); - serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(brokerEventObjectMissingProjectRD)); + serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectMissingProjectRD)); }); it('should proxy the call to dataservice.postOnRelated', () => { diff --git a/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts index 59f6c31e057..67863cad745 100644 --- a/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts +++ b/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts @@ -33,7 +33,7 @@ class DataServiceImpl extends DataService { /** * The REST endpoint. */ - protected linkPath = 'nbevents'; + protected linkPath = 'qaevents'; /** * Initialize service variables diff --git a/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts index 33c7b338edb..2dedc84d086 100644 --- a/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts @@ -6,4 +6,4 @@ import { ResourceType } from '../../../shared/resource-type'; * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const QUALITY_ASSURANCE_EVENT_OBJECT = new ResourceType('nbevent'); +export const QUALITY_ASSURANCE_EVENT_OBJECT = new ResourceType('qaevent'); diff --git a/src/app/core/notifications/qa/models/quality-assurance-event.model.ts b/src/app/core/notifications/qa/models/quality-assurance-event.model.ts index 15fbae7821d..f070e7303ad 100644 --- a/src/app/core/notifications/qa/models/quality-assurance-event.model.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-event.model.ts @@ -11,16 +11,16 @@ import { RemoteData } from '../../../data/remote-data'; import {CacheableObject} from '../../../cache/cacheable-object.model'; /** - * The interface representing the Notifications Broker event message + * The interface representing the Quality Assurance event message */ export interface QualityAssuranceEventMessageObject { } /** - * The interface representing the Notifications Broker event message + * The interface representing the Quality Assurance event message */ -export interface OpenaireBrokerEventMessageObject { +export interface OpenaireQualityAssuranceEventMessageObject { /** * The type of 'value' */ @@ -74,7 +74,7 @@ export interface OpenaireBrokerEventMessageObject { } /** - * The interface representing the Notifications Broker event model + * The interface representing the Quality Assurance event model */ @typedObject export class QualityAssuranceEventObject implements CacheableObject { @@ -84,19 +84,19 @@ export class QualityAssuranceEventObject implements CacheableObject { static type = QUALITY_ASSURANCE_EVENT_OBJECT; /** - * The Notifications Broker event uuid inside DSpace + * The Quality Assurance event uuid inside DSpace */ @autoserialize id: string; /** - * The universally unique identifier of this Notifications Broker event + * The universally unique identifier of this Quality Assurance event */ @autoserializeAs(String, 'id') uuid: string; /** - * The Notifications Broker event original id (ex.: the source archive OAI-PMH identifier) + * The Quality Assurance event original id (ex.: the source archive OAI-PMH identifier) */ @autoserialize originalId: string; @@ -114,13 +114,13 @@ export class QualityAssuranceEventObject implements CacheableObject { trust: number; /** - * The timestamp Notifications Broker event was saved in DSpace + * The timestamp Quality Assurance event was saved in DSpace */ @autoserialize eventDate: string; /** - * The Notifications Broker event status (ACCEPTED, REJECTED, DISCARDED, PENDING) + * The Quality Assurance event status (ACCEPTED, REJECTED, DISCARDED, PENDING) */ @autoserialize status: string; @@ -129,7 +129,7 @@ export class QualityAssuranceEventObject implements CacheableObject { * The suggestion data. Data may vary depending on the source */ @autoserialize - message: OpenaireBrokerEventMessageObject; + message: OpenaireQualityAssuranceEventMessageObject; /** * The type of this ConfigObject diff --git a/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts index 585216c34f8..5f4c8dd954a 100644 --- a/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts @@ -6,4 +6,4 @@ import { ResourceType } from '../../../shared/resource-type'; * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const QUALITY_ASSURANCE_SOURCE_OBJECT = new ResourceType('nbsource'); +export const QUALITY_ASSURANCE_SOURCE_OBJECT = new ResourceType('qasource'); diff --git a/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts index 8cd5bec61bc..7e12dd9ca81 100644 --- a/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts @@ -6,4 +6,4 @@ import { ResourceType } from '../../../shared/resource-type'; * Needs to be in a separate file to prevent circular * dependencies in webpack. */ -export const QUALITY_ASSURANCE_TOPIC_OBJECT = new ResourceType('nbtopic'); +export const QUALITY_ASSURANCE_TOPIC_OBJECT = new ResourceType('qatopic'); diff --git a/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts index dff604b0c40..d574b36802a 100644 --- a/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts +++ b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts @@ -32,13 +32,13 @@ describe('QualityAssuranceSourceRestService', () => { let http: HttpClient; let comparator: any; - const endpointURL = 'https://rest.api/rest/api/integration/nbsources'; + const endpointURL = 'https://rest.api/rest/api/integration/qasources'; const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); const array = [ qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerSourceObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceSourceObjectMorePid); + const qaSourceObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceSourceObjectMorePid); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); beforeEach(() => { @@ -56,7 +56,7 @@ describe('QualityAssuranceSourceRestService', () => { rdbService = jasmine.createSpyObj('rdbService', { buildSingle: cold('(a)', { - a: brokerSourceObjectRD + a: qaSourceObjectRD }), buildList: cold('(a)', { a: paginatedListRD @@ -118,7 +118,7 @@ describe('QualityAssuranceSourceRestService', () => { it('should return a RemoteData for the object with the given URL', () => { const result = service.getSource(qualityAssuranceSourceObjectMorePid.id); const expected = cold('(a)', { - a: brokerSourceObjectRD + a: qaSourceObjectRD }); expect(result).toBeObservable(expected); }); diff --git a/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts index 85045aebcd0..10bcfbe896a 100644 --- a/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts +++ b/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts @@ -31,7 +31,7 @@ class DataServiceImpl extends DataService { /** * The REST endpoint. */ - protected linkPath = 'nbsources'; + protected linkPath = 'qasources'; /** * Initialize service variables @@ -100,7 +100,7 @@ export class QualityAssuranceSourceRestService { * The list of Quality Assurance source. */ public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { - return this.dataService.getBrowseEndpoint(options, 'nbsources').pipe( + return this.dataService.getBrowseEndpoint(options, 'qasources').pipe( take(1), mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), ); @@ -110,7 +110,7 @@ export class QualityAssuranceSourceRestService { * Clear FindAll source requests from cache */ public clearFindAllSourceRequests() { - this.requestService.setStaleByHrefSubstring('nbsources'); + this.requestService.setStaleByHrefSubstring('qasources'); } /** @@ -125,7 +125,7 @@ export class QualityAssuranceSourceRestService { */ public getSource(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { const options = {}; - return this.dataService.getBrowseEndpoint(options, 'nbsources').pipe( + return this.dataService.getBrowseEndpoint(options, 'qasources').pipe( take(1), mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...linksToFollow)) ); diff --git a/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts index cb828141a6d..458bc4957d6 100644 --- a/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts +++ b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts @@ -32,13 +32,13 @@ describe('QualityAssuranceTopicRestService', () => { let http: HttpClient; let comparator: any; - const endpointURL = 'https://rest.api/rest/api/integration/nbtopics'; + const endpointURL = 'https://rest.api/rest/api/integration/qatopics'; const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); const array = [ qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); - const brokerTopicObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceTopicObjectMorePid); + const qaTopicObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceTopicObjectMorePid); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); beforeEach(() => { @@ -56,7 +56,7 @@ describe('QualityAssuranceTopicRestService', () => { rdbService = jasmine.createSpyObj('rdbService', { buildSingle: cold('(a)', { - a: brokerTopicObjectRD + a: qaTopicObjectRD }), buildList: cold('(a)', { a: paginatedListRD @@ -118,7 +118,7 @@ describe('QualityAssuranceTopicRestService', () => { it('should return a RemoteData for the object with the given URL', () => { const result = service.getTopic(qualityAssuranceTopicObjectMorePid.id); const expected = cold('(a)', { - a: brokerTopicObjectRD + a: qaTopicObjectRD }); expect(result).toBeObservable(expected); }); diff --git a/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts index da901267097..da9d95d290d 100644 --- a/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts +++ b/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts @@ -31,7 +31,7 @@ class DataServiceImpl extends DataService { /** * The REST endpoint. */ - protected linkPath = 'nbtopics'; + protected linkPath = 'qatopics'; /** * Initialize service variables @@ -100,7 +100,7 @@ export class QualityAssuranceTopicRestService { * The list of Quality Assurance topics. */ public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { - return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( + return this.dataService.getBrowseEndpoint(options, 'qatopics').pipe( take(1), mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), ); @@ -110,7 +110,7 @@ export class QualityAssuranceTopicRestService { * Clear FindAll topics requests from cache */ public clearFindAllTopicsRequests() { - this.requestService.setStaleByHrefSubstring('nbtopics'); + this.requestService.setStaleByHrefSubstring('qatopics'); } /** @@ -125,7 +125,7 @@ export class QualityAssuranceTopicRestService { */ public getTopic(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { const options = {}; - return this.dataService.getBrowseEndpoint(options, 'nbtopics').pipe( + return this.dataService.getBrowseEndpoint(options, 'qatopics').pipe( take(1), mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...linksToFollow)) ); diff --git a/src/app/menu.resolver.ts b/src/app/menu.resolver.ts index 4c97d3d1b30..e4eba116228 100644 --- a/src/app/menu.resolver.ts +++ b/src/app/menu.resolver.ts @@ -507,6 +507,29 @@ export class MenuResolver implements Resolve { createSiteAdministratorMenuSections() { this.authorizationService.isAuthorized(FeatureID.AdministratorOf).subscribe((authorized) => { const menuList = [ + /* Notifications */ + { + id: 'notifications', + active: false, + visible: authorized, + model: { + type: MenuItemType.TEXT, + text: 'menu.section.notifications' + } as TextMenuItemModel, + icon: 'bell', + index: 4 + }, + { + id: 'notifications_quality-assurance', + parentID: 'notifications', + active: false, + visible: authorized, + model: { + type: MenuItemType.LINK, + text: 'menu.section.quality-assurance', + link: '/admin/notifications/quality-assurance' + } as LinkMenuItemModel, + }, /* Admin Search */ { id: 'admin_search', diff --git a/src/app/notifications/notifications-state.service.spec.ts b/src/app/notifications/notifications-state.service.spec.ts index cabda48ec58..8c191415b70 100644 --- a/src/app/notifications/notifications-state.service.spec.ts +++ b/src/app/notifications/notifications-state.service.spec.ts @@ -26,7 +26,7 @@ describe('NotificationsStateService', () => { if (mode === 'empty') { initialState = { notifications: { - brokerTopic: { + qaTopic: { topics: [], processing: false, loaded: false, @@ -40,7 +40,7 @@ describe('NotificationsStateService', () => { } else { initialState = { notifications: { - brokerTopic: { + qaTopic: { topics: [ qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract, @@ -284,7 +284,7 @@ describe('NotificationsStateService', () => { if (mode === 'empty') { initialState = { notifications: { - brokerSource: { + qaSource: { source: [], processing: false, loaded: false, @@ -298,7 +298,7 @@ describe('NotificationsStateService', () => { } else { initialState = { notifications: { - brokerSource: { + qaSource: { source: [ qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract, diff --git a/src/app/notifications/notifications.reducer.ts b/src/app/notifications/notifications.reducer.ts index 5800788c42c..4cce554f95c 100644 --- a/src/app/notifications/notifications.reducer.ts +++ b/src/app/notifications/notifications.reducer.ts @@ -6,13 +6,13 @@ import { qualityAssuranceTopicsReducer, QualityAssuranceTopicState, } from './qa * The OpenAIRE State */ export interface NotificationsState { - 'brokerTopic': QualityAssuranceTopicState; - 'brokerSource': QualityAssuranceSourceState; + 'qaTopic': QualityAssuranceTopicState; + 'qaSource': QualityAssuranceSourceState; } export const notificationsReducers: ActionReducerMap = { - brokerTopic: qualityAssuranceTopicsReducer, - brokerSource: qualityAssuranceSourceReducer + qaTopic: qualityAssuranceTopicsReducer, + qaSource: qualityAssuranceSourceReducer }; export const notificationsSelector = createFeatureSelector('notifications'); 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 40fa75943f8..d7f6129b3b2 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/notifications/qa/events/quality-assurance-events.component.html @@ -2,11 +2,11 @@

{{'notifications.events.title'| translate}}

-

{{'notifications.broker.events.description'| translate}}

+

{{'quality-assurance.events.description'| translate}}

- {{'notifications.broker.events.back' | translate}} + {{'quality-assurance.events.back' | translate}}

@@ -14,10 +14,10 @@

{{'notifications.events.title'| translate}}

- {{'notifications.broker.events.topic' | translate}} {{this.showTopic}} + {{'quality-assurance.events.topic' | translate}} {{this.showTopic}}

- + [sortOptions]="paginationSortConfig" (paginationChange)="getQualityAssuranceEvents()"> - +
- - - - - + + + + + @@ -51,8 +51,8 @@

{{eventElement.title}}

@@ -142,7 +142,7 @@

@@ -150,58 +150,58 @@

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 aa47bfc590f..6e3dd8d010a 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.ts @@ -11,7 +11,7 @@ import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; import { QualityAssuranceEventObject, - OpenaireBrokerEventMessageObject + OpenaireQualityAssuranceEventMessageObject } from '../../../core/notifications/qa/models/quality-assurance-event.model'; import { QualityAssuranceEventRestService } from '../../../core/notifications/qa/events/quality-assurance-event-rest.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; @@ -242,12 +242,12 @@ export class QualityAssuranceEventsComponent implements OnInit { .subscribe((rd: RemoteData) => { if (rd.isSuccess && rd.statusCode === 200) { this.notificationsService.success( - this.translateService.instant('notifications.broker.event.action.saved') + this.translateService.instant('quality-assurance.event.action.saved') ); this.getQualityAssuranceEvents(); } else { this.notificationsService.error( - this.translateService.instant('notifications.broker.event.action.error') + this.translateService.instant('quality-assurance.event.action.error') ); } eventData.isRunning = false; @@ -274,7 +274,7 @@ export class QualityAssuranceEventsComponent implements OnInit { .subscribe((rd: RemoteData) => { if (rd.isSuccess) { this.notificationsService.success( - this.translateService.instant('notifications.broker.event.project.bounded') + this.translateService.instant('quality-assurance.event.project.bounded') ); eventData.hasProject = true; eventData.projectTitle = projectTitle; @@ -282,7 +282,7 @@ export class QualityAssuranceEventsComponent implements OnInit { eventData.projectId = projectId; } else { this.notificationsService.error( - this.translateService.instant('notifications.broker.event.project.error') + this.translateService.instant('quality-assurance.event.project.error') ); } eventData.isRunning = false; @@ -303,7 +303,7 @@ export class QualityAssuranceEventsComponent implements OnInit { .subscribe((rd: RemoteData) => { if (rd.isSuccess) { this.notificationsService.success( - this.translateService.instant('notifications.broker.event.project.removed') + this.translateService.instant('quality-assurance.event.project.removed') ); eventData.hasProject = false; eventData.projectTitle = null; @@ -311,7 +311,7 @@ export class QualityAssuranceEventsComponent implements OnInit { eventData.projectId = null; } else { this.notificationsService.error( - this.translateService.instant('notifications.broker.event.project.error') + this.translateService.instant('quality-assurance.event.project.error') ); } eventData.isRunning = false; @@ -323,7 +323,7 @@ export class QualityAssuranceEventsComponent implements OnInit { * Check if the event has a valid href. * @param event */ - public hasPIDHref(event: OpenaireBrokerEventMessageObject): boolean { + public hasPIDHref(event: OpenaireQualityAssuranceEventMessageObject): boolean { return this.getPIDHref(event) !== null; } @@ -331,7 +331,7 @@ export class QualityAssuranceEventsComponent implements OnInit { * Get the event pid href. * @param event */ - public getPIDHref(event: OpenaireBrokerEventMessageObject): string { + public getPIDHref(event: OpenaireQualityAssuranceEventMessageObject): string { return this.computePIDHref(event); } @@ -419,7 +419,7 @@ export class QualityAssuranceEventsComponent implements OnInit { ); } - protected computePIDHref(event: OpenaireBrokerEventMessageObject) { + protected computePIDHref(event: OpenaireQualityAssuranceEventMessageObject) { const type = event.type.toLowerCase(); const pid = event.value; let prefix = null; diff --git a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts index 64a5f6908fe..64a2df30ba1 100644 --- a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts +++ b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts @@ -15,7 +15,7 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { QualityAssuranceEventObject, QualityAssuranceEventMessageObject, - OpenaireBrokerEventMessageObject, + OpenaireQualityAssuranceEventMessageObject, } from '../../../core/notifications/qa/models/quality-assurance-event.model'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; import { Item } from '../../../core/shared/item.model'; @@ -98,7 +98,7 @@ export class ProjectEntryImportModalComponent implements OnInit { /** * The prefix for every i18n key within this modal */ - labelPrefix = 'notifications.broker.event.modal.'; + labelPrefix = 'quality-assurance.event.modal.'; /** * The search configuration to retrieve project */ @@ -181,7 +181,7 @@ export class ProjectEntryImportModalComponent implements OnInit { public ngOnInit(): void { this.pagination = Object.assign(new PaginationComponentOptions(), { id: 'notifications-project-bound', pageSize: this.pageSize }); this.projectTitle = (this.externalSourceEntry.projectTitle !== null) ? this.externalSourceEntry.projectTitle - : (this.externalSourceEntry.event.message as OpenaireBrokerEventMessageObject).title; + : (this.externalSourceEntry.event.message as OpenaireQualityAssuranceEventMessageObject).title; this.searchOptions = Object.assign(new PaginatedSearchOptions( { configuration: this.configuration, 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 5309098c555..20f4d4394a5 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.component.html +++ b/src/app/notifications/qa/source/quality-assurance-source.component.html @@ -1,15 +1,15 @@
-

{{'notifications.broker.title'| translate}}

-

{{'notifications.broker.source.description'| translate}}

+

{{'quality-assurance.title'| translate}}

+

{{'quality-assurance.source.description'| translate}}

-

{{'notifications.broker.source'| translate}}

+

{{'quality-assurance.source'| translate}}

- + {{'notifications.broker.source'| translate}}

[hideSortOptions]="true" (paginationChange)="getQualityAssuranceSource()"> - +
{{'notifications.broker.event.table.trust' | translate}}{{'notifications.broker.event.table.publication' | translate}}{{'notifications.broker.event.table.details' | translate}}{{'notifications.broker.event.table.project-details' | translate}}{{'notifications.broker.event.table.actions' | translate}}{{'quality-assurance.event.table.trust' | translate}}{{'quality-assurance.event.table.publication' | translate}}{{'quality-assurance.event.table.details' | translate}}{{'quality-assurance.event.table.project-details' | translate}}{{'quality-assurance.event.table.actions' | translate}}
-

{{'notifications.broker.event.table.pidtype' | translate}} {{eventElement.event.message.type}}

-

{{'notifications.broker.event.table.pidvalue' | translate}}
+

{{'quality-assurance.event.table.pidtype' | translate}} {{eventElement.event.message.type}}

+

{{'quality-assurance.event.table.pidvalue' | translate}}
{{eventElement.event.message.value}} @@ -60,37 +60,37 @@

-

{{'notifications.broker.event.table.subjectValue' | translate}}
{{eventElement.event.message.value}}

+

{{'quality-assurance.event.table.subjectValue' | translate}}
{{eventElement.event.message.value}}

- {{'notifications.broker.event.table.abstract' | translate}}
+ {{'quality-assurance.event.table.abstract' | translate}}
{{eventElement.event.message.abstract}}

- {{'notifications.broker.event.table.suggestedProject' | translate}} + {{'quality-assurance.event.table.suggestedProject' | translate}}

- {{'notifications.broker.event.table.project' | translate}}
+ {{'quality-assurance.event.table.project' | translate}}
{{eventElement.event.message.title}}

- {{'notifications.broker.event.table.acronym' | translate}} {{eventElement.event.message.acronym}}
- {{'notifications.broker.event.table.code' | translate}} {{eventElement.event.message.code}}
- {{'notifications.broker.event.table.funder' | translate}} {{eventElement.event.message.funder}}
- {{'notifications.broker.event.table.fundingProgram' | translate}} {{eventElement.event.message.fundingProgram}}
- {{'notifications.broker.event.table.jurisdiction' | translate}} {{eventElement.event.message.jurisdiction}} + {{'quality-assurance.event.table.acronym' | translate}} {{eventElement.event.message.acronym}}
+ {{'quality-assurance.event.table.code' | translate}} {{eventElement.event.message.code}}
+ {{'quality-assurance.event.table.funder' | translate}} {{eventElement.event.message.funder}}
+ {{'quality-assurance.event.table.fundingProgram' | translate}} {{eventElement.event.message.fundingProgram}}
+ {{'quality-assurance.event.table.jurisdiction' | translate}} {{eventElement.event.message.jurisdiction}}


- {{(eventElement.hasProject ? 'notifications.broker.event.project.found' : 'notifications.broker.event.project.notFound') | translate}} + {{(eventElement.hasProject ? 'quality-assurance.event.project.found' : 'quality-assurance.event.project.notFound') | translate}} {{eventElement.handle}}
- - - + + + @@ -39,7 +39,7 @@

{{'notifications.broker.source'| translate}}

{{'notifications.broker.table.source' | translate}}{{'notifications.broker.table.last-event' | translate}}{{'notifications.broker.table.actions' | translate}}{{'quality-assurance.table.source' | translate}}{{'quality-assurance.table.last-event' | translate}}{{'quality-assurance.table.actions' | translate}}
- - - + + + @@ -39,7 +39,7 @@

{{'notifications.broker.topics'| translate}}

@@ -155,13 +166,13 @@ @@ -25,8 +27,7 @@

[sortOptions]="paginationSortConfig" (paginationChange)="getQualityAssuranceEvents()"> - - + @@ -34,11 +35,15 @@

{{'notifications.broker.table.topic' | translate}}{{'notifications.broker.table.last-event' | translate}}{{'notifications.broker.table.actions' | translate}}{{'quality-assurance.table.topic' | translate}}{{'quality-assurance.table.last-event' | translate}}{{'quality-assurance.table.actions' | translate}}
-
+
- - -
- - - - - + + + + + @@ -51,7 +56,7 @@

{{eventElement.title}}

- + From 85deeaab6a32716ae55995ace4f5f3084775585e Mon Sep 17 00:00:00 2001 From: reetagithub <51482276+reetagithub@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:59:26 +0300 Subject: [PATCH 069/196] Update fi.json5 (#2422) * Update fi.json5 Two last translations to the Finnish file. --- src/assets/i18n/fi.json5 | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/assets/i18n/fi.json5 b/src/assets/i18n/fi.json5 index c56fcb6fecc..ede41ffb0c2 100644 --- a/src/assets/i18n/fi.json5 +++ b/src/assets/i18n/fi.json5 @@ -742,8 +742,7 @@ "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Voit lisätä tai poistaa ryhmän käyttäjän joko napsauttamalla 'Selaa kaikkia' -painiketta tai käyttämällä alla olevaa hakupalkkia käyttäjien etsimiseen (käytä hakupalkin vasemmalla puolella olevaa pudotusvalikkoa valitaksesi, haetaanko metatietojen vai sähköpostin perusteella). Napsauta sitten plus-kuvaketta jokaisen käyttäjän kohdalla, jonka haluat lisätä alla olevaan luetteloon, tai roskakorikuvaketta jokaisen käyttäjän kohdalla, jonka haluat poistaa. Alla olevassa luettelossa voi olla useita sivuja: voit siirtyä seuraaville sivuille luettelon alapuolella olevilla sivunohjaimilla. Kun olet valmis, tallenna muutokset napsauttamalla yläosassa olevaa Tallenna-painiketta.", // "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "To add or remove a Subgroup to/from this group, either click the 'Browse All' button or use the search bar below to search for users. Then click the plus icon for each user you wish to add in the list below, or the trash can icon for each user you wish to remove. The list below may have several pages: use the page controls below the list to navigate to the next pages. Once you are ready, save your changes by clicking the 'Save' button in the top section.", - // TODO New key - Add a translation - ree made ticket 2321 to DSpace's github - "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Jos haluat lisätä tai poistaa alaryhmän tähän ryhmään tai tästä ryhmästä, napsauta joko 'Selaa kaikkia' -painiketta tai käytä alla olevaa hakupalkkia käyttäjien etsimiseen. Napsauta sitten luettelossa plus-kuvaketta jokaisen käyttäjän kohdalla, jonka haluat lisätä, tai roskakorikuvaketta jokaisen käyttäjän kohdalla, jonka haluat poistaa. Luettelossa voi olla useita sivuja: voit siirtyä seuraaville sivuille luettelon alapuolella olevilla sivunohjaimilla. Kun olet valmis, tallenna muutokset napsauttamalla yläosassa olevaa Tallenna-painiketta.", + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Jos haluat lisätä tai poistaa alaryhmän tähän ryhmään tai tästä ryhmästä, napsauta joko 'Selaa kaikkia' -painiketta tai käytä alla olevaa hakupalkkia ryhmien etsimiseen. Napsauta sitten luettelossa plus-kuvaketta jokaisen ryhmän kohdalla, jonka haluat lisätä, tai roskakorikuvaketta jokaisen ryhmän kohdalla, jonka haluat poistaa. Luettelossa voi olla useita sivuja: voit siirtyä seuraaville sivuille luettelon alapuolella olevilla sivunohjaimilla. Kun olet valmis, tallenna muutokset napsauttamalla yläosassa olevaa Tallenna-painiketta.", // "admin.search.breadcrumbs": "Administrative Search", "admin.search.breadcrumbs": "Ylläpitäjän haku", @@ -7607,8 +7606,7 @@ "person.page.orcid.scope.authenticate": "Hae ORCID-tunnisteesi", // "person.page.orcid.scope.read-limited": "Read your information with visibility set to Trusted Parties", - // TODO New key - Add a translation - "person.page.orcid.scope.read-limited": "Read your information with visibility set to Trusted Parties", + "person.page.orcid.scope.read-limited": "Lue omat tietosi Trusted Parties -näkyvyysasetuksilla", // "person.page.orcid.scope.activities-update": "Add/update your research activities", "person.page.orcid.scope.activities-update": "Lisää/päivitä tutkimustoimiasi", @@ -7706,4 +7704,4 @@ // "admin.system-wide-alert.title": "System-wide Alerts", "admin.system-wide-alert.title": "Järjestelmänlaajuiset hälytykset", -} \ No newline at end of file +} From 6b5708cffda28620460f33ddc4fbf58ad9c6cb1d Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Mon, 25 Sep 2023 23:51:48 +0200 Subject: [PATCH 070/196] [DURACOM-185] Fix pointer on language dropdown menu --- src/app/shared/lang-switch/lang-switch.component.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/shared/lang-switch/lang-switch.component.scss b/src/app/shared/lang-switch/lang-switch.component.scss index 7b593a9bb59..ea099435a8e 100644 --- a/src/app/shared/lang-switch/lang-switch.component.scss +++ b/src/app/shared/lang-switch/lang-switch.component.scss @@ -9,3 +9,7 @@ color: var(--ds-header-icon-color-hover); } } + +.dropdown-item { + cursor: pointer; +} From c2250671277ce3e5d6101a496888daef151ece44 Mon Sep 17 00:00:00 2001 From: Alan Orth Date: Mon, 18 Sep 2023 14:40:19 +0300 Subject: [PATCH 071/196] src/app/shared/search: don't capitalize metadata values Don't capitalize metadata values for display purposes. (cherry picked from commit 47029c0a78d14c8e9d0557040223c0490eed42dd) --- .../search-facet-selected-option.component.html | 2 +- .../search-labels/search-label/search-label.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html index d5f88c53332..42fa7f9e6b5 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html @@ -4,7 +4,7 @@ [queryParams]="removeQueryParams" queryParamsHandling="merge"> diff --git a/src/app/shared/search/search-labels/search-label/search-label.component.html b/src/app/shared/search/search-labels/search-label/search-label.component.html index bffb7f9329b..17c5a487181 100644 --- a/src/app/shared/search/search-labels/search-label/search-label.component.html +++ b/src/app/shared/search/search-labels/search-label/search-label.component.html @@ -1,4 +1,4 @@ - {{('search.filters.applied.' + key) | translate}}: {{'search.filters.' + filterName + '.' + value | translate: {default: normalizeFilterValue(value)} }} From cae831bd41a078c5fed801ad5f56e0078a22742c Mon Sep 17 00:00:00 2001 From: Milos Ivanovic Date: Tue, 26 Sep 2023 07:29:17 +0200 Subject: [PATCH 072/196] Serbian (Latin) translation (#2508) Serbian (latin) translation added. --- config/config.example.yml | 5 +- src/assets/i18n/sr-lat.json5 | 2616 ++++++++++++++++++++++++++++++ src/config/default-app-config.ts | 1 + 3 files changed, 2621 insertions(+), 1 deletion(-) create mode 100644 src/assets/i18n/sr-lat.json5 diff --git a/config/config.example.yml b/config/config.example.yml index d2734bd28e1..d73a68e8aa3 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -208,6 +208,9 @@ languages: - code: pt-BR label: Português do Brasil active: true + - code: sr-lat + label: Srpski (lat) + active: true - code: fi label: Suomi active: true @@ -379,4 +382,4 @@ vocabularies: # Default collection/community sorting order at Advanced search, Create/update community and collection when there are not a query. comcolSelectionSort: sortField: 'dc.title' - sortDirection: 'ASC' \ No newline at end of file + sortDirection: 'ASC' diff --git a/src/assets/i18n/sr-lat.json5 b/src/assets/i18n/sr-lat.json5 new file mode 100644 index 00000000000..df8cfa18c9d --- /dev/null +++ b/src/assets/i18n/sr-lat.json5 @@ -0,0 +1,2616 @@ +{ + // Initial version provided by University of Kragujevac, Serbia 2023. + "401.help": "Niste ovlašćeni da pristupite ovoj stranici. Možete koristiti dugme ispod da se vratite na početnu stranicu.", + "401.link.home-page": "Odvedi me na početnu stranicu", + "401.unauthorized": "Neovlašćen pristup", + "403.help": "Nemate dozvolu da pristupite ovoj stranici. Možete koristiti dugme ispod da se vratite na početnu stranicu.", + "403.link.home-page": "Odvedi me na početnu stranicu", + "403.forbidden": "Zabranjen pristup", + "500.page-internal-server-error": "Usluga nije dostupna", + "500.help": "Server privremeno nije u mogućnosti da servisira vaš zahtev zbog zastoja u održavanju ili problema sa kapacitetom. Pokušajte ponovo kasnije.", + "500.link.home-page": "Odvedi me na početnu stranicu", + "404.help": "Ne možemo da pronađemo stranicu koju tražite. Stranica je možda premeštena ili izbrisana. Možete koristiti dugme ispod da se vratite na početnu stranicu.", + "404.link.home-page": "Odvedi me na početnu stranicu", + "404.page-not-found": "Stranica nije pronađena", + "error-page.description.401": "Neovlašćen pristup", + "error-page.description.403": "Zabranjen pristup", + "error-page.description.500": "Usluga nije dostupna", + "error-page.description.404": "Stranica nije pronađena", + "error-page.orcid.generic-error": "Došlo je do greške prilikom prijavljivanja preko ORCID-a. Uverite se da ste podelili imejl adresu svog ORCID naloga sa DSpace-om. Ako greška i dalje postoji, kontaktirajte administratora", + "access-status.embargo.listelement.badge": "Embargo", + "access-status.metadata.only.listelement.badge": "Samo metapodaci", + "access-status.open.access.listelement.badge": "Otvoren pristup", + "access-status.restricted.listelement.badge": "Ograničen pristup", + "access-status.unknown.listelement.badge": "Nepoznato", + "admin.curation-tasks.breadcrumbs": "Zadaci kuriranja sistema", + "admin.curation-tasks.title": "Zadaci kuriranja sistema", + "admin.curation-tasks.header": "Zadaci kuriranja sistema", + "admin.registries.bitstream-formats.breadcrumbs": "Formatirajte registar", + "admin.registries.bitstream-formats.create.breadcrumbs": "Format bitstream-a", + "admin.registries.bitstream-formats.create.failure.content": "Došlo je do greške pri kreiranju novog formata bitstream-a.", + "admin.registries.bitstream-formats.create.failure.head": "Neuspešno", + "admin.registries.bitstream-formats.create.head": "Kreirajte format bitstream-a", + "admin.registries.bitstream-formats.create.new": "Dodajte novi format bitstream-a", + "admin.registries.bitstream-formats.create.success.content": "Novi format bitstrim-a je uspešno kreiran.", + "admin.registries.bitstream-formats.create.success.head": "Uspešno", + "admin.registries.bitstream-formats.delete.failure.amount": "Uklanjanje {{ amount }} formata nije uspelo", + "admin.registries.bitstream-formats.delete.failure.head": "Neuspešno", + "admin.registries.bitstream-formats.delete.success.amount": "Uspešno uklonjen {{ amount }} format", + "admin.registries.bitstream-formats.delete.success.head": "Uspešno", + "admin.registries.bitstream-formats.description": "Ova lista formata bitstream-a pruža informacije o poznatim formatima i nivou njihove podrške.", + "admin.registries.bitstream-formats.edit.breadcrumbs": "Format bitstream-a", + "admin.registries.bitstream-formats.edit.description.hint": "", + "admin.registries.bitstream-formats.edit.description.label": "Opis", + "admin.registries.bitstream-formats.edit.extensions.hint": "Ekstenzije su ekstenzije fajlova koje se koriste za automatsku identifikaciju formata otpremljenih fajlova. Možete da unesete nekoliko ekstenzija za svaki format.", + "admin.registries.bitstream-formats.edit.extensions.label": "Ekstenzije fajlova", + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Unesite ekstenziju fajla bez tačke", + "admin.registries.bitstream-formats.edit.failure.content": "Došlo je do greške pri uređivanju formata bitstream-a", + "admin.registries.bitstream-formats.edit.failure.head": "Neuspešno", + "admin.registries.bitstream-formats.edit.head": "Format bitstream-a: {{ format }}", + "admin.registries.bitstream-formats.edit.internal.hint": "Formati označeni kao interni su skriveni od korisnika i koriste se u administrativne svrhe.", + "admin.registries.bitstream-formats.edit.internal.label": "Unutrašnje", + "admin.registries.bitstream-formats.edit.mimetype.hint": "MIME tip povezan sa ovim formatom ne mora biti jedinstven.", + "admin.registries.bitstream-formats.edit.mimetype.label": "MIME tip", + "admin.registries.bitstream-formats.edit.shortDescription.hint": "Jedinstveno ime za ovaj format, (npr. Microsoft Word XP ili Microsoft Word 2000)", + "admin.registries.bitstream-formats.edit.shortDescription.label": "Ime", + "admin.registries.bitstream-formats.edit.success.content": "Format bitstream-a je uspešno izmenjen.", + "admin.registries.bitstream-formats.edit.success.head": "Uspešno", + "admin.registries.bitstream-formats.edit.supportLevel.hint": "Nivo podrške koju vaša institucija obećava za ovaj format.", + "admin.registries.bitstream-formats.edit.supportLevel.label": "Nivo podrške", + "admin.registries.bitstream-formats.head": "Registar formata bitstream-a", + "admin.registries.bitstream-formats.no-items": "Nema formata bitova za prikaz.", + "admin.registries.bitstream-formats.table.delete": "Izbriši izabrano", + "admin.registries.bitstream-formats.table.deselect-all": "Poništite sve", + "admin.registries.bitstream-formats.table.internal": "Unutrašnje", + "admin.registries.bitstream-formats.table.mimetype": "MIME tip", + "admin.registries.bitstream-formats.table.name": "Ime", + "admin.registries.bitstream-formats.table.id": "ID", + "admin.registries.bitstream-formats.table.return": "Nazad", + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Poznato", + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Podržano", + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Nepoznato", + "admin.registries.bitstream-formats.table.supportLevel.head": "Nivo podrške", + "admin.registries.bitstream-formats.title": "Registar formata bitstream-a", + "admin.registries.metadata.breadcrumbs": "Registar metapodataka", + "admin.registries.metadata.description": "Registar metapodataka održava listu svih polja metapodataka dostupnih u spremištu. Ova polja mogu biti podeljena na više šema. Međutim, DSpace zahteva kvalifikovanu Dublin Core šemu", + "admin.registries.metadata.form.create": "Kreirajte šemu metapodataka", + "admin.registries.metadata.form.edit": "Uredite šemu metapodataka", + "admin.registries.metadata.form.name": "Ime", + "admin.registries.metadata.form.namespace": "Prostor imena", + "admin.registries.metadata.head": "Registar metapodataka", + "admin.registries.metadata.schemas.no-items": "Nema šema metapodataka za prikaz.", + "admin.registries.metadata.schemas.table.delete": "Izbriši izabrano", + "admin.registries.metadata.schemas.table.id": "ID", + "admin.registries.metadata.schemas.table.name": "Ime", + "admin.registries.metadata.schemas.table.namespace": "Prostor imena", + "admin.registries.metadata.title": "Registar metapodataka", + "admin.registries.schema.breadcrumbs": "Šema metapodataka", + "admin.registries.schema.description": "Ovo je šema metapodataka za \"{{namespace}}\".", + "admin.registries.schema.fields.head": "Polja metapodataka šeme", + "admin.registries.schema.fields.no-items": "Nema polja metapodataka za prikaz.", + "admin.registries.schema.fields.table.delete": "Izbriši izabrano", + "admin.registries.schema.fields.table.field": "Polje", + "admin.registries.schema.fields.table.id": "ID", + "admin.registries.schema.fields.table.scopenote": "Scope napomena", + "admin.registries.schema.form.create": "Kreirajte polje za metapodatke", + "admin.registries.schema.form.edit": "Izmenite polje za metapodatke", + "admin.registries.schema.form.element": "Element", + "admin.registries.schema.form.qualifier": "Kvalifikator", + "admin.registries.schema.form.scopenote": "Scope napomena", + "admin.registries.schema.head": "Šema metapodataka", + "admin.registries.schema.notification.created": "Uspešno kreirana šema metapodataka \"{{prefix}}\"", + "admin.registries.schema.notification.deleted.failure": "Neuspešno brisanje {{amount}} šema metapodataka", + "admin.registries.schema.notification.deleted.success": "Uspešno izbrisane {{amount}} šeme metapodataka", + "admin.registries.schema.notification.edited": "Uspešno izmenjena šema metapodataka \"{{prefix}}\"", + "admin.registries.schema.notification.failure": "Greška", + "admin.registries.schema.notification.field.created": "Uspešno kreirano polje metapodataka \"{{field}}\"", + "admin.registries.schema.notification.field.deleted.failure": "Neuspešno brisanje {{amount}} polja metapodataka ", + "admin.registries.schema.notification.field.deleted.success": "Uspešno izbrisana {{amount}} polja metapodataka", + "admin.registries.schema.notification.field.edited": "Uspešno izmenjeno polje metapodataka \"{{field}}\"", + "admin.registries.schema.notification.success": "Uspešno", + "admin.registries.schema.return": "Nazad", + "admin.registries.schema.title": "Registar šeme metapodataka", + "admin.access-control.bulk-access.breadcrumbs": "Upravljanje masovnim pristupom", + "administrativeBulkAccess.search.results.head": "Rezultati pretrage", + "admin.access-control.bulk-access": "Upravljanje masovnim pristupom", + "admin.access-control.bulk-access.title": "Upravljanje masovnim pristupom", + "admin.access-control.bulk-access-browse.header": "Korak 1: Izaberite objekte", + "admin.access-control.bulk-access-browse.search.header": "Pretraga", + "admin.access-control.bulk-access-browse.selected.header": "Trenutni izbor ({{number}})", + "admin.access-control.bulk-access-settings.header": "Korak 2: Operacija koju treba izvršiti", + "admin.access-control.epeople.actions.delete": "Izbrišite EPerson", + "admin.access-control.epeople.actions.impersonate": "Oponašati EPerson", + "admin.access-control.epeople.actions.reset": "Resetujte šifru", + "admin.access-control.epeople.actions.stop-impersonating": "Zaustavi predstavljanje kao EPerson", + "admin.access-control.epeople.breadcrumbs": "EPeople", + "admin.access-control.epeople.title": "EPeople", + "admin.access-control.epeople.head": "EPeople", + "admin.access-control.epeople.search.head": "Pretraga", + "admin.access-control.epeople.button.see-all": "Pregledajte sve", + "admin.access-control.epeople.search.scope.metadata": "Metapodaci", + "admin.access-control.epeople.search.scope.email": "E-mail (tačno)", + "admin.access-control.epeople.search.button": "Pretraga", + "admin.access-control.epeople.search.placeholder": "Pretražite ljude...", + "admin.access-control.epeople.button.add": "Dodajte EPerson", + "admin.access-control.epeople.table.id": "ID", + "admin.access-control.epeople.table.name": "Ime", + "admin.access-control.epeople.table.email": "E-mail (tačno)", + "admin.access-control.epeople.table.edit": "Izmena", + "admin.access-control.epeople.table.edit.buttons.edit": "Izmenite \"{{name}}\"", + "admin.access-control.epeople.table.edit.buttons.edit-disabled": "Niste ovlašćeni za uređivanje ove grupe", + "admin.access-control.epeople.table.edit.buttons.remove": "Izbrišite \"{{name}}\"", + "admin.access-control.epeople.no-items": "Nema EPeople za prikaz.", + "admin.access-control.epeople.form.create": "Kreirajte EPerson", + "admin.access-control.epeople.form.edit": "Izmenite EPerson", + "admin.access-control.epeople.form.firstName": "Ime", + "admin.access-control.epeople.form.lastName": "Prezime", + "admin.access-control.epeople.form.email": "E-mail", + "admin.access-control.epeople.form.emailHint": "Mora biti važeća e-mail adresa", + "admin.access-control.epeople.form.canLogIn": "Može se prijaviti", + "admin.access-control.epeople.form.requireCertificate": "Potreban je sertifikat", + "admin.access-control.epeople.form.return": "Nazad", + "admin.access-control.epeople.form.notification.created.success": "Uspešno kreiran EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure": "Neuspešno kreiranje EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure.emailInUse": "Neuspešno kreiranje EPerson \"{{name}}\", email \"{{email}}\" se već koristi.", + "admin.access-control.epeople.form.notification.edited.failure.emailInUse": "Neuspešna izmena EPerson \"{{name}}\", email \"{{email}}\" se već koristi.", + "admin.access-control.epeople.form.notification.edited.success": "Uspešno izmenjen EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.edited.failure": "Neuspešna izmena EPerson \"{{name}}\" ", + "admin.access-control.epeople.form.notification.deleted.success": "Uspešno izbrisan EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.failure": "Neuspešno brisanje EPerson \"{{name}}\" ", + "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Član ovih grupa:", + "admin.access-control.epeople.form.table.id": "ID", + "admin.access-control.epeople.form.table.name": "Ime", + "admin.access-control.epeople.form.table.collectionOrCommunity": "Kolekcija/Zajednica", + "admin.access-control.epeople.form.memberOfNoGroups": "Ovaj EPerson nije član nijedne grupe", + "admin.access-control.epeople.form.goToGroups": "Dodajte grupama", + "admin.access-control.epeople.notification.deleted.failure": "Neuspešno brisanje EPerson: \"{{name}}\"", + "admin.access-control.epeople.notification.deleted.success": "Uspešno izbrisan EPerson: \"{{name}}\"", + "admin.access-control.groups.title": "Grupe", + "admin.access-control.groups.breadcrumbs": "Grupe", + "admin.access-control.groups.singleGroup.breadcrumbs": "Izmenite grupu", + "admin.access-control.groups.title.singleGroup": "Izmenite grupu", + "admin.access-control.groups.title.addGroup": "Nova grupa", + "admin.access-control.groups.addGroup.breadcrumbs": "Nova grupa", + "admin.access-control.groups.head": "Grupe", + "admin.access-control.groups.button.add": "Dodajte grupu", + "admin.access-control.groups.search.head": "Pretraga grupa", + "admin.access-control.groups.button.see-all": "Pregledajte sve", + "admin.access-control.groups.search.button": "Pretraga", + "admin.access-control.groups.search.placeholder": "Pretražite grupe...", + "admin.access-control.groups.table.id": "ID", + "admin.access-control.groups.table.name": "Ime", + "admin.access-control.groups.table.collectionOrCommunity": "Kolekcija/Zajednica", + "admin.access-control.groups.table.members": "Članovi", + "admin.access-control.groups.table.edit": "Izmeniti", + "admin.access-control.groups.table.edit.buttons.edit": "Izmenite \"{{name}}\"", + "admin.access-control.groups.table.edit.buttons.remove": "Izbrišite \"{{name}}\"", + "admin.access-control.groups.no-items": "Nije pronađena nijedna grupa sa ovim u svom imenu ili ovim kao UUID", + "admin.access-control.groups.notification.deleted.success": "Uspešno izbrisana grupa \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.title": "Neuspešno brisanje grupe \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.content": "Uzrok: \"{{cause}}\"", + "admin.access-control.groups.form.alert.permanent": "Ova grupa je trajna, tako da se ne može menjati ili brisati. I dalje možete da dodajete i uklanjate članove grupe koristeći ovu stranicu.", + "admin.access-control.groups.form.alert.workflowGroup": "Ova grupa se ne može izmeniti ili izbrisati jer odgovara ulozi u procesu slanja i toka posla u \"{{name}}\" {{comcol}}. Možete je izbrisati sa kartice \"dodeli uloge\" na stranici za uređivanje {{comcol}}. I dalje možete da dodajete i uklanjate članove grupe koristeći ovu stranicu.", + "admin.access-control.groups.form.head.create": "Kreiraj grupu", + "admin.access-control.groups.form.head.edit": "Izmeni grupu", + "admin.access-control.groups.form.groupName": "Naziv grupe", + "admin.access-control.groups.form.groupCommunity": "Zajednica ili kolekcija", + "admin.access-control.groups.form.groupDescription": "Opis", + "admin.access-control.groups.form.notification.created.success": "Uspešno kreirana Grupa \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure": "Neuspešno kreiranje Grupe \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure.groupNameInUse": "Neuspešno kreiranje Grupe sa imenom: \"{{name}}\", proverite da ime nije već upotrebljeno.", + "admin.access-control.groups.form.notification.edited.failure": "Neuspešna izmena Grupe \"{{name}}\"", + "admin.access-control.groups.form.notification.edited.failure.groupNameInUse": "Naziv \"{{name}}\" se već koristi!", + "admin.access-control.groups.form.notification.edited.success": "Grupa \"{{name}}\" je uspešno izmenjena", + "admin.access-control.groups.form.actions.delete": "Izbrišite grupu", + "admin.access-control.groups.form.delete-group.modal.header": "Izbrišite grupu \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.info": "Da li ste sigurni da želite da izbrišete grupu \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.cancel": "Poništiti, otkazati", + "admin.access-control.groups.form.delete-group.modal.confirm": "Izbrišite", + "admin.access-control.groups.form.notification.deleted.success": "Grupa \"{{ name }}\" je uspešno obrisana", + "admin.access-control.groups.form.notification.deleted.failure.title": "Brisanje grupe \"{{ name }}\" nije uspelo", + "admin.access-control.groups.form.notification.deleted.failure.content": "Uzrok: \"{{ uzrok }}\"", + "admin.access-control.groups.form.members-list.head": "EPeople", + "admin.access-control.groups.form.members-list.search.head": "Dodajte EPeople", + "admin.access-control.groups.form.members-list.button.see-all": "Pregledajte sve", + "admin.access-control.groups.form.members-list.headMembers": "Trenutni članovi", + "admin.access-control.groups.form.members-list.search.scope.metadata": "Metapodatak", + "admin.access-control.groups.form.members-list.search.scope.email": "E-mail (tačno)", + "admin.access-control.groups.form.members-list.search.button": "Pretraga", + "admin.access-control.groups.form.members-list.table.id": "ID", + "admin.access-control.groups.form.members-list.table.name": "Ime", + "admin.access-control.groups.form.members-list.table.identity": "Identitet", + "admin.access-control.groups.form.members-list.table.email": "Email", + "admin.access-control.groups.form.members-list.table.netid": "NetID", + "admin.access-control.groups.form.members-list.table.edit": "Ukloni / Dodaj", + "admin.access-control.groups.form.members-list.table.edit.buttons.remove": "Uklonite člana sa imenom \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.addMember": "Član je uspešno dodat: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.addMember": "Dodavanje člana nije uspelo: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.deleteMember": "Uspešno obrisan član: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.deleteMember": "Brisanje člana nije uspelo: \"{{name}}\"", + "admin.access-control.groups.form.members-list.table.edit.buttons.add": "Dodaj člana sa imenom \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup": "Nema trenutno aktivne grupe, prvo pošaljite ime.", + "admin.access-control.groups.form.members-list.no-members-yet": "Još nema članova u grupi, pretražite i dodajte.", + "admin.access-control.groups.form.members-list.no-items": "Nijedan EPeople nije pronađen u toj pretrazi", + "admin.access-control.groups.form.subgroups-list.notification.failure": "Nešto nije u redu: \"{{cause}}\"", + "admin.access-control.groups.form.subgroups-list.head": "Grupe", + "admin.access-control.groups.form.subgroups-list.search.head": "Dodajte podgrupu", + "admin.access-control.groups.form.subgroups-list.button.see-all": "Pregledajte sve", + "admin.access-control.groups.form.subgroups-list.headSubgroups": "Trenutne podgrupe", + "admin.access-control.groups.form.subgroups-list.search.button": "Pretraga", + "admin.access-control.groups.form.subgroups-list.table.id": "ID", + "admin.access-control.groups.form.subgroups-list.table.name": "Ime", + "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Kolekcija/Zajednica", + "admin.access-control.groups.form.subgroups-list.table.edit": "Ukloni / Dodaj", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove": "Uklonite podgrupu sa imenom \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add": "Dodajte podgrupu sa imenom \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup": "Trenutna grupa", + "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup": "Podgrupa je uspešno dodata: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup": "Dodavanje podgrupe nije uspelo: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup": "Uspešno obrisana podgrupa: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup": "Brisanje podgrupe nije uspelo: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup": "Nema trenutno aktivne grupe, prvo pošaljite ime.", + "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup": "Ovo je trenutna grupa, ne može se dodati.", + "admin.access-control.groups.form.subgroups-list.no-items": "Nije pronađena nijedna grupa sa ovim u svom imenu ili ovim kao UUID", + "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "Još nema podgrupa u grupi.", + "admin.access-control.groups.form.return": "Nazad", + "admin.access-control.groups.form.tooltip.editGroupPage": "Na ovoj stranici možete da menjate svojstva i članove grupe. U gornjem odeljku možete da izmenite ime i opis grupe, osim ako je ovo administratorska grupa za kolekciju ili zajednicu, u kom slučaju se ime i opis grupe automatski generišu i ne mogu se menjati. U sledećim odeljcima možete da menjate članstvo u grupi. Pogledajte [viki](https://viki.lirasis.org/displai/DSDOC7k/Create+or+manage+a+user+group) za više detalja.", + "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Da biste dodali ili uklonili Eperson u/iz ove grupe, ili kliknite na dugme 'Pregledaj sve' ili koristite traku za pretragu ispod da biste pretražili korisnike (koristite padajući meni sa leve strane trake za pretragu da biste izabrali da li ćete pretraživati prema metapodacima ili prema e-mailu). Zatim kliknite na ikonu plus za svakog korisnika kojeg želite da dodate na listu ispod ili na ikonu korpe za smeće za svakog korisnika kojeg želite da uklonite. Lista u nastavku može imati nekoliko stranica: koristite kontrole stranice ispod liste da biste prešli na sledeće stranice. Kada budete spremni, sačuvajte promene klikom na dugme \"Sačuvaj\" u gornjem delu.", + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Da biste dodali ili uklonili podgrupu u/iz ove grupe, kliknite na dugme 'Pregledaj sve' ili koristite traku za pretragu ispod da biste pretražili korisnike. Zatim kliknite na ikonu plus za svakog korisnika kojeg želite da dodate na listu ispod ili na ikonu korpe za smeće za svakog korisnika kojeg želite da uklonite. Lista u nastavku može imati nekoliko stranica: koristite kontrole stranice ispod liste da biste prešli na sledeće stranice. Kada budete spremni, sačuvajte promene klikom na dugme \"Sačuvaj\" u gornjem delu.", + "admin.search.breadcrumbs": "Administrativna pretraga", + "admin.search.collection.edit": "Uredite", + "admin.search.community.edit": "Uredite", + "admin.search.item.delete": "Izbrišite", + "admin.search.item.edit": "Uredite", + "admin.search.item.make-private": "Učinite nevidljivim", + "admin.search.item.make-public": "Učinite vidljivim", + "admin.search.item.move": "Pomerite", + "admin.search.item.reinstate": "Reinstate", + "admin.search.item.withdraw": "Odustati", + "admin.search.title": "Administrativna pretraga", + "administrativeView.search.results.head": "Administrativna pretraga", + "admin.workflow.breadcrumbs": "Administriranje radnog procesa", + "admin.workflow.title": "Administriranje radnog procesa", + "admin.workflow.item.workflow": "Proces rada", + "admin.workflow.item.workspace": "Radni prostor", + "admin.workflow.item.delete": "Izbrišite", + "admin.workflow.item.send-back": "Vratite", + "admin.workflow.item.policies": "Politike", + "admin.workflow.item.supervision": "Nadzor", + "admin.metadata-import.breadcrumbs": "Uvezi metapodatke", + "admin.batch-import.breadcrumbs": "Uvezi Batch", + "admin.metadata-import.title": "Uvezi metapodatke", + "admin.batch-import.title": "Uvezi Batch", + "admin.metadata-import.page.header": "Uvezite metapodatke", + "admin.batch-import.page.header": "Uvezi Batch", + "admin.metadata-import.page.help": "Ovde možete da prevučete ili pregledate CSV fajlove koji sadrže batch operacije metapodataka za fajlove", + "admin.batch-import.page.help": "Izaberite kolekciju u koju želite da uvezete. Zatim prevucite ili potražite zip fajl jednostavnog arhivskog formata (SAF) koja uključuje stavke za uvoz", + "admin.batch-import.page.toggle.help": "Moguće je izvršiti uvoz bilo sa otpremanjem fajla ili preko URL-a, koristite gornji prekidač da biste podesili izvor unosa", + "admin.metadata-import.page.dropMsg": "Prevucite CSV sa metapodacima za uvoz", + "admin.batch-import.page.dropMsg": "Prevucite batch ZIP za uvoz", + "admin.metadata-import.page.dropMsgReplace": "Prevucite da zamenite CSV sa metapodacima za uvoz", + "admin.batch-import.page.dropMsgReplace": "Prevucite da zamenite batch ZIP za uvoz", + "admin.metadata-import.page.button.return": "Nazad", + "admin.metadata-import.page.button.proceed": "Nastavite", + "admin.metadata-import.page.button.select-collection": "Izaberite kolekciju", + "admin.metadata-import.page.error.addFile": "Prvo izaberite fajl!", + "admin.metadata-import.page.error.addFileUrl": "Prvo unesite url fajl!", + "admin.batch-import.page.error.addFile": "Prvo izaberite Zip fajl!", + "admin.metadata-import.page.toggle.upload": "Otpremite", + "admin.metadata-import.page.toggle.url": "URL", + "admin.metadata-import.page.urlMsg": "Umetnite batch ZIP URL za uvoz", + "admin.metadata-import.page.validateOnly": "Samo validiraj", + "admin.metadata-import.page.validateOnly.hint": "Kada se izabere, otpremljeni CSV će biti potvrđen. Dobićete izveštaj o utvrđenim promenama, ali promene neće biti sačuvane.", + "advanced-workflow-action.rating.form.rating.label": "Ocena", + "advanced-workflow-action.rating.form.rating.error": "Morate oceniti stavku", + "advanced-workflow-action.rating.form.review.label": "Pregled", + "advanced-workflow-action.rating.form.review.error": "Morate uneti recenziju da biste poslali ovu ocenu", + "advanced-workflow-action.rating.description": "Molimo izaberite ocenu ispod", + "advanced-workflow-action.rating.description-requiredDescription": "Molimo izaberite ocenu ispod i dodajte recenziju", + "advanced-workflow-action.select-reviewer.description-single": "Molimo izaberite jednog recenzenta ispod pre slanja", + "advanced-workflow-action.select-reviewer.description-multiple": "Molimo izaberite jednog ili više recenzenata ispod pre slanja", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Dodajte EPeople", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Pregledajte sve", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Trenutni članovi", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metapodaci", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "E-mail (tačno)", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Pretraga", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Ime", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identitet", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Email", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Uklonite / Dodajte", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Uklonite člana sa imenom \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Uspešno dodat član: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Neuspešno dodavanje člana: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Uspešno izbrisan član: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Neuspešno brisanje člana: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Dodajte člana sa imenom \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Trenutno nema aktivne grupe, prvo unesite ime.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "Još nema članova u grupi, pretražite i dodajte.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "Nijedan EPeople nije pronađen u toj pretrazi", + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Nije izabran recenzent.", + "admin.batch-import.page.validateOnly.hint": "Kada se izabere, otpremljeni ZIP će biti potvrđen. Dobićete izveštaj o utvrđenim promenama, ali promene neće biti sačuvane.", + "admin.batch-import.page.remove": "ukloniti", + "auth.errors.invalid-user": "Pogrešna e-mail adresa ili lozinka.", + "auth.messages.expired": "Vaša sesija je istekla. Molimo prijavite se ponovo.", + "auth.messages.token-refresh-failed": "Osvežavanje tokena sesije nije uspelo. Molimo prijavite se ponovo.", + "bitstream.download.page": "Trenutno se preuzima {{bitstream}}...", + "bitstream.download.page.back": "Nazad", + "bitstream.edit.authorizations.link": "Izmenite polise bitstream-a", + "bitstream.edit.authorizations.title": "Izmenite polise bitstream-a", + "bitstream.edit.return": "Nazad", + "bitstream.edit.bitstream": "Bitstream:", + "bitstream.edit.form.description.hint": "Opciono, navedite kratak opis fajla, na primer \"Glavni članak\" ili \"Očitavanja podataka eksperimenta\".", + "bitstream.edit.form.description.label": "Opis", + "bitstream.edit.form.embargo.hint": "Prvi dan od kojeg je pristup dozvoljen. Ovaj datum se ne može izmeniti u ovom obrascu. Da biste postavili datum zabrane za bitstream, idite na karticu Status stavke, kliknite na Ovlašćenja..., kreirajte ili izmenite politiku bitstream-ovaPROČITAJTE i postavite Datum početka po želji.", + "bitstream.edit.form.embargo.label": "Zabrana do određenog datuma", + "bitstream.edit.form.fileName.hint": "Promenite ime fajla za bitstream. Imajte na umu da će se ovim promeniti prikazani bitstream URL, ali će se stari linkovi i dalje razrešiti sve dok se ID sekvence ne promeni.", + "bitstream.edit.form.fileName.label": "Ime fajla", + "bitstream.edit.form.newFormat.label": "Opišite novi format", + "bitstream.edit.form.newFormat.hint": "Aplikacija koju ste koristili za kreiranje fajla, i broj verzije (na primer, \"ACMESoft SuperApp verzija 1.5\").", + "bitstream.edit.form.primaryBitstream.label": "Primarni bitstream", + "bitstream.edit.form.selectedFormat.hint": "Ako format nije na gornjoj listi, izaberite \"format nije na listi\" iznad i opišite ga pod \"Opišite novi format\".", + "bitstream.edit.form.selectedFormat.label": "Izabrani format", + "bitstream.edit.form.selectedFormat.unknown": "Format nije na listi", + "bitstream.edit.notifications.error.format.title": "Došlo je do greške prilikom čuvanja bitstream formata", + "bitstream.edit.notifications.error.primaryBitstream.title": "Došlo je do greške prilikom čuvanja primarnog bitstream-a", + "bitstream.edit.form.iiifLabel.label": "IIIF oznaka", + "bitstream.edit.form.iiifLabel.hint": "Oznaka canvas-a za ovu sliku. Ako nije data, koristiće se podrazumevana oznaka.", + "bitstream.edit.form.iiifToc.label": "IIIF Pregled sadržaja", + "bitstream.edit.form.iiifToc.hint": "Dodavanje teksta ovde, čini ovo mesto početkom novog opsega sadržaja.", + "bitstream.edit.form.iiifWidth.label": "IIIF širina platna", + "bitstream.edit.form.iiifWidth.hint": "Širina canvas-a obično treba da odgovara širini slike.", + "bitstream.edit.form.iiifHeight.label": "IIIF visina platna", + "bitstream.edit.form.iiifHeight.hint": "Visina canvas-a obično treba da odgovara visini slike.", + "bitstream.edit.notifications.saved.content": "Vaše promene u ovom bitstream-u su sačuvane.", + "bitstream.edit.notifications.saved.title": "Bitstream je sačuvan", + "bitstream.edit.title": "Izmenite bitstream", + "bitstream-request-a-copy.alert.canDownload1": "Već imate pristup ovom fajlu. Ako želite da preuzmete fajl, kliknite", + "bitstream-request-a-copy.alert.canDownload2": "ovde", + "bitstream-request-a-copy.header": "Zatražite kopiju fajla", + "bitstream-request-a-copy.intro": "Unesite sledeće informacije da biste zatražili kopiju sledeće stavke:", + "bitstream-request-a-copy.intro.bitstream.one": "Zahteva se sledeći fajl:", + "bitstream-request-a-copy.intro.bitstream.all": "Zahtevaju se svi fajlovi.", + "bitstream-request-a-copy.name.label": "ime *", + "bitstream-request-a-copy.name.error": "Ime je obavezno", + "bitstream-request-a-copy.email.label": "Vaša email adresa *", + "bitstream-request-a-copy.email.hint": "Ova e-mail adresa se koristi za slanje fajla.", + "bitstream-request-a-copy.email.error": "Molim Vas unesite ispravnu e-mail adresu.", + "bitstream-request-a-copy.allfiles.label": "Fajlovi", + "bitstream-request-a-copy.files-all-false.label": "Samo traženi fajl", + "bitstream-request-a-copy.files-all-true.label": "Sve fajlovi (ove stavke) u ograničenom pristupu", + "bitstream-request-a-copy.message.label": "Poruka", + "bitstream-request-a-copy.return": "Nazad", + "bitstream-request-a-copy.submit": "Zahtevaj kopiju", + "bitstream-request-a-copy.submit.success": "Zahtev za stavku je uspešno dostavljen.", + "bitstream-request-a-copy.submit.error": "Nešto nije u redu sa slanjem zahteva za stavku.", + "browse.back.all-results": "Svi rezultati pregleda", + "browse.comcol.by.author": "Po autoru", + "browse.comcol.by.dateissued": "Po datumu izdanja", + "browse.comcol.by.subject": "Po predmetu", + "browse.comcol.by.srsc": "Po kategoriji predmeta", + "browse.comcol.by.title": "Po naslovu", + "browse.comcol.head": "Pregledajte", + "browse.empty": "Nema stavki za prikaz.", + "browse.metadata.author": "Autoru", + "browse.metadata.dateissued": "Datumu izdanja", + "browse.metadata.subject": "Predmetu", + "browse.metadata.title": "Naslovu", + "browse.metadata.author.breadcrumbs": "Pregled po autoru", + "browse.metadata.dateissued.breadcrumbs": "Pregled po datumu", + "browse.metadata.subject.breadcrumbs": "Pregled po predmetu", + "browse.metadata.srsc.breadcrumbs": "Pregled po kategoriji predmeta", + "browse.metadata.title.breadcrumbs": "Pregled po naslovu", + "pagination.next.button": "Sledeće", + "pagination.previous.button": "Prethodno", + "pagination.next.button.disabled.tooltip": "Nema više stranica sa rezultatima", + "browse.startsWith": ", počevši od {{ startsWith }}", + "browse.startsWith.choose_start": "(Izaberite početak)", + "browse.startsWith.choose_year": "(Izaberite godinu)", + "browse.startsWith.choose_year.label": "Izaberite godinu izdanja", + "browse.startsWith.jump": "Filtrirajte rezultate po godini ili mesecu", + "browse.startsWith.months.april": "April", + "browse.startsWith.months.august": "Avgust", + "browse.startsWith.months.december": "Decembar", + "browse.startsWith.months.february": "Februar", + "browse.startsWith.months.january": "Januar", + "browse.startsWith.months.july": "Jul", + "browse.startsWith.months.june": "Jun", + "browse.startsWith.months.march": "Mart", + "browse.startsWith.months.may": "Maj ", + "browse.startsWith.months.none": "(Izaberite mesec)", + "browse.startsWith.months.none.label": "Izaberite mesec izdanja", + "browse.startsWith.months.november": "Novembar", + "browse.startsWith.months.october": "Oktobar", + "browse.startsWith.months.september": "Septembar", + "browse.startsWith.submit": "Pregledaj", + "browse.startsWith.type_date": "Filtrirajte rezultate po datumu", + "browse.startsWith.type_date.label": "Ili unesite datum (godina-mesec) i kliknite na dugme Pregledaj", + "browse.startsWith.type_text": "Filtrirajte rezultate upisivanjem prvih nekoliko slova", + "browse.startsWith.input": "Filter", + "browse.taxonomy.button": "Pregledaj", + "browse.title": "Pregledanje {{ collection }} prema {{ field }}{{ startsWith }} {{ value }}", + "browse.title.page": "Pregledanje {{ collection }} prema {{ field }} {{ value }}", + "search.browse.item-back": "Nazad na rezultate", + "chips.remove": "Uklonite čip", + "claimed-approved-search-result-list-element.title": "Odobreno", + "claimed-declined-search-result-list-element.title": "Odbijeno, vraćeno podnosiocu", + "claimed-declined-task-search-result-list-element.title": "Odbijeno, vraćeno menadžeru za pregled", + "collection.create.head": "Napravite kolekciju", + "collection.create.notifications.success": "Kolekcija je uspešno napravljena", + "collection.create.sub-head": "Napravite kolekciju za zajednicu {{ parent }}", + "collection.curate.header": "Sačuvaj kolekciju: {{collection}}", + "collection.delete.cancel": "Poništiti, otkazati", + "collection.delete.confirm": "Potvrdi", + "collection.delete.processing": "Brisanje", + "collection.delete.head": "Izbrišite kolekciju", + "collection.delete.notification.fail": "Kolekcija se ne može izbrisati", + "collection.delete.notification.success": "Kolekcija je uspešno izbrisana", + "collection.delete.text": "Da li ste sigurni da želite da izbrišete kolekciju \"{{ dso }}\"", + "collection.edit.delete": "Izbrišite ovu kolekciju", + "collection.edit.head": "Uredite kolekciju", + "collection.edit.breadcrumbs": "Uredite kolekciju", + "collection.edit.tabs.mapper.head": "Mapiranje stavki", + "collection.edit.tabs.item-mapper.title": "Uređivanje kolekcije - mapiranje stavki", + "collection.edit.item-mapper.cancel": "Poništiti, otkazati", + "collection.edit.item-mapper.collection": "Kolekcija: \"{{name}}\"", + "collection.edit.item-mapper.confirm": "Mapirajte izabrane stavke", + "collection.edit.item-mapper.description": "Ovo je alatka za mapiranje stavki koja omogućava administratorima kolekcije da mapiraju stavke iz drugih kolekcija u ovu kolekciju. Možete tražiti stavke iz drugih kolekcija i mapirati ih ili pregledati listu trenutno mapiranih stavki.", + "collection.edit.item-mapper.head": "Mapiranje stavki - mapa stavki iz drugih kolekcija", + "collection.edit.item-mapper.no-search": "Unesite upit za pretragu", + "collection.edit.item-mapper.notifications.map.error.content": "Došlo je do grešaka za mapiranje {{amount}} stavki.", + "collection.edit.item-mapper.notifications.map.error.head": "Greške u mapiranju", + "collection.edit.item-mapper.notifications.map.success.content": "Uspešno mapirane {{amount}} stavke.", + "collection.edit.item-mapper.notifications.map.success.head": "Mapiranje je završeno", + "collection.edit.item-mapper.notifications.unmap.error.content": "Došlo je do grešaka pri uklanjanju mapiranja stavki {{amount}}.", + "collection.edit.item-mapper.notifications.unmap.error.head": "Uklonite greške mapiranja", + "collection.edit.item-mapper.notifications.unmap.success.content": "Uspešno su uklonjena mapiranja {{amount}} stavki.", + "collection.edit.item-mapper.notifications.unmap.success.head": "Uklanjanje mapiranja je završeno", + "collection.edit.item-mapper.remove": "Uklanjanje mapiranja izabranih stavki", + "collection.edit.item-mapper.search-form.placeholder": "Pretraži stavke...", + "collection.edit.item-mapper.tabs.browse": "Pregledajte mapirane stavke", + "collection.edit.item-mapper.tabs.map": "Mapirajte nove stavke", + "collection.edit.logo.delete.title": "Izbrišite logo", + "collection.edit.logo.delete-undo.title": "Opozovi brisanje", + "collection.edit.logo.label": "Logo kolekcije", + "collection.edit.logo.notifications.add.error": "Otpremanje loga kolekcije nije uspelo. Proverite sadržaj pre ponovnog pokušaja.", + "collection.edit.logo.notifications.add.success": "Otpremanje loga kolekcije je uspešno.", + "collection.edit.logo.notifications.delete.success.title": "Logo je izbrisan", + "collection.edit.logo.notifications.delete.success.content": "Uspešno je obrisan logo kolekcije", + "collection.edit.logo.notifications.delete.error.title": "Greška pri brisanju loga", + "collection.edit.logo.upload": "Prevucite logotip kolekcije za otpremanje", + "collection.edit.notifications.success": "Uspešno uređena kolekcija", + "collection.edit.return": "Nazad", + "collection.edit.tabs.access-control.head": "Kontrola pristupa", + "collection.edit.tabs.access-control.title": "Uređivanje kolekcije - Kontrola pristupa", + "collection.edit.tabs.curate.head": "Curate", + "collection.edit.tabs.curate.title": "Uređivanje kolekcije - Curate", + "collection.edit.tabs.authorizations.head": "Ovlašćenja", + "collection.edit.tabs.authorizations.title": "Uređivanje kolekcije - ovlašćenja", + "collection.edit.item.authorizations.load-bundle-button": "Učitajte još paketa", + "collection.edit.item.authorizations.load-more-button": "Učitaj više", + "collection.edit.item.authorizations.show-bitstreams-button": "Prikaži bitstream smernice za paket", + "collection.edit.tabs.metadata.head": "Uredi metapodatke", + "collection.edit.tabs.metadata.title": "Uređivanje kolekcije - Metapodaci", + "collection.edit.tabs.roles.head": "Dodeli uloge", + "collection.edit.tabs.roles.title": "Uređivanje kolekcije - Uloge", + "collection.edit.tabs.source.external": "Ova kolekcija prikuplja svoj sadržaj iz spoljašnjeg izvora", + "collection.edit.tabs.source.form.errors.oaiSource.required": "Morate da obezbedite set ID ciljne kolekcije.", + "collection.edit.tabs.source.form.harvestType": "Sadržaj se prikuplja", + "collection.edit.tabs.source.form.head": "Konfigurišite spoljni izvor", + "collection.edit.tabs.source.form.metadataConfigId": "Format metapodataka", + "collection.edit.tabs.source.form.oaiSetId": "ID specifičnog skupa za OAI", + "collection.edit.tabs.source.form.oaiSource": "OAI provajder", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Sakupite metapodatke i bitstream-ove (zahteva ORE podršku)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF": "Sakupite metapodatke i reference na bitstream-ove (zahteva ORE podršku)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Samo prikupljeni metapodaci", + "collection.edit.tabs.source.head": "Izvor sadržaja", + "collection.edit.tabs.source.notifications.discarded.content": "Vaše promene su odbačene. Da biste ponovo postavili svoje promene, kliknite na dugme \"Opozovi\".", + "collection.edit.tabs.source.notifications.discarded.title": "Promene su odbačene", + "collection.edit.tabs.source.notifications.invalid.content": "Vaše promene nisu sačuvane. Proverite da li su sva polja ispravna pre nego što sačuvate.", + "collection.edit.tabs.source.notifications.invalid.title": "Metapodaci su nevažeći", + "collection.edit.tabs.source.notifications.saved.content": "Vaše promene izvora sadržaja ove kolekcije su sačuvane.", + "collection.edit.tabs.source.notifications.saved.title": "Izvor sadržaja je sačuvan", + "collection.edit.tabs.source.title": "Uređivanje kolekcije – Izvor sadržaja", + "collection.edit.template.add-button": "Dodati", + "collection.edit.template.breadcrumbs": "Šablon stavke", + "collection.edit.template.cancel": "Otkazati", + "collection.edit.template.delete-button": "Izbrišite", + "collection.edit.template.edit-button": "Izmenite", + "collection.edit.template.error": "Došlo je do greške pri preuzimanju stavke šablona", + "collection.edit.template.head": "Izmenite stavku šablona za kolekciju \"{{ collection }}\"", + "collection.edit.template.label": "Stavka šablona", + "collection.edit.template.loading": "Učitava se stavka šablona...", + "collection.edit.template.notifications.delete.error": "Neuspešno brisanje šablona stavke", + "collection.edit.template.notifications.delete.success": "Uspešno obrisan šablon stavke", + "collection.edit.template.title": "Izmenite stavku šablona", + "collection.form.abstract": "Kratak opis", + "collection.form.description": "Uvodni tekst (HTML)", + "collection.form.errors.title.required": "Molimo unesite ime kolekcije", + "collection.form.license": "Licenca", + "collection.form.provenance": "Poreklo", + "collection.form.rights": "Autorski tekst (HTML)", + "collection.form.tableofcontents": "Vesti (HTML)", + "collection.form.title": "Ime", + "collection.form.entityType": "Tip entiteta", + "collection.listelement.badge": "Kolekcija", + "collection.page.browse.recent.head": "Nedavni podnesci", + "collection.page.browse.recent.empty": "Nema stavki za prikaz", + "collection.page.edit": "Izmenite ovu kolekciju", + "collection.page.handle": "Trajni URI za ovu kolekciju", + "collection.page.license": "Licenca", + "collection.page.news": "Vesti", + "collection.select.confirm": "Potvrdite izabrano", + "collection.select.empty": "Nema kolekcija za prikaz", + "collection.select.table.title": "Naslov", + "collection.source.controls.head": "Kontrola prikupljanja", + "collection.source.controls.test.submit.error": "Nešto nije u redu sa pokretanjem testiranja podešavanja", + "collection.source.controls.test.failed": "Skripta za testiranje podešavanja nije uspela", + "collection.source.controls.test.completed": "Skripta za testiranje podešavanja je uspešno završena", + "collection.source.controls.test.submit": "Testna konfiguracija", + "collection.source.controls.test.running": "Testiranje konfiguracije...", + "collection.source.controls.import.submit.success": "Uvoz je uspešno pokrenut", + "collection.source.controls.import.submit.error": "Nešto nije u redu sa pokretanjem uvoza", + "collection.source.controls.import.submit": "Uvezite sada", + "collection.source.controls.import.running": "Uvoz...", + "collection.source.controls.import.failed": "Došlo je do greške tokom uvoza", + "collection.source.controls.import.completed": "Uvoz je završen", + "collection.source.controls.reset.submit.success": "Resetovanje i ponovni uvoz su uspešno pokrenuti", + "collection.source.controls.reset.submit.error": "Nešto nije u redu sa pokretanjem resetovanja i ponovnog uvoza", + "collection.source.controls.reset.failed": "Došlo je do greške tokom resetovanja i ponovnog uvoza", + "collection.source.controls.reset.completed": "Resetovanje i ponovni uvoz su završeni", + "collection.source.controls.reset.submit": "Resetujte i ponovo uvezite", + "collection.source.controls.reset.running": "Resetovanje i ponovni uvoz...", + "collection.source.controls.harvest.status": "Status prikupljaanja:", + "collection.source.controls.harvest.start": "Vreme početka prikupljanja:", + "collection.source.controls.harvest.last": "Vreme početka prikupljanja:", + "collection.source.controls.harvest.message": "Informacije o prikupljanju:", + "collection.source.controls.harvest.no-information": "N/A", + "collection.source.update.notifications.error.content": "Navedena podešavanja su testirana i nisu funkcionisala.", + "collection.source.update.notifications.error.title": "Greška na serveru", + "communityList.breadcrumbs": "Lista zajednice", + "communityList.tabTitle": "List zajednice", + "communityList.title": "Lista zajednica", + "communityList.showMore": "Prikaži više", + "community.create.head": "Kreirajte zajednicu", + "community.create.notifications.success": "Zajednica je uspešno kreirana", + "community.create.sub-head": "Kreirajte podzajednicu za zajednicu {{ parent }}", + "community.curate.header": "Urednik zajednice: {{community}}", + "community.delete.cancel": "Otkazati", + "community.delete.confirm": "Potvrdite", + "community.delete.processing": "Brisanje...", + "community.delete.head": "Izbrišite zajednicu", + "community.delete.notification.fail": "Nije moguće izbrisati zajednicu", + "community.delete.notification.success": "Uspešno izbrisana zajednica", + "community.delete.text": "Da li ste sigurni da želite da izbrišete zajednicu \"{{ dso }}\"", + "community.edit.delete": "Izbrišite ovu zajednicu", + "community.edit.head": "Izmenite zajednicu", + "community.edit.breadcrumbs": "Izmenite zajednicu", + "community.edit.logo.delete.title": "Izbrišite logo", + "community.edit.logo.delete-undo.title": "Poništite brisanje", + "community.edit.logo.label": "Logo zajednice", + "community.edit.logo.notifications.add.error": "Otpremanje logoa zajednice nije uspelo. Molimo proverite sadržaj pre ponovnog pokušaja.", + "community.edit.logo.notifications.add.success": "Uspešno otpremanje logoa zajednice.", + "community.edit.logo.notifications.delete.success.title": "Logo je izbrisan", + "community.edit.logo.notifications.delete.success.content": "Uspešno izbrisan logo zajednice", + "community.edit.logo.notifications.delete.error.title": "Greška pri brisanju logoa", + "community.edit.logo.upload": "Unesite logo zajednice da biste ga otpremili", + "community.edit.notifications.success": "Uspešno je izmenjena zajednica", + "community.edit.notifications.unauthorized": "Nemate ovlašćenje da izvršite ovu promenu", + "community.edit.notifications.error": "Došlo je do greške pri uređivanju zajednice", + "community.edit.return": "Nazad", + "community.edit.tabs.curate.head": "Curate", + "community.edit.tabs.curate.title": "Uređivanje zajednice - Curate", + "community.edit.tabs.access-control.head": "Kontrola pristupa", + "community.edit.tabs.access-control.title": "Uređivanje zajednice - Kontrola pristupa", + "community.edit.tabs.metadata.head": "Uredi metapodatke", + "community.edit.tabs.metadata.title": "Uređivanje zajednice – Metapodaci", + "community.edit.tabs.roles.head": "Dodeli uloge", + "community.edit.tabs.roles.title": "Uređivanje zajednice - Uloge", + "community.edit.tabs.authorizations.head": "Ovlašćenja", + "community.edit.tabs.authorizations.title": "Uređivanje zajednice - ovlašćenja", + "community.listelement.badge": "Zajednica", + "comcol-role.edit.no-group": "Nijedan", + "comcol-role.edit.create": "Kreirajte", + "comcol-role.edit.create.error.title": "Pravljenje grupe za ulogu \"{{ role }}\" nije uspelo", + "comcol-role.edit.restrict": "Ograničiti", + "comcol-role.edit.delete": "Izbrišite", + "comcol-role.edit.delete.error.title": "Brisanje grupe uloga \"{{ role }}\" nije uspelo", + "comcol-role.edit.community-admin.name": "Administratori", + "comcol-role.edit.collection-admin.name": "Administratori", + "comcol-role.edit.community-admin.description": "Administratori zajednice mogu da kreiraju podzajednice ili kolekcije i da upravljaju tim podzajednicama ili zbirkama ili da im dodeljuju upravljanje. Pored toga, oni odlučuju ko može da podnese stavke u bilo koju podzbirku, uređuju metapodatke stavki (nakon podnošenja) i dodaju (mapiraju) postojeće stavke iz drugih kolekcija (predmet ovlašćenja).", + "comcol-role.edit.collection-admin.description": "Administratori kolekcije odlučuju ko može da šalje stavke u kolekciju, uređuju metapodatke stavki (nakon slanja) i dodaju (mapiraju) postojeće stavke iz drugih kolekcija u ovu kolekciju (predmet ovlašćenja za tu kolekciju).", + "comcol-role.edit.submitters.name": "Podnosioci", + "comcol-role.edit.submitters.description": "E-ljudi i grupe koje imaju dozvolu da podnose nove stavke u ovu kolekciju.", + "comcol-role.edit.item_read.name": "Podrazumevani pristup za čitanje stavke", + "comcol-role.edit.item_read.description": "E-Ljudi i grupe koje mogu da čitaju nove stavke poslate u ovu kolekciju. Promene ove uloge nisu retroaktivne. Postojeće stavke u sistemu će i dalje moći da vide oni koji su imali pristup za čitanje u vreme njihovog dodavanja.", + "comcol-role.edit.item_read.anonymous-group": "Podrazumevano čitanje za dolazne stavke je trenutno postavljeno na Anonimno.", + "comcol-role.edit.bitstream_read.name": "Podrazumevani pristup za čitanje bitstreamova", + "comcol-role.edit.bitstream_read.description": "Administratori zajednice mogu da kreiraju podzajednice ili kolekcije i da upravljaju tim podzajednicama ili zbirkama ili da im dodeljuju upravljanje. Pored toga, oni odlučuju ko može da podnese stavke u bilo koju podzbirku, uređuju metapodatke stavki (nakon podnošenja) i dodaju (mapiraju) postojeće stavke iz drugih kolekcija (predmet ovlašćenja).", + "comcol-role.edit.bitstream_read.anonymous-group": "Podrazumevano čitanje za dolazne bitstreamove je trenutno podešeno na Anonimno.", + "comcol-role.edit.editor.name": "Urednici", + "comcol-role.edit.editor.description": "Urednici mogu da uređuju metapodatke dolaznih podnesaka, a zatim da ih prihvate ili odbiju.", + "comcol-role.edit.finaleditor.name": "Konačni urednici", + "comcol-role.edit.finaleditor.description": "Konačni urednici mogu da uređuju metapodatke dolaznih podnesaka, ali neće moći da ih odbiju.", + "comcol-role.edit.reviewer.name": "Recenzenti", + "comcol-role.edit.reviewer.description": "Recenzenti mogu da prihvate ili odbiju dolazne podneske. Međutim, oni ne mogu da uređuju metapodatke podneska.", + "comcol-role.edit.scorereviewers.name": "Rezultat recenzenata", + "comcol-role.edit.scorereviewers.description": "Recenzenti mogu da daju ocenu dolaznim podnescima, što će definisati da li će podnesak biti odbijen ili ne.", + "community.form.abstract": "Kratak opis", + "community.form.description": "Uvodni tekst (HTML)", + "community.form.errors.title.required": "Unesite naziv zajednice", + "community.form.rights": "Tekst autorskih prava (HTML)", + "community.form.tableofcontents": "Vesti (HTML)", + "community.form.title": "Ime", + "community.page.edit": "Uredite ovu zajednicu", + "community.page.handle": "Stalni URI za ovu zajednicu", + "community.page.license": "Licenca", + "community.page.news": "Vesti", + "community.all-lists.head": "Podzajednice i kolekcije", + "community.sub-collection-list.head": "Kolekcije u ovoj zajednici", + "community.sub-community-list.head": "Zajednice u ovoj zajednici", + "cookies.consent.accept-all": "Prihvatite sve", + "cookies.consent.accept-selected": "Prihvatite izabrano", + "cookies.consent.app.opt-out.description": "Ova aplikacija se podrazumevano učitava (ali možete da odustanete)", + "cookies.consent.app.opt-out.title": "(odustati)", + "cookies.consent.app.purpose": "Svrha", + "cookies.consent.app.required.description": "Ova aplikacija je uvek potrebna", + "cookies.consent.app.required.title": "(uvek potrebno)", + "cookies.consent.app.disable-all.description": "Koristite ovaj prekidač da omogućite ili onemogućite sve usluge.", + "cookies.consent.app.disable-all.title": "Omogućite ili onemogućite sve usluge", + "cookies.consent.update": "Bilo je promena od vaše poslednje posete, ažurirajte svoju saglasnost.", + "cookies.consent.close": "Zatvoriti", + "cookies.consent.decline": "Odbiti", + "cookies.consent.ok": "To je u redu", + "cookies.consent.save": "sačuvati", + "cookies.consent.content-notice.title": "Saglasnost za kolačiće", + "cookies.consent.content-notice.description": "Prikupljamo i obrađujemo vaše lične podatke u sledeće svrhe: Provera autentičnosti, podešavanja, potvrda i statistika.
Da biste saznali više, pročitajte našu {privaciPolicy}.", + "cookies.consent.content-notice.description.no-privacy": "Prikupljamo i obrađujemo vaše lične podatke u sledeće svrhe: Provera autentičnosti, podešavanja, potvrda i statistika.", + "cookies.consent.content-notice.learnMore": "Prilagoditi", + "cookies.consent.content-modal.description": "Ovde možete videti i prilagoditi informacije koje prikupljamo o vama.", + "cookies.consent.content-modal.privacy-policy.name": "Pravila o privatnosti", + "cookies.consent.content-modal.privacy-policy.text": "Da saznate više, pročitajte našu {privaciPolicy}.", + "cookies.consent.content-modal.title": "Informacije koje prikupljamo", + "cookies.consent.content-modal.services": "Usluge", + "cookies.consent.content-modal.service": "Usluga", + "cookies.consent.app.title.authentication": "Provera", + "cookies.consent.app.description.authentication": "Potrebno za prijavljivanje", + "cookies.consent.app.title.preferences": "Podešavanja", + "cookies.consent.app.description.preferences": "Potrebno za čuvanje vaših podešavanja", + "cookies.consent.app.title.acknowledgement": "Potvrda", + "cookies.consent.app.description.acknowledgement": "Potrebno za čuvanje vaših potvrda i saglasnosti", + "cookies.consent.app.title.google-analytics": "Google analitike", + "cookies.consent.app.description.google-analytics": "Omogućava nam da pratimo statističke podatke", + "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", + "cookies.consent.app.description.google-recaptcha": "Koristimo Google reCAPTCHA uslugu tokom registracije i oporavka lozinke", + "cookies.consent.purpose.functional": "Funkcionalni", + "cookies.consent.purpose.statistical": "Statistički", + "cookies.consent.purpose.registration-password-recovery": "Registracija i oporavak lozinke", + "cookies.consent.purpose.sharing": "Deljenje", + "curation-task.task.citationpage.label": "Generišite stranicu sa citatima", + "curation-task.task.checklinks.label": "Proverite veze u metapodacima", + "curation-task.task.noop.label": "NOOP", + "curation-task.task.profileformats.label": "Profil Bitstrim formati", + "curation-task.task.requiredmetadata.label": "Proverite potrebne metapodatke", + "curation-task.task.translate.label": "Microsoft prevodilac", + "curation-task.task.vscan.label": "Pretraga virusa", + "curation-task.task.register-doi.label": "Registrujte DOI", + "curation.form.task-select.label": "Zadatak:", + "curation.form.submit": "Početak", + "curation.form.submit.success.head": "Zadato kuriranje je uspešno pokrenuto", + "curation.form.submit.success.content": "Bićete preusmereni na odgovarajuću stranicu procesa.", + "curation.form.submit.error.head": "Neuspešno pokretanje zadatog kuriranja", + "curation.form.submit.error.content": "Došlo je do greške pri pokušaju pokretanja zadatog kuriranja.", + "curation.form.submit.error.invalid-handle": "Nije moguće odrediti ručicu za ovaj objekat", + "curation.form.handle.label": "Handle:", + "curation.form.handle.hint": "Savet: Unesite [your-handle-prefix]/0 da biste pokrenuli zadatak na celom sajtu (ovu mogućnost ne podržavaju svi zadaci)", + "deny-request-copy.email.message": "Poštovani {{ recipientName }}, \n Kao odgovor na vaš zahtev, sa žaljenjem vas obaveštavam da nije moguće poslati kopiju fajla koju ste tražili, u vezi sa dokumentom: \"{{ itemUrl }}\" ({{ itemName }}), čiji sam autor. \n Srdačan pozdrav, \n{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.subject": "Zatražite kopiju dokumenta", + "deny-request-copy.error": "Došlo je do greške", + "deny-request-copy.header": "Odbijen zahtev za kopiranje dokumenta", + "deny-request-copy.intro": "Ova poruka biće poslata podnosiocu zahteva", + "deny-request-copy.success": "Zahtev za stavku je odbijen uspešno", + "dso.name.untitled": "Bez naslova", + "dso.name.unnamed": "Bez imena", + "dso-selector.create.collection.head": "Nova kolekcija", + "dso-selector.create.collection.sub-level": "Kreirajte novu kolekciju u", + "dso-selector.create.community.head": "Nova zajednica", + "dso-selector.create.community.or-divider": "ili", + "dso-selector.create.community.sub-level": "Kreirajte novu zajednicu u", + "dso-selector.create.community.top-level": "Kreirajte novu zajednicu najvišeg nivoa", + "dso-selector.create.item.head": "Nova stavka", + "dso-selector.create.item.sub-level": "Kreirajte novu stavku u", + "dso-selector.create.submission.head": "Novi podnesak", + "dso-selector.edit.collection.head": "Izmenite kolekciju", + "dso-selector.edit.community.head": "Izmenite zajednicu", + "dso-selector.edit.item.head": "Izmenite stavku", + "dso-selector.error.title": "Došlo je do greške pri pretrazi {{ type }}", + "dso-selector.export-metadata.dspaceobject.head": "Izvezite metapodatke iz", + "dso-selector.export-batch.dspaceobject.head": "Izvezite paket (ZIP) iz", + "dso-selector.import-batch.dspaceobject.head": "Uvezite paket iz", + "dso-selector.no-results": "Nije pronađen {{ type }}", + "dso-selector.placeholder": "Pretražite {{ type }}", + "dso-selector.select.collection.head": "Izaberite kolekciju", + "dso-selector.set-scope.community.head": "Izaberite opseg pretrage", + "dso-selector.set-scope.community.button": "Pretražite čitav repozitorijum", + "dso-selector.set-scope.community.or-divider": "ili", + "dso-selector.set-scope.community.input-header": "Pretražite zajednicu ili kolekciju", + "dso-selector.claim.item.head": "Smernice za profil", + "dso-selector.claim.item.body": "Ovo su postojeći profili koji se možda odnose na Vas. Ako se prepoznate u jednom od ovih profila, izaberite ga i na stranici sa detaljima, među opcijama, izaberite da ga zatražite. U suprotnom, možete kreirati novi profil od nule koristeći dugme ispod.", + "dso-selector.claim.item.not-mine-label": "Nijedan od ovih nije moj", + "dso-selector.claim.item.create-from-scratch": "Kreirajte novi", + "dso-selector.results-could-not-be-retrieved": "Nešto nije u redu, molimo osvežite ponovo ↻", + "supervision-group-selector.header": "Selektor grupe za nadzor", + "supervision-group-selector.select.type-of-order.label": "Izaberite tip naloga", + "supervision-group-selector.select.type-of-order.option.none": "NIJEDAN", + "supervision-group-selector.select.type-of-order.option.editor": "UREDNIK", + "supervision-group-selector.select.type-of-order.option.observer": "POSMATRAČ", + "supervision-group-selector.select.group.label": "Izaberite grupu", + "supervision-group-selector.button.cancel": "Otkazati", + "supervision-group-selector.button.save": "Sačuvati", + "supervision-group-selector.select.type-of-order.error": "Molimo izaberite tip naloga", + "supervision-group-selector.select.group.error": "Molimo izaberite grupu", + "supervision-group-selector.notification.create.success.title": "Uspešno je kreiran nalog nadzora za grupu {{ name }}", + "supervision-group-selector.notification.create.failure.title": "Greška", + "supervision-group-selector.notification.create.already-existing": "Već postoji nalog za nadzor za ovu stavku izabrane grupe", + "confirmation-modal.export-metadata.header": "Izvoz metapodataka za {{ dsoName }}", + "confirmation-modal.export-metadata.info": "Da li ste sigurni da želite da izvezete metapodatke za {{ dsoName }}", + "confirmation-modal.export-metadata.cancel": "Otkazati", + "confirmation-modal.export-metadata.confirm": "Izvoz", + "confirmation-modal.export-batch.header": "Izvezite paket (ZIP) za {{ dsoName }}", + "confirmation-modal.export-batch.info": "Da li ste sigurni da želite da izvezete paket (ZIP) za {{ dsoName }}", + "confirmation-modal.export-batch.cancel": "Otkazati", + "confirmation-modal.export-batch.confirm": "Izvoz", + "confirmation-modal.delete-eperson.header": "Izbrišite Eperson \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.info": "Da li ste sigurni da želite da izbrišete Eperson \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.cancel": "Otkazati", + "confirmation-modal.delete-eperson.confirm": "Izbrisati", + "confirmation-modal.delete-profile.header": "Izbrišite profil", + "confirmation-modal.delete-profile.info": "Da li ste sigurni da želite da izbrišete svoj profil", + "confirmation-modal.delete-profile.cancel": "Otkazati", + "confirmation-modal.delete-profile.confirm": "Izbrisati", + "confirmation-modal.delete-subscription.header": "Ukloniti pretplatu", + "confirmation-modal.delete-subscription.info": "Da li ste sigurni da želite da izbrišete pretplatu za \"{{ dsoName }}\"", + "confirmation-modal.delete-subscription.cancel": "Otkazati", + "confirmation-modal.delete-subscription.confirm": "Izbrisati", + "error.bitstream": "Greška pri preuzimanju bitstream-a", + "error.browse-by": "Greška pri preuzimanju stavki", + "error.collection": "Greška pri preuzimanju kolekcije", + "error.collections": "Greška pri preuzimanju kolekcija", + "error.community": "Greška pri preuzimanju zajednice", + "error.identifier": "Nije pronađena nijedna stavka za identifikator", + "error.default": "Greška", + "error.item": "Greška pri preuzimanju stavke", + "error.items": "Greška pri preuzimanju stavki", + "error.objects": "Greška pri preuzimanju objekata", + "error.recent-submissions": "Greška pri preuzimanju nedavnih podnesaka", + "error.search-results": "Greška pri preuzimanju rezultata pretrage", + "error.invalid-search-query": "Upit za pretragu nije ispravan. Proverite najbolja rešenja za Solr sintaksu upita za dodatne informacije o ovoj grešci .", + "error.sub-collections": "Greška pri preuzimanju podkolekcija", + "error.sub-communities": "Greška pri preuzimanju podzajednica", + "error.submission.sections.init-form-error": "Došlo je do greške tokom inicijalizacije odeljka, molimo proverite konfiguraciju obrasca za unos. Detalji su ispod:

", + "error.top-level-communities": "Greška pri preuzimanju zajednica najvišeg nivoa", + "error.validation.license.notgranted": "Morate dodeliti ovu licencu da biste dovršili svoj podnesak. Ako u ovom trenutku niste u mogućnosti da dodelite ovu licencu, možete da sačuvate svoj rad i vratite se kasnije ili uklonite podnesak.", + "error.validation.pattern": "Ovaj unos je ograničen trenutnim obrascem: {{ pattern }}.", + "error.validation.filerequired": "Otpremanje fajla je obavezno", + "error.validation.required": "Ovo polje je obavezno", + "error.validation.NotValidEmail": "Ovaj e-mail nije važeći e-mail", + "error.validation.emailTaken": "Ova e-mail adresa je već zauzeta", + "error.validation.groupExists": "Ova grupa već postoji", + "error.validation.metadata.name.invalid-pattern": "Ovo polje ne može da sadrži tačke, zareze ili razmake. Umesto toga, koristite polja Element i kvalifikator", + "error.validation.metadata.name.max-length": "Ovo polje ne sme da sadrži više od 32 znaka", + "error.validation.metadata.namespace.max-length": "Ovo polje ne sme da sadrži više od 256 znakova", + "error.validation.metadata.element.invalid-pattern": "Ovo polje ne može da sadrži tačke, zareze ili razmake. Umesto toga, koristite polje Kvalifikator", + "error.validation.metadata.element.max-length": "Ovo polje ne sme da sadrži više od 64 znaka", + "error.validation.metadata.qualifier.invalid-pattern": "Ovo polje ne može da sadrži tačke, zareze ili razmake", + "error.validation.metadata.qualifier.max-length": "Ovo polje ne sme da sadrži više od 64 znaka", + "feed.description": "Syndication feed", + "file-section.error.header": "Greška pri pribavljanju fajlova za ovu stavku", + "footer.copyright": "autorska prava © 2002-{{ year }}", + "footer.link.dspace": "DSpace softver", + "footer.link.lyrasis": "LIRASIS", + "footer.link.cookies": "Podešavanja kolačića", + "footer.link.privacy-policy": "Pravila o privatnosti", + "footer.link.end-user-agreement": "Ugovor sa krajnjim korisnikom", + "footer.link.feedback": "Pošalji povratne informacije", + "forgot-email.form.header": "Zaboravili ste lozinku", + "forgot-email.form.info": "Unesite e-mail adresu povezanu sa nalogom.", + "forgot-email.form.email": "E-mail adresa *", + "forgot-email.form.email.error.required": "Unesite e-mail adresu", + "forgot-email.form.email.error.not-email-form": "Unesite važeću e-mail adresu", + "forgot-email.form.email.hint": "E-mail sa daljim uputstvima biće poslat na ovu adresu ", + "forgot-email.form.submit": "Resetujte lozinku", + "forgot-email.form.success.head": "Poslat je e-mail za resetovanje lozinke", + "forgot-email.form.success.content": "E-mail koji sadrži posebnu URL adresu i dalja uputstva biće poslat na {{ email }} ", + "forgot-email.form.error.head": "Greška pri pokušaju resetovanja lozinke", + "forgot-email.form.error.content": "Došlo je do greške pri pokušaju resetovanja lozinke za nalog povezan sa sledećom adresom e-pošte: {{ email }}", + "forgot-password.title": "Zaboravili ste lozinku", + "forgot-password.form.head": "Zaboravili ste lozinku", + "forgot-password.form.info": "Unesite novu lozinku u polje ispod i potvrdite je tako što ćete je ponovo ukucati u drugo polje.", + "forgot-password.form.card.security": "Bezbednost", + "forgot-password.form.identification.header": "Identifikovati", + "forgot-password.form.identification.email": "E-mail adresa:", + "forgot-password.form.label.password": "Lozinka", + "forgot-password.form.label.passwordrepeat": "Ponovo otkucajte da biste potvrdili", + "forgot-password.form.error.empty-password": "Unesite lozinku u polje ispod.", + "forgot-password.form.error.matching-passwords": "Lozinke se ne poklapaju.", + "forgot-password.form.notification.error.title": "Greška pri pokušaju slanja nove lozinke", + "forgot-password.form.notification.success.content": "Resetovanje lozinke je bilo uspešno. Prijavljeni ste kao kreirani korisnik.", + "forgot-password.form.notification.success.title": "Resetovanje lozinke je završeno", + "forgot-password.form.submit": "Pošalji lozinku", + "form.add": "Dodaj još", + "form.add-help": "Kliknite ovde da dodate trenutni unos i da dodate još jedan", + "form.cancel": "Poništiti, otkazati", + "form.clear": "Jasno", + "form.clear-help": "Kliknite ovde da biste uklonili izabranu vrednost", + "form.discard": "Odbacite", + "form.drag": "Prevucite", + "form.edit": "Uredite", + "form.edit-help": "Kliknite ovde da biste izmenili izabranu vrednost", + "form.first-name": "Ime", + "form.group-collapse": "Skupi", + "form.group-collapse-help": "Kliknite ovde za skupljanje", + "form.group-expand": "Proširiti", + "form.group-expand-help": "Kliknite ovde da biste proširili i dodali još elemenata", + "form.last-name": "Prezime", + "form.loading": "Učitavanje...", + "form.lookup": "Potražite", + "form.lookup-help": "Kliknite ovde da biste potražili postojeću vezu", + "form.no-results": "Nisu pronađeni rezultati", + "form.no-value": "Nije uneta vrednost", + "form.other-information.email": "E-mail", + "form.other-information.first-name": "Ime", + "form.other-information.insolr": "U Solr indeksu", + "form.other-information.institution": "Institucija", + "form.other-information.last-name": "Prezime", + "form.other-information.orcid": "ORCID", + "form.remove": "Uklonite", + "form.save": "Sačuvajte", + "form.save-help": "Sačuvajte izmene", + "form.search": "Pretraga", + "form.search-help": "Kliknite ovde da biste potražili postojeću prepisku", + "form.submit": "Sačuvajte", + "form.create": "Kreirajte", + "form.repeatable.sort.tip": "Spustite stavku na novu poziciju", + "grant-deny-request-copy.deny": "Ne šalji kopiju", + "grant-deny-request-copy.email.back": "Nazad", + "grant-deny-request-copy.email.message": "Opciona dodatna poruka", + "grant-deny-request-copy.email.message.empty": "Unesite poruku", + "grant-deny-request-copy.email.permissions.info": "Možete iskoristiti ovu priliku da ponovo razmotrite ograničenja pristupa dokumentu, kako biste izbegli da odgovorite na ove zahteve. Ako želite da zamolite administratore spremišta da uklone ova ograničenja, označite polje ispod.", + "grant-deny-request-copy.email.permissions.label": "Promenite u otvoreni pristup", + "grant-deny-request-copy.email.send": "Pošaljite", + "grant-deny-request-copy.email.subject": "Predmet", + "grant-deny-request-copy.email.subject.empty": "Unesite temu", + "grant-deny-request-copy.grant": "Pošaljite kopiju", + "grant-deny-request-copy.header": "Zahtev za kopiju dokumenta", + "grant-deny-request-copy.home-page": "Vrati me na početnu stranicu", + "grant-deny-request-copy.intro1": "Ako ste jedan od autora dokumenta {{ name }}, onda koristite jednu od opcija u nastavku da odgovorite na zahtev korisnika.", + "grant-deny-request-copy.intro2": "Nakon što odaberete opciju, biće vam predstavljen predloženi odgovor e-maila koji možete da izmenite.", + "grant-deny-request-copy.processed": "Ovaj zahtev je već obrađen. Možete koristiti dugme ispod da se vratite na početnu stranicu.", + "grant-request-copy.email.subject": "Zatražite kopiju dokumenta", + "grant-request-copy.error": "Došlo je do greške", + "grant-request-copy.header": "Odobrite zahtev za kopiju dokumenta", + "grant-request-copy.intro": "Podnosiocu zahteva će biti poslata poruka. Traženi dokument(i) će biti priložen.", + "grant-request-copy.success": "Zahtev za stavku je uspešno odobren", + "health.breadcrumbs": "Zdravlje", + "health-page.heading": "Zdravlje", + "health-page.info-tab": "Informacije", + "health-page.status-tab": "Status", + "health-page.error.msg": "Usluga provere zdravlja je privremeno nedostupna", + "health-page.property.status": "Statusni kod", + "health-page.section.db.title": "Baza podataka", + "health-page.section.geoIp.title": "GeoIp", + "health-page.section.solrAuthorityCore.title": "Solr: authority core", + "health-page.section.solrOaiCore.title": "Solr: oai core", + "health-page.section.solrSearchCore.title": "Solr: search core", + "health-page.section.solrStatisticsCore.title": "Solr: statistics core", + "health-page.section-info.app.title": "Backend aplikacije", + "health-page.section-info.java.title": "Java", + "health-page.status": "Status", + "health-page.status.ok.info": "Operativni", + "health-page.status.error.info": "Otkriveni su problemi", + "health-page.status.warning.info": "Otkriveni su mogući problemi", + "health-page.title": "Zdravlje", + "health-page.section.no-issues": "Nisu otkriveni problemi", + "home.description": "", + "home.breadcrumbs": "Home", + "home.search-form.placeholder": "Pretražite repozitorijum...", + "home.title": "Home", + "home.top-level-communities.head": "Zajednice u DSpace-u", + "home.top-level-communities.help": "Izaberite zajednicu da biste pregledali njene kolekcije.", + "info.end-user-agreement.accept": "Pročitao sam i prihvatam Ugovorom sa krajnjim korisnikom", + "info.end-user-agreement.accept.error": "Došlo je do greške pri prihvatanju Ugovora sa krajnjim korisnikom", + "info.end-user-agreement.accept.success": "Uspešno ažuriran Ugovor sa krajnjim korisnikom", + "info.end-user-agreement.breadcrumbs": "Ugovor sa krajnjim korisnikom", + "info.end-user-agreement.buttons.cancel": "Otkazati", + "info.end-user-agreement.buttons.save": "Sačuvati", + "info.end-user-agreement.head": "Ugovor sa krajnjim korisnikom", + "info.end-user-agreement.title": "Ugovor sa krajnjim korisnikom", + "info.end-user-agreement.hosting-country": "Sjedinjene Države", + "info.privacy.breadcrumbs": "Izjava o zaštiti privatnosti", + "info.privacy.head": "Izjava o zaštiti privatnosti", + "info.privacy.title": "Izjava o zaštiti privatnosti", + "info.feedback.breadcrumbs": "Povratna informacija", + "info.feedback.head": "Povratna informacija", + "info.feedback.title": "Povratna informacija", + "info.feedback.info": "Hvala Vam što ste podelili povratne informacije o DSpace sistemu. Cenimo Vaše komentare!", + "info.feedback.email_help": "Ova adresa će biti korišćena za praćenje vaših povratnih informacija.", + "info.feedback.send": "Pošaljite povratne informacije", + "info.feedback.comments": "Komentari", + "info.feedback.email-label": "Vaš Email", + "info.feedback.create.success": "Povratne informacije su uspešno poslate!", + "info.feedback.error.email.required": "Potrebna je važeća e-mail adresa", + "info.feedback.error.message.required": "Komentar je obavezan", + "info.feedback.page-label": "Strana", + "info.feedback.page_help": "Stranica je u vezi sa Vašim povratnim informacijama", + "item.alerts.private": "Ova stavka se ne može otkriti", + "item.alerts.withdrawn": "Ova stavka je povučena", + "item.edit.authorizations.heading": "Pomoću ovog editora možete da pregledate i menjate opcije stavke, kao i da menjate opcije pojedinačnih komponenti stavke: pakete i bitstream-ove. Ukratko, stavka je kontejner paketa, a paketi su kontejneri bitstream-ova. Kontejneri obično imaju opcije DODAVANJE/BRISANJE/ČITANJE/PISANJE, dok bitstream-ovi imaju samo opcije ČITANJE/PISANJE.", + "item.edit.authorizations.title": "Izmenite opcije stavke", + "item.badge.private": "Nevidljiv", + "item.badge.withdrawn": "Povučeno", + "item.bitstreams.upload.bundle": "Paket", + "item.bitstreams.upload.bundle.placeholder": "Izaberite paket ili unesite novo ime paketa", + "item.bitstreams.upload.bundle.new": "Kreirajte paket", + "item.bitstreams.upload.bundles.empty": "Ova stavka ne sadrži pakete za otpremanje bitstream-ova.", + "item.bitstreams.upload.cancel": "Otkazati", + "item.bitstreams.upload.drop-message": "Unesite datoteku za otpremanje", + "item.bitstreams.upload.item": "Stavka:", + "item.bitstreams.upload.notifications.bundle.created.content": "Uspešno kreiran novi paket.", + "item.bitstreams.upload.notifications.bundle.created.title": "Kreirani paket", + "item.bitstreams.upload.notifications.upload.failed": "Otpremanje neuspešno. Molimo Vas proverite sadržaj pre ponovnog pokušaja.", + "item.bitstreams.upload.title": "Otpremanje bitstream-a", + "item.edit.bitstreams.bundle.edit.buttons.upload": "Otpremiti", + "item.edit.bitstreams.bundle.displaying": "Trenutno se prikazuje {{ amount }} bitstream-ova od {{ total }}.", + "item.edit.bitstreams.bundle.load.all": "Učitajte sve ({{ total }})", + "item.edit.bitstreams.bundle.load.more": "Učitajte još", + "item.edit.bitstreams.bundle.name": "PAKET: {{ name }}", + "item.edit.bitstreams.discard-button": "Odbaciti", + "item.edit.bitstreams.edit.buttons.download": "Preuzimanje", + "item.edit.bitstreams.edit.buttons.drag": "Prevucite", + "item.edit.bitstreams.edit.buttons.edit": "Izmeniti", + "item.edit.bitstreams.edit.buttons.remove": "Ukloniti", + "item.edit.bitstreams.edit.buttons.undo": "Poništiti promene", + "item.edit.bitstreams.empty": "Ova stavka ne sadrži bitstream-ove. Kliknite na dugme za otpremanje da biste ga kreirali.", + "item.edit.bitstreams.headers.actions": "Radnje", + "item.edit.bitstreams.headers.bundle": "Paket", + "item.edit.bitstreams.headers.description": "Opis", + "item.edit.bitstreams.headers.format": "Format", + "item.edit.bitstreams.headers.name": "Ime", + "item.edit.bitstreams.notifications.discarded.content": "Vaše promene su odbačene. Da biste ponovo postavili svoje promene, kliknite na dugme \"Opozovi\".", + "item.edit.bitstreams.notifications.discarded.title": "Promene su odbačene", + "item.edit.bitstreams.notifications.move.failed.title": "Greška pri pokretanju bitstream-ova", + "item.edit.bitstreams.notifications.move.saved.content": "Promene koje ste pokrenuli u bitstream-ovima i paketima ove stavke su sačuvane.", + "item.edit.bitstreams.notifications.move.saved.title": "Pokrenute promene su sačuvane", + "item.edit.bitstreams.notifications.outdated.content": "Stavku na kojoj trenutno radite je promenio drugi korisnik. Vaše trenutne promene se odbacuju da bi se sprečili konflikti", + "item.edit.bitstreams.notifications.outdated.title": "Zastarele promene", + "item.edit.bitstreams.notifications.remove.failed.title": "Greška pri brisanju bitstream-a", + "item.edit.bitstreams.notifications.remove.saved.content": "Vaše izmene u vezi sa uklanjanjem bitstream-ova ove stavke su sačuvane.", + "item.edit.bitstreams.notifications.remove.saved.title": "Promene uklanjanja su sačuvane", + "item.edit.bitstreams.reinstate-button": "Poništiti", + "item.edit.bitstreams.save-button": "Sačuvati", + "item.edit.bitstreams.upload-button": "Otpremiti", + "item.edit.delete.cancel": "Otkazati", + "item.edit.delete.confirm": "Izbrisati", + "item.edit.delete.description": "Da li ste sigurni da ovu stavku treba potpuno izbrisati? Oprez: Trenutno ne bi ostao nijedan obrisani zapis.", + "item.edit.delete.error": "Došlo je do greške prilikom brisanja stavke", + "item.edit.delete.header": "Izbrišite stavku: {{ id }}", + "item.edit.delete.success": "Stavka je izbrisana", + "item.edit.head": "Uredite stavku", + "item.edit.breadcrumbs": "Uredite stavku", + "item.edit.tabs.disabled.tooltip": "Niste ovlašćeni da pristupite ovoj kartici", + "item.edit.tabs.mapper.head": "Mapiranje kolekcije", + "item.edit.tabs.item-mapper.title": "Uređivanje stavke - mapiranje kolekcije", + "item.edit.identifiers.doi.status.UNKNOWN": "Nepoznato", + "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "Na čekanju za registraciju", + "item.edit.identifiers.doi.status.TO_BE_RESERVED": "Na čekanju za rezervaciju", + "item.edit.identifiers.doi.status.IS_REGISTERED": "Registrovano", + "item.edit.identifiers.doi.status.IS_RESERVED": "Rezervisano", + "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Rezervisano (na čekanju za ažuriranje)", + "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Registrovano (na čekanju za ažuriranje)", + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "Na čekanju za ažuriranje i registraciju", + "item.edit.identifiers.doi.status.TO_BE_DELETED": "Na čekanju za brisanje", + "item.edit.identifiers.doi.status.DELETED": "Izbrisano", + "item.edit.identifiers.doi.status.PENDING": "Na čekanju (nije registrovano)", + "item.edit.identifiers.doi.status.MINTED": "Minted (nije registrovano)", + "item.edit.tabs.status.buttons.register-doi.label": "Registrujte novi ili DOI na čekanju", + "item.edit.tabs.status.buttons.register-doi.button": "Registrujte DOI...", + "item.edit.register-doi.header": "Registrujte novi ili DOI na čekanju", + "item.edit.register-doi.description": "Pregledajte sve identifikatore i stavke metapodataka na čekanju ispod i kliknite na Potvrdi da biste nastavili sa DOI registracijom, ili Otkaži da biste se povukli", + "item.edit.register-doi.confirm": "Potvrditi", + "item.edit.register-doi.cancel": "Poništiti, otkazati", + "item.edit.register-doi.success": "DOI na čekanju za registraciju uspešno.", + "item.edit.register-doi.error": "Greška pri registraciji DOI", + "item.edit.register-doi.to-update": "Sledeći DOI je već minted i biće na čekanju za registraciju na mreži", + "item.edit.item-mapper.buttons.add": "Mapirajte stavku u izabrane kolekcije", + "item.edit.item-mapper.buttons.remove": "Uklonite mapiranje stavke za izabrane kolekcije", + "item.edit.item-mapper.cancel": "Poništiti, otkazati", + "item.edit.item-mapper.description": "Ovo je alatka za mapiranje stavki koja omogućava administratorima da mapiraju ovu stavku u druge kolekcije. Možete pretražiti kolekcije i mapirati ih ili pregledati listu kolekcija na koje je stavka trenutno mapirana.", + "item.edit.item-mapper.head": "Mapiranje stavke – mapirajte stavku u kolekcije", + "item.edit.item-mapper.item": "Stavka: \"{{name}}\"", + "item.edit.item-mapper.no-search": "Unesite upit za pretragu", + "item.edit.item-mapper.notifications.add.error.content": "Došlo je do grešaka pri mapiranju stavke u {{amount}} kolekcije.", + "item.edit.item-mapper.notifications.add.error.head": "Greške u mapiranju", + "item.edit.item-mapper.notifications.add.success.content": "Stavka je uspešno mapirana u {{amount}} kolekcije.", + "item.edit.item-mapper.notifications.add.success.head": "Mapiranje je završeno", + "item.edit.item-mapper.notifications.remove.error.content": "Došlo je do grešaka pri uklanjanju mapiranja na {{amount}} kolekcije.", + "item.edit.item-mapper.notifications.remove.error.head": "Uklanjanje grešaka u mapiranju", + "item.edit.item-mapper.notifications.remove.success.content": "Uspešno je uklonjeno mapiranje stavke u {{amount}} kolekcije.", + "item.edit.item-mapper.notifications.remove.success.head": "Uklanjanje mapiranja je završeno", + "item.edit.item-mapper.search-form.placeholder": "Pretraži kolekcije...", + "item.edit.item-mapper.tabs.browse": "Pregledajte mapirane kolekcije", + "item.edit.item-mapper.tabs.map": "Mapirajte nove kolekcije", + "item.edit.metadata.add-button": "Dodati", + "item.edit.metadata.discard-button": "Odbaciti", + "item.edit.metadata.edit.buttons.confirm": "Potvrditi", + "item.edit.metadata.edit.buttons.drag": "Prevucite da biste promenili redosled", + "item.edit.metadata.edit.buttons.edit": "Urediti", + "item.edit.metadata.edit.buttons.remove": "Ukloniti", + "item.edit.metadata.edit.buttons.undo": "Poništiti promene", + "item.edit.metadata.edit.buttons.unedit": "Zaustaviti uređivanje", + "item.edit.metadata.edit.buttons.virtual": "Ovo je virtuelna vrednost metapodataka, odnosno vrednost nasleđena od povezanog entiteta. Ne može se direktno menjati. Dodajte ili uklonite odgovarajući odnos na kartici \"Odnosi\".", + "item.edit.metadata.empty": "Stavka trenutno ne sadrži nikakve metapodatke. Kliknite na Dodaj da biste počeli da dodajete vrednost metapodataka.", + "item.edit.metadata.headers.edit": "Urediti", + "item.edit.metadata.headers.field": "Polje", + "item.edit.metadata.headers.language": "Jezik", + "item.edit.metadata.headers.value": "Vrednost", + "item.edit.metadata.metadatafield.error": "Došlo je do greške pri proveri polja metapodataka", + "item.edit.metadata.metadatafield.invalid": "Izaberite važeće polje za metapodatke", + "item.edit.metadata.notifications.discarded.content": "Vaše promene su odbačene. Da biste vratili svoje promene, kliknite na dugme \"Poništi\".", + "item.edit.metadata.notifications.discarded.title": "Promene su odbačene", + "item.edit.metadata.notifications.error.title": "Došlo je do greške", + "item.edit.metadata.notifications.invalid.content": "Vaše promene nisu sačuvane. Uverite se da su sva polja važeća pre nego što sačuvate.", + "item.edit.metadata.notifications.invalid.title": "Metapodaci su nevažeći", + "item.edit.metadata.notifications.outdated.content": "Stavku na kojoj trenutno radite je promenio drugi korisnik. Vaše trenutne promene se odbacuju da bi se sprečili konflikti", + "item.edit.metadata.notifications.outdated.title": "Promene su zastarele", + "item.edit.metadata.notifications.saved.content": "Vaše promene metapodataka ove stavke su sačuvane.", + "item.edit.metadata.notifications.saved.title": "Metapodaci su sačuvani", + "item.edit.metadata.reinstate-button": "Poništiti", + "item.edit.metadata.reset-order-button": "Poništite promenu redosleda", + "item.edit.metadata.save-button": "Sačuvati", + "item.edit.modify.overview.field": "Polje", + "item.edit.modify.overview.language": "Jezik", + "item.edit.modify.overview.value": "Vrednost", + "item.edit.move.cancel": "Nazad", + "item.edit.move.save-button": "Sačuvati", + "item.edit.move.discard-button": "Odbaciti", + "item.edit.move.description": "Izaberite kolekciju u koju želite da premestite ovu stavku. Da biste suzili listu prikazanih kolekcija, možete da unesete upit za pretragu u okvir.", + "item.edit.move.error": "Došlo je do greške pri pokušaju premeštanja stavke", + "item.edit.move.head": "Premestite stavku: {{id}}", + "item.edit.move.inheritpolicies.checkbox": "Smernice nasleđivanja", + "item.edit.move.inheritpolicies.description": "Nasledite podrazumevane smernice odredišne kolekcije", + "item.edit.move.move": "Premestite", + "item.edit.move.processing": "Premeštanje...", + "item.edit.move.search.placeholder": "Unesite upit za pretragu da biste potražili kolekcije", + "item.edit.move.success": "Stavka je uspešno premeštena", + "item.edit.move.title": "Premestite stavku", + "item.edit.private.cancel": "Poništiti, otkazati", + "item.edit.private.confirm": "Učinite nepristupačnim", + "item.edit.private.description": "Da li ste sigurni da ova stavka treba da bude nepristupačna u arhivi?", + "item.edit.private.error": "Došlo je do greške pri postavljanju nepristupačne stavke", + "item.edit.private.header": "Učinite stavku nepristupačnom: {{ id }}", + "item.edit.private.success": "Stavka je sada nepristupačna", + "item.edit.public.cancel": "Poništiti, otkazati", + "item.edit.public.confirm": "Učinite pristupačnim", + "item.edit.public.description": "Da li ste sigurni da ova stavka treba da bude pristupačna u arhivi?", + "item.edit.public.error": "Došlo je do greške pri omogućavanju vidljivosti stavke", + "item.edit.public.header": "Učinite stavku vidljivom: {{ id }}", + "item.edit.public.success": "Stavka je sada vidljiva", + "item.edit.reinstate.cancel": "Otkazati", + "item.edit.reinstate.confirm": "Obnoviti", + "item.edit.reinstate.description": "Da li ste sigurni da ovu stavku treba vratiti u arhivu?", + "item.edit.reinstate.error": "Došlo je do greške pri vraćanju stavke", + "item.edit.reinstate.header": "Vratite stavku: {{ id }}", + "item.edit.reinstate.success": "Stavka je uspešno vraćena", + "item.edit.relationships.discard-button": "Odbaciti", + "item.edit.relationships.edit.buttons.add": "Dodati", + "item.edit.relationships.edit.buttons.remove": "Ukloniti", + "item.edit.relationships.edit.buttons.undo": "Poništiti promene", + "item.edit.relationships.no-relationships": "Nema relacija", + "item.edit.relationships.notifications.discarded.content": "Vaše promene su odbačene. Da biste vratili svoje promene, kliknite na dugme \"Poništiti\".", + "item.edit.relationships.notifications.discarded.title": "Promene su odbačene", + "item.edit.relationships.notifications.failed.title": "Greška pri izmeni relacija", + "item.edit.relationships.notifications.outdated.content": "Stavku na kojoj trenutno radite je promenio drugi korisnik. Vaše trenutne promene su odbačene da bi se sprečili konflikti", + "item.edit.relationships.notifications.outdated.title": "Zastarele promene", + "item.edit.relationships.notifications.saved.content": "Vaše promene u relacijama ove stavke su sačuvane.", + "item.edit.relationships.notifications.saved.title": "Relacije su sačuvane", + "item.edit.relationships.reinstate-button": "Poništi", + "item.edit.relationships.save-button": "Sačuvati", + "item.edit.relationships.no-entity-type": "Dodajte metapodatke \"dspace.entity.type\" da biste omogućili relacije za ovu stavku", + "item.edit.return": "Nazad", + "item.edit.tabs.bitstreams.head": "Bitstream-ovi", + "item.edit.tabs.bitstreams.title": "Izmena stavke - Bitstream-ovi", + "item.edit.tabs.curate.head": "Kuriranje", + "item.edit.tabs.curate.title": "Izmena stavke - Kuriranje", + "item.edit.curate.title": "Kuriranje stavke: {{item}}", + "item.edit.tabs.access-control.head": "Kontrola pristupa", + "item.edit.tabs.access-control.title": "Izmena stavke - Kontrola pristupa", + "item.edit.tabs.metadata.head": "Metapodaci", + "item.edit.tabs.metadata.title": "Izmena stavke – Metapodaci", + "item.edit.tabs.relationships.head": "Relacije", + "item.edit.tabs.relationships.title": "Izmena stavke - Relacije", + "item.edit.tabs.status.buttons.authorizations.button": "Ovlašćenja...", + "item.edit.tabs.status.buttons.authorizations.label": "Izmenite smernice ovlašćenja stavke", + "item.edit.tabs.status.buttons.delete.button": "Trajno izbrisati", + "item.edit.tabs.status.buttons.delete.label": "Potpuno izbrisati stavku", + "item.edit.tabs.status.buttons.mappedCollections.button": "Mapirane kolekcije", + "item.edit.tabs.status.buttons.mappedCollections.label": "Upravljajte mapiranim kolekcijama", + "item.edit.tabs.status.buttons.move.button": "Premesti ovu stavku u drugu kolekciju", + "item.edit.tabs.status.buttons.move.label": "Premesti stavku u drugu kolekciju", + "item.edit.tabs.status.buttons.private.button": "Postavite da bude nevidljivo...", + "item.edit.tabs.status.buttons.private.label": "Postavite stavku da bude nevidljiva", + "item.edit.tabs.status.buttons.public.button": "Postavite da bude vidljivo...", + "item.edit.tabs.status.buttons.public.label": "Postavite stavku da bude vidljiva", + "item.edit.tabs.status.buttons.reinstate.button": "Ponovo postavite...", + "item.edit.tabs.status.buttons.reinstate.label": "Vratite stavku u repozitorijum", + "item.edit.tabs.status.buttons.unauthorized": "Niste ovlašćeni da izvršite ovu radnju", + "item.edit.tabs.status.buttons.withdraw.button": "Povucite ovu stavku", + "item.edit.tabs.status.buttons.withdraw.label": "Povucite stavku iz repozitorijuma", + "item.edit.tabs.status.description": "Dobrodošli na stranicu za upravljanje stavkama. Odavde možete povući, vratiti, premestiti ili izbrisati stavku. Takođe možete ažurirati ili dodati nove metapodatke / bitstream-ove na drugim karticama.", + "item.edit.tabs.status.head": "Status", + "item.edit.tabs.status.labels.handle": "Handle", + "item.edit.tabs.status.labels.id": "Interni ID stavke", + "item.edit.tabs.status.labels.itemPage": "Stranica stavke", + "item.edit.tabs.status.labels.lastModified": "Poslednja izmena", + "item.edit.tabs.status.title": "Izmena stavke - Status", + "item.edit.tabs.versionhistory.head": "Istorija verzija", + "item.edit.tabs.versionhistory.title": "Izmena stavke - Istorija verzija", + "item.edit.tabs.versionhistory.under-construction": "Izmena ili dodavanje novih verzija još uvek nije moguće u ovom korisničkom interfejsu.", + "item.edit.tabs.view.head": "Prikaži stavku", + "item.edit.tabs.view.title": "Izmeni stavku - Prikaži", + "item.edit.withdraw.cancel": "Otkazati", + "item.edit.withdraw.confirm": "Povucite", + "item.edit.withdraw.description": "Da li ste sigurni da ovu stavku treba povući iz arhive?", + "item.edit.withdraw.error": "Došlo je do greške pri povlačenju stavke", + "item.edit.withdraw.header": "Povucite stavku: {{ id }}", + "item.edit.withdraw.success": "Stavka je uspešno povučena", + "item.orcid.return": "Nazad", + "item.listelement.badge": "Stavka", + "item.page.description": "Opis", + "item.page.journal-issn": "ISSN časopisa", + "item.page.journal-title": "Naslov časopisa", + "item.page.publisher": "Izdavač", + "item.page.titleprefix": "Stavka:", + "item.page.volume-title": "Naslov sveske", + "item.search.results.head": "Rezultati pretrage stavki", + "item.search.title": "Pretraga stavke", + "item.truncatable-part.show-more": "Prikažite još", + "item.truncatable-part.show-less": "Skupiti", + "workflow-item.search.result.delete-supervision.modal.header": "Izbrišite nalog za nadzor", + "workflow-item.search.result.delete-supervision.modal.info": "Da li ste sigurni da želite da izbrišete nalog za nadzor", + "workflow-item.search.result.delete-supervision.modal.cancel": "Otkazati", + "workflow-item.search.result.delete-supervision.modal.confirm": "Izbrisati", + "workflow-item.search.result.notification.deleted.success": "Uspešno je izbrisan nalog za nadzor \"{{name}}\"", + "workflow-item.search.result.notification.deleted.failure": "Neuspešno brisanje naloga za nadzor \"{{name}}\"", + "workflow-item.search.result.list.element.supervised-by": "Pregledao:", + "workflow-item.search.result.list.element.supervised.remove-tooltip": "Ukloniti grupu za nadzor", + "item.page.abstract": "Sažetak", + "item.page.author": "Autori", + "item.page.citation": "Citat", + "item.page.collections": "Kolekcije", + "item.page.collections.loading": "Učitavanje...", + "item.page.collections.load-more": "Učitajte još", + "item.page.date": "Datum", + "item.page.edit": "Izmenite ovu stavku", + "item.page.files": "Fajlovi", + "item.page.filesection.description": "Opis:", + "item.page.filesection.download": "Preuzimanje", + "item.page.filesection.format": "Format:", + "item.page.filesection.name": "ime:", + "item.page.filesection.size": "Veličina:", + "item.page.journal.search.title": "Članci u ovom časopisu", + "item.page.link.full": "Pun zapis stavke", + "item.page.link.simple": "Jednostavan zapis stavke", + "item.page.orcid.title": "ORCID", + "item.page.orcid.tooltip": "Otvorite stranicu za podešavanje ORCID-a", + "item.page.person.search.title": "Članci ovog autora", + "item.page.related-items.view-more": "Prikaži još {{ amount}}", + "item.page.related-items.view-less": "Sakrij poslednji {{ amount}}", + "item.page.relationships.isAuthorOfPublication": "Publikacije", + "item.page.relationships.isJournalOfPublication": "Publikacije", + "item.page.relationships.isOrgUnitOfPerson": "Autori", + "item.page.relationships.isOrgUnitOfProject": "Istraživački projekti", + "item.page.subject": "Ključne reči", + "item.page.uri": "URI", + "item.page.bitstreams.view-more": "Prikaži više", + "item.page.bitstreams.collapse": "Skupiti", + "item.page.filesection.original.bundle": "Originalni paket", + "item.page.filesection.license.bundle": "Licencni paket", + "item.page.return": "Nazad", + "item.page.version.create": "Kreirajte novu verziju", + "item.page.version.hasDraft": "Nova verzija se ne može kreirati zato što je u toku podnošenje", + "item.page.claim.button": "Potvrda", + "item.page.claim.tooltip": "Potvrdi ovu stavku kao profil", + "item.preview.dc.identifier.uri": "Identifikator:", + "item.preview.dc.contributor.author": "Autori:", + "item.preview.dc.date.issued": "Datum objavljivanja:", + "item.preview.dc.description.abstract": "Sažetak:", + "item.preview.dc.identifier.other": "Drugi identifikator:", + "item.preview.dc.language.iso": "Jezik:", + "item.preview.dc.subject": "Predmeti:", + "item.preview.dc.title": "Naslov:", + "item.preview.dc.type": "Tip:", + "item.preview.oaire.citation.issue": "Izdanje", + "item.preview.oaire.citation.volume": "Opseg", + "item.preview.dc.relation.issn": "ISSN", + "item.preview.dc.identifier.isbn": "ISBN", + "item.preview.dc.identifier": "Identifikator:", + "item.preview.dc.relation.ispartof": "Časopis ili serija", + "item.preview.dc.identifier.doi": "DOI", + "item.preview.dc.publisher": "Izdavač:", + "item.preview.person.familyName": "prezime:", + "item.preview.person.givenName": "Ime:", + "item.preview.person.identifier.orcid": "ORCID:", + "item.preview.project.funder.name": "Finansijer:", + "item.preview.project.funder.identifier": "Identifikator finansijera:", + "item.preview.oaire.awardNumber": "ID finansiranja:", + "item.preview.dc.title.alternative": "Akronim:", + "item.preview.dc.coverage.spatial": "Jurisdikcija:", + "item.preview.oaire.fundingStream": "Tok finansiranja:", + "item.select.confirm": "Potvrdite izabrano", + "item.select.empty": "Nema stavki za prikaz", + "item.select.table.author": "Autor", + "item.select.table.collection": "Kolekcija", + "item.select.table.title": "Naslov", + "item.version.history.empty": "Još uvek nema drugih verzija za ovu stavku.", + "item.version.history.head": "Istorija verzija", + "item.version.history.return": "Nazad", + "item.version.history.selected": "Izabrana verzija", + "item.version.history.selected.alert": "Trenutno gledate verziju {{verzija}} stavke.", + "item.version.history.table.version": "Verzija", + "item.version.history.table.item": "Stavka", + "item.version.history.table.editor": "Urednik", + "item.version.history.table.date": "Datum", + "item.version.history.table.summary": "Rezime", + "item.version.history.table.workspaceItem": "Stavka radnog prostora", + "item.version.history.table.workflowItem": "Stavka procesa rada", + "item.version.history.table.actions": "Postupak", + "item.version.history.table.action.editWorkspaceItem": "Uredite stavku radnog prostora", + "item.version.history.table.action.editSummary": "Uredite rezime", + "item.version.history.table.action.saveSummary": "Sačuvajte izmene rezimea", + "item.version.history.table.action.discardSummary": "Odbacite izmene rezimea", + "item.version.history.table.action.newVersion": "Kreirajte novu verziju od ovog", + "item.version.history.table.action.deleteVersion": "Izbrišite verziju", + "item.version.history.table.action.hasDraft": "Nova verzija se ne može kreirati zato što je u toku prihvat u istoriji verzija", + "item.version.notice": "Ovo nije najnovija verzija ove stavke. Najnoviju verziju možete pronaći ovde.", + "item.version.create.modal.header": "Nova verzija", + "item.version.create.modal.text": "Napravite novu verziju za ovu stavku", + "item.version.create.modal.text.startingFrom": "počevši od verzije {{version}}", + "item.version.create.modal.button.confirm": "Kreirajte", + "item.version.create.modal.button.confirm.tooltip": "Kreirajte novu verziju", + "item.version.create.modal.button.cancel": "Poništiti, otkazati", + "item.version.create.modal.button.cancel.tooltip": "Ne kreirajte novu verziju", + "item.version.create.modal.form.summary.label": "Rezime", + "item.version.create.modal.form.summary.placeholder": "Ubacite rezime za novu verziju", + "item.version.create.modal.submitted.header": "Kreiranje nove verzije...", + "item.version.create.modal.submitted.text": "Nova verzija je u izradi. Ovo može potrajati neko vreme ako stavka ima mnogo veza.", + "item.version.create.notification.success": "Nova verzija je napravljena sa brojem verzije {{version}}", + "item.version.create.notification.failure": "Nova verzija nije kreirana", + "item.version.create.notification.inProgress": "Nova verzija se ne može kreirati zato što je u toku prihvat u istoriji verzija", + "item.version.delete.modal.header": "Izbrišite verziju", + "item.version.delete.modal.text": "Da li želite da izbrišete verziju {{version}}?", + "item.version.delete.modal.button.confirm": "Izbrišite", + "item.version.delete.modal.button.confirm.tooltip": "Izbrišite ovu verziju", + "item.version.delete.modal.button.cancel": "Poništiti, otkazati", + "item.version.delete.modal.button.cancel.tooltip": "Nemojte brisati ovu verziju", + "item.version.delete.notification.success": "Verzija broj {{version}} je izbrisana", + "item.version.delete.notification.failure": "Verzija broj {{version}} nije izbrisana", + "item.version.edit.notification.success": "Sažetak verzije broj {{version}} je promenjen", + "item.version.edit.notification.failure": "Sažetak verzije broj {{version}} nije promenjen", + "itemtemplate.edit.metadata.add-button": "Dodati", + "itemtemplate.edit.metadata.discard-button": "Odbaciti", + "itemtemplate.edit.metadata.edit.buttons.confirm": "Potvrditi", + "itemtemplate.edit.metadata.edit.buttons.drag": "Prevucite da biste promenili redosled", + "itemtemplate.edit.metadata.edit.buttons.edit": "Izmeniti", + "itemtemplate.edit.metadata.edit.buttons.remove": "Ukloniti", + "itemtemplate.edit.metadata.edit.buttons.undo": "Poništiti promene", + "itemtemplate.edit.metadata.edit.buttons.unedit": "Zaustavite izmene", + "itemtemplate.edit.metadata.empty": "Šablon stavke trenutno ne sadrži nikakve metapodatke. Kliknite na Dodaj da biste započeli dodavanje vrednosti metapodataka.", + "itemtemplate.edit.metadata.headers.edit": "Izmeniti", + "itemtemplate.edit.metadata.headers.field": "Polje", + "itemtemplate.edit.metadata.headers.language": "Jezik", + "itemtemplate.edit.metadata.headers.value": "Vrednost", + "itemtemplate.edit.metadata.metadatafield.error": "Došlo je do greške prilikom provere polja metapodataka", + "itemtemplate.edit.metadata.metadatafield.invalid": "Molimo izaberite važeće polje metapodataka", + "itemtemplate.edit.metadata.notifications.discarded.content": "Vaše promene su odbačene. Da biste vratili svoje promene, kliknite na dugme \"Poništi\".", + "itemtemplate.edit.metadata.notifications.discarded.title": "Promene su odbačene", + "itemtemplate.edit.metadata.notifications.error.title": "Došlo je do greške", + "itemtemplate.edit.metadata.notifications.invalid.content": "Vaše promene nisu sačuvane. Molimo proverite da li su sva polja ispravna pre nego što sačuvate.", + "itemtemplate.edit.metadata.notifications.invalid.title": "Metapodaci su nevažeći", + "itemtemplate.edit.metadata.notifications.outdated.content": "Drugi korisnik je promenio šablon stavke na kome trenutno radite. Vaše trenutne promene se odbacuju da bi se sprečili konflikti", + "itemtemplate.edit.metadata.notifications.outdated.title": "Promene su zastarele", + "itemtemplate.edit.metadata.notifications.saved.content": "Vaše promene metapodataka ovog šablona stavke su sačuvane.", + "itemtemplate.edit.metadata.notifications.saved.title": "Metapodaci su sačuvani", + "itemtemplate.edit.metadata.reinstate-button": "Poništiti", + "itemtemplate.edit.metadata.reset-order-button": "Poništiti promenu redosleda", + "itemtemplate.edit.metadata.save-button": "Sačuvati", + "journal.listelement.badge": "Časopis", + "journal.page.description": "Opis", + "journal.page.edit": "Uredite ovu stavku", + "journal.page.editor": "Glavni urednik", + "journal.page.issn": "ISSN", + "journal.page.publisher": "Izdavač", + "journal.page.titleprefix": "Časopis:", + "journal.search.results.head": "Rezultati pretrage časopisa", + "journal-relationships.search.results.head": "Rezultati pretrage časopisa", + "journal.search.title": "Pretraga časopisa", + "journalissue.listelement.badge": "Izdanje časopisa", + "journalissue.page.description": "Opis", + "journalissue.page.edit": "Izmenite ovu stavku", + "journalissue.page.issuedate": "Datum izdanja", + "journalissue.page.journal-issn": "Časopis ISSN", + "journalissue.page.journal-title": "Naslov časopisa", + "journalissue.page.keyword": "Ključne reči", + "journalissue.page.number": "Broj", + "journalissue.page.titleprefix": "Izdanje časopisa:", + "journalvolume.listelement.badge": "Sveska časopisa", + "journalvolume.page.description": "Opis", + "journalvolume.page.edit": "Izmenite ovu stavku", + "journalvolume.page.issuedate": "Datum izdanja", + "journalvolume.page.titleprefix": "Sveska časopisa:", + "journalvolume.page.volume": "Sveska", + "iiifsearchable.listelement.badge": "Spisak medija", + "iiifsearchable.page.titleprefix": "Dokument:", + "iiifsearchable.page.doi": "Trajna veza:", + "iiifsearchable.page.issue": "Izdanje:", + "iiifsearchable.page.description": "Opis:", + "iiifviewer.fullscreen.notice": "Koristite ceo ekran da bolje vidite.", + "iiif.listelement.badge": "Image Media", + "iiif.page.titleprefix": "Slika:", + "iiif.page.doi": "Trajna veza:", + "iiif.page.issue": "Izdanje:", + "iiif.page.description": "Opis:", + "loading.bitstream": "Učitavanje bitstream-a...", + "loading.bitstreams": "Učitavanje bitstream-ova...", + "loading.browse-by": "Učitavanje stavki...", + "loading.browse-by-page": "Učitavanje stranice...", + "loading.collection": "Učitavanje kolekcije...", + "loading.collections": "Učitavanje kolekcija...", + "loading.content-source": "Učitavanje izvora sadržaja...", + "loading.community": "Učitavanje zajednice...", + "loading.default": "Učitavanje...", + "loading.item": "Učitavanje stavke...", + "loading.items": "Učitavanje stavki...", + "loading.mydspace-results": "Učitavanje stavki...", + "loading.objects": "Učitavanje...", + "loading.recent-submissions": "Učitavanje nedavnih podnesaka...", + "loading.search-results": "Učitavanje rezultata pretrage...", + "loading.sub-collections": "Učitavanje potkolekcija...", + "loading.sub-communities": "Učitavanje podzajednica...", + "loading.top-level-communities": "Učitavanje zajednica najvišeg nivoa...", + "login.form.email": "Email adresa", + "login.form.forgot-password": "Zaboravili ste lozinku?", + "login.form.header": "Molimo prijavite se na DSpace", + "login.form.new-user": "Novi korisnik? Kliknite ovde da se registrujete.", + "login.form.or-divider": "ili", + "login.form.oidc": "Prijavite se sa OIDC", + "login.form.orcid": "Prijavite se sa ORCID-om", + "login.form.password": "Lozinka", + "login.form.shibboleth": "Prijavite se sa Shibboleth", + "login.form.submit": "Prijavite se", + "login.title": "Prijavite se", + "login.breadcrumbs": "Prijavite se", + "logout.form.header": "Odjavite se sa DSpace-a", + "logout.form.submit": "Odjavite se", + "logout.title": "Odjavite se", + "menu.header.admin": "Menadžment", + "menu.header.image.logo": "Logo repozitorijuma", + "menu.header.admin.description": "Menadžment meni", + "menu.section.access_control": "Kontrola pristupa", + "menu.section.access_control_authorizations": "Ovlašćenja", + "menu.section.access_control_bulk": "Upravljanje masovnim pristupom", + "menu.section.access_control_groups": "Grupe", + "menu.section.access_control_people": "Ljudi", + "menu.section.admin_search": "Admin pretraga", + "menu.section.browse_community": "Ova zajednica", + "menu.section.browse_community_by_author": "Po autoru", + "menu.section.browse_community_by_issue_date": "Po datumu izdanja", + "menu.section.browse_community_by_title": "Po naslovu", + "menu.section.browse_global": "Čitav repozitorijum", + "menu.section.browse_global_by_author": "Po autoru", + "menu.section.browse_global_by_dateissued": "Po datumu izdanja", + "menu.section.browse_global_by_subject": "Po predmetu", + "menu.section.browse_global_by_srsc": "Po kategoriji predmeta", + "menu.section.browse_global_by_title": "Po naslovu", + "menu.section.browse_global_communities_and_collections": "Zajednice i kolekcije", + "menu.section.control_panel": "Kontrolna tabla", + "menu.section.curation_task": "Kurativni zadatak", + "menu.section.edit": "Urediti", + "menu.section.edit_collection": "Kolekcija", + "menu.section.edit_community": "Zajednica", + "menu.section.edit_item": "Stavka", + "menu.section.export": "Izvoz", + "menu.section.export_collection": "Kolekcija", + "menu.section.export_community": "Zajednica", + "menu.section.export_item": "Stavka", + "menu.section.export_metadata": "Metapodaci", + "menu.section.export_batch": "Grupni izvoz (ZIP)", + "menu.section.icon.access_control": "Odeljak menija Kontrola pristupa", + "menu.section.icon.admin_search": "Odeljak menija za admin pretragu", + "menu.section.icon.control_panel": "Odeljak menija kontrolne table", + "menu.section.icon.curation_tasks": "Odeljak menija Zadatak kuriranja", + "menu.section.icon.edit": "Uredite odeljak menija", + "menu.section.icon.export": "Izvezite odeljak menija", + "menu.section.icon.find": "Pronađite odeljak menija", + "menu.section.icon.health": "Odeljak menija za zdravstvenu proveru", + "menu.section.icon.import": "Uvezite odeljak menija", + "menu.section.icon.new": "Novi odeljak menija", + "menu.section.icon.pin": "Zakačite bočnu traku", + "menu.section.icon.processes": "Procesi provere zdravlja", + "menu.section.icon.registries": "Odeljak menija Registri", + "menu.section.icon.statistics_task": "Odeljak menija Statistički zadatak", + "menu.section.icon.workflow": "Odeljak menija Administracija procesa rada", + "menu.section.icon.unpin": "Otkačite bočnu traku", + "menu.section.import": "Uvoz", + "menu.section.import_batch": "Grupni uvoz (ZIP)", + "menu.section.import_metadata": "Metapodaci", + "menu.section.new": "Novo", + "menu.section.new_collection": "Kolekcija", + "menu.section.new_community": "Zajednica", + "menu.section.new_item": "Stavka", + "menu.section.new_item_version": "Verzija stavke", + "menu.section.new_process": "Proces", + "menu.section.pin": "Zakačite bočnu traku", + "menu.section.unpin": "Otkačite bočnu traku", + "menu.section.processes": "Procesi", + "menu.section.health": "Zdravlje", + "menu.section.registries": "Registri", + "menu.section.registries_format": "Format", + "menu.section.registries_metadata": "Metapodaci", + "menu.section.statistics": "Statistika", + "menu.section.statistics_task": "Statistički zadatak", + "menu.section.toggle.access_control": "Uključite odeljak Kontrola pristupa", + "menu.section.toggle.control_panel": "Uključite odeljak Kontrolna tabla", + "menu.section.toggle.curation_task": "Uključi/isključi odeljak Zadatak kuriranja", + "menu.section.toggle.edit": "Uključite odeljak Uredi", + "menu.section.toggle.export": "Uključite odeljak Izvezi", + "menu.section.toggle.find": "Uključi odeljak Pronađi", + "menu.section.toggle.import": "Uključite odeljak Uvezi", + "menu.section.toggle.new": "Uključite novi odeljak", + "menu.section.toggle.registries": "Uključite odeljak Registri", + "menu.section.toggle.statistics_task": "Uključi/isključi odeljak statistički zadatak", + "menu.section.workflow": "Administracija procesa rada", + "metadata-export-search.tooltip": "Izvezite rezultate pretrage kao CSV", + "metadata-export-search.submit.success": "Izvoz je uspešno započet", + "metadata-export-search.submit.error": "Pokretanje izvoza nije uspelo", + "mydspace.breadcrumbs": "Moj DSpace", + "mydspace.description": "", + "mydspace.messages.controller-help": "Izaberite ovu opciju da biste poslali poruku podnosiocu stavke.", + "mydspace.messages.description-placeholder": "Unesite svoju poruku ovde...", + "mydspace.messages.hide-msg": "Sakrijte poruku", + "mydspace.messages.mark-as-read": "Označite kao pročitano", + "mydspace.messages.mark-as-unread": "Označite kao nepročitanu", + "mydspace.messages.no-content": "Bez sadržaja.", + "mydspace.messages.no-messages": "Još nema poruka.", + "mydspace.messages.send-btn": "Pošalji", + "mydspace.messages.show-msg": "Prikaži poruku", + "mydspace.messages.subject-placeholder": "Predmet...", + "mydspace.messages.submitter-help": "Izaberite ovu opciju da biste poslali poruku kontroloru.", + "mydspace.messages.title": "Poruke", + "mydspace.messages.to": "Do", + "mydspace.new-submission": "Novi podnesak", + "mydspace.new-submission-external": "Uvezite metapodatke iz spoljnog izvora", + "mydspace.new-submission-external-short": "Uvezite metapodatke", + "mydspace.results.head": "Vaši podnesci", + "mydspace.results.no-abstract": "Nema sažetka", + "mydspace.results.no-authors": "Nema autora", + "mydspace.results.no-collections": "Nema kolekcija", + "mydspace.results.no-date": "Nema datuma", + "mydspace.results.no-files": "Nema fajlova", + "mydspace.results.no-results": "Nema stavki za prikaz", + "mydspace.results.no-title": "Bez naslova", + "mydspace.results.no-uri": "Nema URI", + "mydspace.search-form.placeholder": "Pretraga u mydspace...", + "mydspace.show.workflow": "Radni zadaci", + "mydspace.show.workspace": "Vaši podnesci", + "mydspace.show.supervisedWorkspace": "Nadzirane stavke", + "mydspace.status.mydspaceArchived": "Arhivirano", + "mydspace.status.mydspaceValidation": "Validacija", + "mydspace.status.mydspaceWaitingController": "Čeka se kontroler", + "mydspace.status.mydspaceWorkflow": "Radni proces", + "mydspace.status.mydspaceWorkspace": "Radni prostor", + "mydspace.title": "MyDSpace", + "mydspace.upload.upload-failed": "Greška pri kreiranju novog radnog prostora. Molimo proverite otpremljeni sadržaj pre nego što pokušate ponovo.", + "mydspace.upload.upload-failed-manyentries": "Neobrađen fajl. Otkriveno je previše unosa, ali je dozvoljen samo za jedan fajl.", + "mydspace.upload.upload-failed-moreonefile": "Neobrađen zahtev. Dozvoljen je samo jedan fajl.", + "mydspace.upload.upload-multiple-successful": "{{qty}} novih stavki radnog prostora je kreirano.", + "mydspace.view-btn": "Pogled", + "nav.browse.header": "Čitav repozitorijum", + "nav.community-browse.header": "Od zajednice", + "nav.context-help-toggle": "Uključite dodatnu pomoć", + "nav.language": "Promena jezika", + "nav.login": "Prijavi se", + "nav.user-profile-menu-and-logout": "Meni korisničkog profila i odjava", + "nav.logout": "Odjaviti se", + "nav.main.description": "Glavna navigaciona traka", + "nav.mydspace": "MyDSpace", + "nav.profile": "Profil", + "nav.search": "Pretraga", + "nav.search.button": "Pošaljite pretragu", + "nav.statistics.header": "Statistika", + "nav.stop-impersonating": "Prestanite da se predstavljate kao Eperson", + "nav.subscriptions": "Pretplate", + "nav.toggle": "Uključivanje navigacije", + "nav.user.description": "Traka korisničkog profila", + "none.listelement.badge": "Stavka", + "orgunit.listelement.badge": "Organizaciona jedinica", + "orgunit.listelement.no-title": "Bez naslova", + "orgunit.page.city": "Grad", + "orgunit.page.country": "Država", + "orgunit.page.dateestablished": "Datum postavljanja", + "orgunit.page.description": "Opis", + "orgunit.page.edit": "Izmeniti ovu stavku", + "orgunit.page.id": "ID", + "orgunit.page.titleprefix": "Organizaciona jedinica:", + "pagination.options.description": "Opcije straničenja", + "pagination.results-per-page": "Rezultati po stranici", + "pagination.showing.detail": "{{ range }} od {{ total }}", + "pagination.showing.label": "Prikazuje se", + "pagination.sort-direction": "Opcije sortiranja", + "person.listelement.badge": "Osoba", + "person.listelement.no-title": "Ime nije pronađeno", + "person.page.birthdate": "Datum rođenja", + "person.page.edit": "Izmeniti ovu stavku", + "person.page.email": "Email adresa", + "person.page.firstname": "Ime", + "person.page.jobtitle": "Zvanje", + "person.page.lastname": "Prezime", + "person.page.name": "Ime", + "person.page.link.full": "Prikaži sve metapodatke", + "person.page.orcid": "ORCID", + "person.page.staffid": "ID zaposlenih", + "person.page.titleprefix": "Osoba:", + "person.search.results.head": "Rezultati pretrage osoba", + "person-relationships.search.results.head": "Rezultati pretrage osoba", + "person.search.title": "Pretraga osoba", + "process.new.select-parameters": "Parametri", + "process.new.cancel": "Otkazati", + "process.new.submit": "Sačuvati", + "process.new.select-script": "Skripta", + "process.new.select-script.placeholder": "Izaberite skriptu...", + "process.new.select-script.required": "Skripta je obavezna", + "process.new.parameter.file.upload-button": "Izaberite fajl...", + "process.new.parameter.file.required": "Molimo izaberite fajl", + "process.new.parameter.string.required": "Vrednost parametra je obavezna", + "process.new.parameter.type.value": "vrednost", + "process.new.parameter.type.file": "fajl", + "process.new.parameter.required.missing": "Sledeći parametri su obavezni, ali još uvek nedostaju:", + "process.new.notification.success.title": "Uspeh", + "process.new.notification.success.content": "Proces je uspešno kreiran", + "process.new.notification.error.title": "Greška", + "process.new.notification.error.content": "Došlo je do greške pri kreiranju ovog procesa", + "process.new.notification.error.max-upload.content": "Fajl prevazilazi maksimalnu veličinu za otpremanje", + "process.new.header": "Kreirajte novi proces", + "process.new.title": "Kreirajte novi proces", + "process.new.breadcrumbs": "Kreirajte novi proces", + "process.detail.arguments": "Argumenti", + "process.detail.arguments.empty": "Ovaj proces ne sadrži argumente", + "process.detail.back": "Nazad", + "process.detail.output": "Izlaz procesa", + "process.detail.logs.button": "Preuzmite izlaz procesa", + "process.detail.logs.loading": "Preuzimanje", + "process.detail.logs.none": "Ovaj proces nema izlaz", + "process.detail.output-files": "Izlazni fajlovi", + "process.detail.output-files.empty": "Ovaj proces ne sadrži izlazne fajlove", + "process.detail.script": "Skripta", + "process.detail.title": "Proces: {{ id }} - {{ name }}", + "process.detail.start-time": "Vreme početka", + "process.detail.end-time": "Vreme završetka", + "process.detail.status": "Status", + "process.detail.create": "Napravite sličan proces", + "process.detail.actions": "Akcije", + "process.detail.delete.button": "Izbrišite proces", + "process.detail.delete.header": "Izbrišite proces", + "process.detail.delete.body": "Da li ste sigurni da želite da izbrišete trenutni proces?", + "process.detail.delete.cancel": "Poništiti, otkazati", + "process.detail.delete.confirm": "Izbrišite proces", + "process.detail.delete.success": "Proces je uspešno obrisan.", + "process.detail.delete.error": "Nešto je pošlo naopako prilikom brisanja procesa", + "process.overview.table.finish": "Vreme završetka (UTC)", + "process.overview.table.id": "ID procesa", + "process.overview.table.name": "Ime", + "process.overview.table.start": "Vreme početka (UTC)", + "process.overview.table.status": "Status", + "process.overview.table.user": "Korisnik", + "process.overview.title": "Pregled procesa", + "process.overview.breadcrumbs": "Pregled procesa", + "process.overview.new": "Novo", + "process.overview.table.actions": "Akcije", + "process.overview.delete": "Izbrišite {{count}} procesa", + "process.overview.delete.clear": "Očistite izbor za brisanje", + "process.overview.delete.processing": "Brišu se procesi ({{count}}). Sačekajte da se brisanje u potpunosti završi. Imajte na umu da ovo može potrajati.", + "process.overview.delete.body": "Da li ste sigurni da želite da izbrišete {{count}} proces(e)?", + "process.overview.delete.header": "Izbrišite procese", + "process.bulk.delete.error.head": "Greška u procesu brisanja", + "process.bulk.delete.error.body": "Nije moguće izbrisati proces sa ID-om {{processId}}. Preostali procesi će nastaviti da se brišu.", + "process.bulk.delete.success": "Procesi ({{count}}) su uspešno izbrisani", + "profile.breadcrumbs": "Ažuriranje profila", + "profile.card.identify": "Identitet", + "profile.card.security": "Bezbednost", + "profile.form.submit": "Sačuvati", + "profile.groups.head": "Grupe ovlašćenja kojima pripadate", + "profile.special.groups.head": "Autorizacija posebnih grupa kojima pripadate", + "profile.head": "Ažuriranje profil", + "profile.metadata.form.error.firstname.required": "Ime je obavezno", + "profile.metadata.form.error.lastname.required": "Prezime je obavezno", + "profile.metadata.form.label.email": "Email adresa", + "profile.metadata.form.label.firstname": "Ime", + "profile.metadata.form.label.language": "Jezik", + "profile.metadata.form.label.lastname": "Prezime", + "profile.metadata.form.label.phone": "Kontakt telefon", + "profile.metadata.form.notifications.success.content": "Vaše promene na profilu su sačuvane.", + "profile.metadata.form.notifications.success.title": "Profil je sačuvan", + "profile.notifications.warning.no-changes.content": "Nisu napravljene nikakve promene na profilu.", + "profile.notifications.warning.no-changes.title": "Bez promene", + "profile.security.form.error.matching-passwords": "Lozinke se ne poklapaju.", + "profile.security.form.info": "Opciono, možete da unesete novu lozinku u polje ispod i potvrdite je tako što ćete je ponovo ukucati u drugo polje.", + "profile.security.form.label.password": "Lozinka", + "profile.security.form.label.passwordrepeat": "Ponovo otkucajte da biste potvrdili", + "profile.security.form.label.current-password": "Trenutna lozinka", + "profile.security.form.notifications.success.content": "Vaše promene lozinke su sačuvane.", + "profile.security.form.notifications.success.title": "Lozinka je sačuvana", + "profile.security.form.notifications.error.title": "Greška pri promeni lozinki", + "profile.security.form.notifications.error.change-failed": "Došlo je do greške pri pokušaju promene lozinke. Proverite da li je trenutna lozinka tačna.", + "profile.security.form.notifications.error.not-same": "Navedene lozinke nisu iste.", + "profile.security.form.notifications.error.general": "Popunite obavezna polja bezbednosnog obrasca.", + "profile.title": "Ažuriranje profila", + "profile.card.researcher": "Profil istraživača", + "project.listelement.badge": "Istraživački projekat", + "project.page.contributor": "Saradnici", + "project.page.description": "Opis", + "project.page.edit": "Uredite ovu stavku", + "project.page.expectedcompletion": "Očekivani završetak", + "project.page.funder": "finansijeri", + "project.page.id": "ID", + "project.page.keyword": "Ključne reči", + "project.page.status": "Status", + "project.page.titleprefix": "Istraživački projekat:", + "project.search.results.head": "Rezultati pretrage projekta", + "project-relationships.search.results.head": "Rezultati pretrage projekta", + "publication.listelement.badge": "Publikacija", + "publication.page.description": "Opis", + "publication.page.edit": "Uredite ovu stavku", + "publication.page.journal-issn": "Časopis ISSN", + "publication.page.journal-title": "Naslov časopisa", + "publication.page.publisher": "Izdavač", + "publication.page.titleprefix": "Publikacija:", + "publication.page.volume-title": "Naslov sveske", + "publication.search.results.head": "Rezultati pretrage publikacije", + "publication-relationships.search.results.head": "Rezultati pretrage publikacije", + "publication.search.title": "Pretraga publikacija", + "media-viewer.next": "Sledeće", + "media-viewer.previous": "Prethodno", + "media-viewer.playlist": "Play lista", + "register-email.title": "Registracija novog korisnika", + "register-page.create-profile.header": "Napravite profil", + "register-page.create-profile.identification.header": "Identifikovati", + "register-page.create-profile.identification.email": "Email adresa", + "register-page.create-profile.identification.first-name": "Ime *", + "register-page.create-profile.identification.first-name.error": "Molimo unesite ime", + "register-page.create-profile.identification.last-name": "Prezime *", + "register-page.create-profile.identification.last-name.error": "Molimo unesite prezime", + "register-page.create-profile.identification.contact": "Kontakt telefon", + "register-page.create-profile.identification.language": "Jezik", + "register-page.create-profile.security.header": "Bezbednost", + "register-page.create-profile.security.info": "Molimo unesite lozinku u polje ispod i potvrdite je tako što ćete je ponovo uneti u drugo polje.", + "register-page.create-profile.security.label.password": "Lozinka *", + "register-page.create-profile.security.label.passwordrepeat": "Unesite ponovo da potvrdite *", + "register-page.create-profile.security.error.empty-password": "Molimo unesite lozinku u polje ispod.", + "register-page.create-profile.security.error.matching-passwords": "Lozinke se ne poklapaju.", + "register-page.create-profile.submit": "Završite registraciju", + "register-page.create-profile.submit.error.content": "Nešto nije u redu prilikom registracije novog korisnika.", + "register-page.create-profile.submit.error.head": "Neuspešna registracija", + "register-page.create-profile.submit.success.content": "Registracija je uspešna. Prijavljeni ste kao kreirani korisnik.", + "register-page.create-profile.submit.success.head": "Registracija je završena", + "register-page.registration.header": "Registracija novog korisnika", + "register-page.registration.info": "Registrujte nalog da biste se pretplatili na kolekcije za ažuriranja putem email-a i pošaljite nove stavke na DSpace.", + "register-page.registration.email": "Email adresa *", + "register-page.registration.email.error.required": "Molimo unesite email adresu", + "register-page.registration.email.error.not-email-form": "Molimo unesite važeću email adresu.", + "register-page.registration.email.error.not-valid-domain": "Koristite email sa dozvoljenim domenima: {{ domains }}", + "register-page.registration.email.hint": "Ova adresa će biti verifikovana i korišćena kao vaše korisničko ime.", + "register-page.registration.submit": "Registrovati", + "register-page.registration.success.head": "Verifikacioni email je poslat", + "register-page.registration.success.content": "Email je poslat na {{ email }} koji sadrži poseban URL i dalja uputstva.", + "register-page.registration.error.head": "Greška pri pokušaju registracije email-a", + "register-page.registration.error.content": "Došlo je do greške pri registraciji sledeće email adrese: {{ email }}", + "register-page.registration.error.recaptcha": "Greška pri pokušaju autentifikacije pomoću recaptcha", + "register-page.registration.google-recaptcha.must-accept-cookies": "Da biste se registrovali, morate prihvatiti kolačiće za registraciju i vraćanje lozinke (Google reCaptcha).", + "register-page.registration.error.maildomain": "Ova email adresa nije na listi domena koji se mogu registrovati. Dozvoljeni domeni su {{ domains }}", + "register-page.registration.google-recaptcha.open-cookie-settings": "Otvorite podešavanja kolačića", + "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", + "register-page.registration.google-recaptcha.notification.message.error": "Došlo je do greške tokom reCaptcha verifikacije", + "register-page.registration.google-recaptcha.notification.message.expired": "Verifikacija je istekla. Molimo potvrdite ponovo.", + "register-page.registration.info.maildomain": "Nalozi se mogu registrovati za email adrese domena", + "relationships.add.error.relationship-type.content": "Nije pronađeno odgovarajuće podudaranje za tip veze {{ type }} između dve stavke", + "relationships.add.error.server.content": "Server je vratio grešku", + "relationships.add.error.title": "Nije moguće dodati vezu", + "relationships.isAuthorOf": "Autori", + "relationships.isAuthorOf.Person": "Autori (osoba)", + "relationships.isAuthorOf.OrgUnit": "Autori (organizacione jedinice)", + "relationships.isIssueOf": "Izdanja časopisa", + "relationships.isJournalIssueOf": "Izdanja časopsa", + "relationships.isJournalOf": "Časopisi", + "relationships.isOrgUnitOf": "Organizacione jedinice", + "relationships.isPersonOf": "Autori", + "relationships.isProjectOf": "Istraživački projekti", + "relationships.isPublicationOf": "Izdanja", + "relationships.isPublicationOfJournalIssue": "Članci", + "relationships.isSingleJournalOf": "Časopis", + "relationships.isSingleVolumeOf": "Sveska časopisa", + "relationships.isVolumeOf": "Sveske časopisa", + "relationships.isContributorOf": "Saradnici", + "relationships.isContributorOf.OrgUnit": "Saradnik (Organizaciona jedinica)", + "relationships.isContributorOf.Person": "Saradnik", + "relationships.isFundingAgencyOf.OrgUnit": "Osnivač", + "repository.image.logo": "Logo repozitorijuma", + "repository.title": "DSpace Repozitorijum", + "repository.title.prefix": "DSpace Repozitorijum ::", + "resource-policies.add.button": "Dodati", + "resource-policies.add.for.": "Dodajte nove smernice", + "resource-policies.add.for.bitstream": "Dodajte nove bitstream smernice", + "resource-policies.add.for.bundle": "Dodajte nove smernice paketa", + "resource-policies.add.for.item": "Dodajte nove smernice stavki", + "resource-policies.add.for.community": "Dodajte nove smernice zajednice", + "resource-policies.add.for.collection": "Dodajte nove smernice kolekcija", + "resource-policies.create.page.heading": "Kreirajte nove smernice resursa za", + "resource-policies.create.page.failure.content": "Došlo je do greške pri kreiranju smernica resursa.", + "resource-policies.create.page.success.content": "Operacija uspela", + "resource-policies.create.page.title": "Kreirajte nove smernice resursa", + "resource-policies.delete.btn": "Izbrišite izabrano", + "resource-policies.delete.btn.title": "Izbrišite izabrane smernice resursa", + "resource-policies.delete.failure.content": "Došlo je do greške prilikom brisanja izabranih smernica resursa.", + "resource-policies.delete.success.content": "Operacija uspela", + "resource-policies.edit.page.heading": "Izmenite smernice resursa", + "resource-policies.edit.page.failure.content": "Došlo je do greške prilikom izmene smernica resursa.", + "resource-policies.edit.page.target-failure.content": "Došlo je do greške prilikom izmene cilja (ePerson ili grupe) smernica resursa.", + "resource-policies.edit.page.other-failure.content": "Došlo je do greške prilikom izmene smernica resursa. Cilj (ePerson ili grupa) je uspešno ažuriran.", + "resource-policies.edit.page.success.content": "Operacija uspela", + "resource-policies.edit.page.title": "Izmena smernica resursa", + "resource-policies.form.action-type.label": "Izabrati vrstu akcije", + "resource-policies.form.action-type.required": "Morate da izaberete akciju polise resursa.", + "resource-policies.form.eperson-group-list.label": "Eperson ili grupa koja će dobiti ovlašćenje", + "resource-policies.form.eperson-group-list.select.btn": "Izabrati", + "resource-policies.form.eperson-group-list.tab.eperson": "Potražite ePerson", + "resource-policies.form.eperson-group-list.tab.group": "Potražite grupu", + "resource-policies.form.eperson-group-list.table.headers.action": "Postupak", + "resource-policies.form.eperson-group-list.table.headers.id": "ID", + "resource-policies.form.eperson-group-list.table.headers.name": "Ime", + "resource-policies.form.eperson-group-list.modal.header": "Ne može se promeniti tip", + "resource-policies.form.eperson-group-list.modal.text1.toGroup": "Nije moguće zameniti ePerson sa grupom.", + "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "Nije moguće zameniti grupu sa ePerson.", + "resource-policies.form.eperson-group-list.modal.text2": "Izbrišite trenutne polise resursa i kreirajte nove sa željenim tipom.", + "resource-policies.form.eperson-group-list.modal.close": "Ok", + "resource-policies.form.date.end.label": "Datum završetka", + "resource-policies.form.date.start.label": "Datum početka", + "resource-policies.form.description.label": "Opis", + "resource-policies.form.name.label": "Ime", + "resource-policies.form.policy-type.label": "Izaberite tip polise", + "resource-policies.form.policy-type.required": "Morate da izaberete tip polise resursa.", + "resource-policies.table.headers.action": "Postupak", + "resource-policies.table.headers.date.end": "Datum završetka", + "resource-policies.table.headers.date.start": "Datum početka", + "resource-policies.table.headers.edit": "Izmeniti", + "resource-policies.table.headers.edit.group": "Izmeniti grupu", + "resource-policies.table.headers.edit.policy": "Izmeniti smernice", + "resource-policies.table.headers.eperson": "Eperson", + "resource-policies.table.headers.group": "Grupa", + "resource-policies.table.headers.id": "ID", + "resource-policies.table.headers.name": "Ime", + "resource-policies.table.headers.policyType": "tip", + "resource-policies.table.headers.title.for.bitstream": "Smernice za bitstream", + "resource-policies.table.headers.title.for.bundle": "Smernice za paket", + "resource-policies.table.headers.title.for.item": "Smernice za stavku", + "resource-policies.table.headers.title.for.community": "Smernice za zajednicu", + "resource-policies.table.headers.title.for.collection": "Smernice za kolekciju", + "search.description": "", + "search.switch-configuration.title": "Prikaži", + "search.title": "Pretraga", + "search.breadcrumbs": "Pretraga", + "search.search-form.placeholder": "Pretražite spremište...", + "search.filters.applied.f.author": "Autor", + "search.filters.applied.f.dateIssued.max": "Datum završetka", + "search.filters.applied.f.dateIssued.min": "Datum početka", + "search.filters.applied.f.dateSubmitted": "Datum prihvatanja", + "search.filters.applied.f.discoverable": "Nije moguće otkriti", + "search.filters.applied.f.entityType": "Tip stavke", + "search.filters.applied.f.has_content_in_original_bundle": "Ima fajlove", + "search.filters.applied.f.itemtype": "Tip", + "search.filters.applied.f.namedresourcetype": "Status", + "search.filters.applied.f.subject": "Predmet", + "search.filters.applied.f.submitter": "Podnosilac", + "search.filters.applied.f.jobTitle": "Zvanje", + "search.filters.applied.f.birthDate.max": "Rođenje - krajnji datum", + "search.filters.applied.f.birthDate.min": "Rođenje - početni datum", + "search.filters.applied.f.supervisedBy": "Pregledao", + "search.filters.applied.f.withdrawn": "Povučen", + "search.filters.filter.author.head": "Autor", + "search.filters.filter.author.placeholder": "Ime autora", + "search.filters.filter.author.label": "Pretražite ime autora", + "search.filters.filter.birthDate.head": "Datum rođenja", + "search.filters.filter.birthDate.placeholder": "Datum rođenja", + "search.filters.filter.birthDate.label": "Pretražite datum rođenja", + "search.filters.filter.collapse": "Skupi filter", + "search.filters.filter.creativeDatePublished.head": "Datum objavljivanja", + "search.filters.filter.creativeDatePublished.placeholder": "Datum objavljivanja", + "search.filters.filter.creativeDatePublished.label": "Pretražite datum objavljivanja", + "search.filters.filter.creativeWorkEditor.head": "Editor", + "search.filters.filter.creativeWorkEditor.placeholder": "Editor", + "search.filters.filter.creativeWorkEditor.label": "Pretraga urednika", + "search.filters.filter.creativeWorkKeywords.head": "Predmet", + "search.filters.filter.creativeWorkKeywords.placeholder": "Predmet", + "search.filters.filter.creativeWorkKeywords.label": "Predmet pretrage", + "search.filters.filter.creativeWorkPublisher.head": "Izdavač", + "search.filters.filter.creativeWorkPublisher.placeholder": "Izdavač", + "search.filters.filter.creativeWorkPublisher.label": "Pretraga izdavača", + "search.filters.filter.dateIssued.head": "Datum", + "search.filters.filter.dateIssued.max.placeholder": "Maksimalni datum", + "search.filters.filter.dateIssued.max.label": "Kraj", + "search.filters.filter.dateIssued.min.placeholder": "Minimalni datum", + "search.filters.filter.dateIssued.min.label": "Početak", + "search.filters.filter.dateSubmitted.head": "Datum prihvatanja", + "search.filters.filter.dateSubmitted.placeholder": "Datum prihvatanja", + "search.filters.filter.dateSubmitted.label": "Pretraga datuma prihvatanja", + "search.filters.filter.discoverable.head": "Nije moguće otkriti", + "search.filters.filter.withdrawn.head": "Povučen", + "search.filters.filter.entityType.head": "Tip stavke", + "search.filters.filter.entityType.placeholder": "Tip stavke", + "search.filters.filter.entityType.label": "Pretražite tip stavke", + "search.filters.filter.expand": "Proširi filter", + "search.filters.filter.has_content_in_original_bundle.head": "Ima fajlove", + "search.filters.filter.itemtype.head": "Tip", + "search.filters.filter.itemtype.placeholder": "Tip", + "search.filters.filter.itemtype.label": "Tip pretrage", + "search.filters.filter.jobTitle.head": "Zvanje", + "search.filters.filter.jobTitle.placeholder": "Zvanje", + "search.filters.filter.jobTitle.label": "Pretraga zvanja", + "search.filters.filter.knowsLanguage.head": "Poznati jezik", + "search.filters.filter.knowsLanguage.placeholder": "Poznati jezik", + "search.filters.filter.knowsLanguage.label": "Pretražite poznati jezik", + "search.filters.filter.namedresourcetype.head": "Status", + "search.filters.filter.namedresourcetype.placeholder": "Status", + "search.filters.filter.namedresourcetype.label": "Status pretrage", + "search.filters.filter.objectpeople.head": "Ljudi", + "search.filters.filter.objectpeople.placeholder": "Ljudi", + "search.filters.filter.objectpeople.label": "Pretražite ljude", + "search.filters.filter.organizationAddressCountry.head": "Država", + "search.filters.filter.organizationAddressCountry.placeholder": "Država", + "search.filters.filter.organizationAddressCountry.label": "Pretražite državu", + "search.filters.filter.organizationAddressLocality.head": "Grad", + "search.filters.filter.organizationAddressLocality.placeholder": "Grad", + "search.filters.filter.organizationAddressLocality.label": "Pretražite grad", + "search.filters.filter.organizationFoundingDate.head": "Datum osnivanja", + "search.filters.filter.organizationFoundingDate.placeholder": "Datum osnivanja", + "search.filters.filter.organizationFoundingDate.label": "Pretražite datum osnivanja", + "search.filters.filter.scope.head": "Opseg", + "search.filters.filter.scope.placeholder": "Filter opsega", + "search.filters.filter.scope.label": "Pretražite filter opsega", + "search.filters.filter.show-less": "Skupiti", + "search.filters.filter.show-more": "Prikaži više", + "search.filters.filter.subject.head": "Predmet", + "search.filters.filter.subject.placeholder": "Predmet", + "search.filters.filter.subject.label": "Predmet pretrage", + "search.filters.filter.submitter.head": "Podnosilac", + "search.filters.filter.submitter.placeholder": "Podnosilac", + "search.filters.filter.submitter.label": "Podnosilac pretrage", + "search.filters.filter.show-tree": "Pregledajte stablo {{ name }}", + "search.filters.filter.supervisedBy.head": "Pregledao", + "search.filters.filter.supervisedBy.placeholder": "Pregledao", + "search.filters.filter.supervisedBy.label": "Pretragu nadgledao", + "search.filters.entityType.JournalIssue": "Izdanja časopisa", + "search.filters.entityType.JournalVolume": "Sveska časopisa", + "search.filters.entityType.OrgUnit": "Organizaciona jedinica", + "search.filters.has_content_in_original_bundle.true": "Da", + "search.filters.has_content_in_original_bundle.false": "Ne", + "search.filters.discoverable.true": "Ne", + "search.filters.discoverable.false": "Da", + "search.filters.namedresourcetype.Archived": "Arhivirano", + "search.filters.namedresourcetype.Validation": "Ispravnost", + "search.filters.namedresourcetype.Waiting for Controller": "Čeka se kontrolor", + "search.filters.namedresourcetype.Workflow": "Proces rada", + "search.filters.namedresourcetype.Workspace": "Radni prostor", + "search.filters.withdrawn.true": "Da", + "search.filters.withdrawn.false": "Ne", + "search.filters.head": "Filteri", + "search.filters.reset": "Resetovanje filtera", + "search.filters.search.submit": "Prihvatite", + "search.form.search": "Pretraga", + "search.form.search_dspace": "Svi repozitorijumi", + "search.form.scope.all": "Čitav repozitorijum", + "search.results.head": "Rezultati pretrage", + "search.results.no-results": "Vaša pretraga nije dala rezultate. Imate problema sa pronalaženjem onoga što tražite? Pokušajte da stavite", + "search.results.no-results-link": "navodnike oko toga", + "search.results.empty": "Vaša pretraga nije dala rezultate.", + "search.results.view-result": "Pogledati", + "search.results.response.500": "Došlo je do greške tokom izvršavanja upita, molimo pokušajte ponovo kasnije", + "default.search.results.head": "Rezultati pretrage", + "default-relationships.search.results.head": "Rezultati pretrage", + "search.sidebar.close": "Povratak na rezultate", + "search.sidebar.filters.title": "Filteri", + "search.sidebar.open": "Alati za pretragu", + "search.sidebar.results": "rezultati", + "search.sidebar.settings.rpp": "Rezultati po strani", + "search.sidebar.settings.sort-by": "Sortirati po", + "search.sidebar.settings.title": "Podešavanja", + "search.view-switch.show-detail": "Prikazati detalje", + "search.view-switch.show-grid": "Prikazati kao mrežu", + "search.view-switch.show-list": "Prikazati kao listu", + "sorting.ASC": "Rastuće", + "sorting.DESC": "Opadajuće", + "sorting.dc.title.ASC": "Naslov rastuće", + "sorting.dc.title.DESC": "Naslov opadajuće", + "sorting.score.ASC": "Najmanje relevantno", + "sorting.score.DESC": "Najrelevantnije", + "sorting.dc.date.issued.ASC": "Datum izdanja rastuće", + "sorting.dc.date.issued.DESC": "Datum izdanja opadajuće", + "sorting.dc.date.accessioned.ASC": "Datum pristupa rastuće", + "sorting.dc.date.accessioned.DESC": "Datum pristupa opadajuće", + "sorting.lastModified.ASC": "Poslednja izmena rastuće", + "sorting.lastModified.DESC": "Poslednja izmena opadajuće", + "statistics.title": "Statistika", + "statistics.header": "Statistika za {{ scope }}", + "statistics.breadcrumbs": "Statistika", + "statistics.page.no-data": "Nema dostupnih podataka", + "statistics.table.no-data": "Nema dostupnih podataka", + "statistics.table.title.TotalVisits": "Ukupno poseta", + "statistics.table.title.TotalVisitsPerMonth": "Ukupno poseta mesečno", + "statistics.table.title.TotalDownloads": "Posete fajlovima", + "statistics.table.title.TopCountries": "Najviše pregleda po državama", + "statistics.table.title.TopCities": "Najviše pregleda po gradovima", + "statistics.table.header.views": "Pogledi", + "statistics.table.no-name": "(ime objekta se ne može učitati)", + "submission.edit.breadcrumbs": "Izmena podneska", + "submission.edit.title": "Izmena podneska", + "submission.general.cancel": "Otkazati", + "submission.general.cannot_submit": "Nemate dozvolu da podnesete novu prijavu.", + "submission.general.deposit": "Depozit", + "submission.general.discard.confirm.cancel": "Otkazati", + "submission.general.discard.confirm.info": "Ova operacija se ne može opozvati. Da li ste sigurni?", + "submission.general.discard.confirm.submit": "Da siguran sam", + "submission.general.discard.confirm.title": "Odbacite podnesak", + "submission.general.discard.submit": "Odbaciti", + "submission.general.info.saved": "Sačuvano", + "submission.general.info.pending-changes": "Nesačuvane promene", + "submission.general.save": "Sačuvati", + "submission.general.save-later": "Sačuvati za kasnije", + "submission.import-external.page.title": "Uvezite metapodatke iz spoljnog izvora", + "submission.import-external.title": "Uvezite metapodatke iz spoljnog izvora", + "submission.import-external.title.Journal": "Uvezite časopis iz spoljnog izvora", + "submission.import-external.title.JournalIssue": "Uvezite izdanje časopisa iz spoljnog izvora", + "submission.import-external.title.JournalVolume": "Uvezite volume časopisa iz spoljnog izvora", + "submission.import-external.title.OrgUnit": "Uvezite izdavača iz spoljnog izvora", + "submission.import-external.title.Person": "Uvezite osobu iz spoljnog izvora", + "submission.import-external.title.Project": "Uvezite projekat iz spoljnog izvora", + "submission.import-external.title.Publication": "Uvezite publikaciju iz spoljnog izvora", + "submission.import-external.title.none": "Uvezite metapodatke iz spoljnog izvora", + "submission.import-external.page.hint": "Unesite upit iznad da biste pronašli stavke sa veba za uvoz u DSpace.", + "submission.import-external.back-to-my-dspace": "Nazad na MyDSpace", + "submission.import-external.search.placeholder": "Pretraga spoljnog izvora", + "submission.import-external.search.button": "Pretraga", + "submission.import-external.search.button.hint": "Napišite nekoliko reči za pretragu", + "submission.import-external.search.source.hint": "Izaberite spoljni izvor", + "submission.import-external.source.arxiv": "arXiv", + "submission.import-external.source.ads": "NASA/ADS", + "submission.import-external.source.cinii": "CiNii", + "submission.import-external.source.crossref": "CrossRef", + "submission.import-external.source.datacite": "DataCite", + "submission.import-external.source.scielo": "SciELO", + "submission.import-external.source.scopus": "Scopus", + "submission.import-external.source.vufind": "VuFind", + "submission.import-external.source.wos": "Naučna mreža", + "submission.import-external.source.orcidWorks": "ORCID", + "submission.import-external.source.epo": "Evropski zavod za patente (EPO)", + "submission.import-external.source.loading": "Učitavanje...", + "submission.import-external.source.sherpaJournal": "SHERPA časopisi", + "submission.import-external.source.sherpaJournalIssn": "SHERPA časopisi od ISSN", + "submission.import-external.source.sherpaPublisher": "SHERPA Publishers", + "submission.import-external.source.openAIREFunding": "Finansiranje OpenAIRE API-ja", + "submission.import-external.source.orcid": "ORCID", + "submission.import-external.source.pubmed": "Pubmed", + "submission.import-external.source.pubmedeu": "Pubmed Europe", + "submission.import-external.source.lcname": "Biblioteka Kongresnih imena", + "submission.import-external.preview.title": "Pregled stavke", + "submission.import-external.preview.title.Publication": "Pregled publikacije", + "submission.import-external.preview.title.none": "Pregled stavke", + "submission.import-external.preview.title.Journal": "Pregled časopisa", + "submission.import-external.preview.title.OrgUnit": "Pregled organizacione jedinice", + "submission.import-external.preview.title.Person": "Pregled osobe", + "submission.import-external.preview.title.Project": "Pregled projekta", + "submission.import-external.preview.subtitle": "Metapodaci u nastavku su uvezeni iz spoljnog izvora. Biće unapred popunjen kada započnete prihvatanje.", + "submission.import-external.preview.button.import": "Počnite sa prihvatanjem", + "submission.import-external.preview.error.import.title": "Greška pri prihvatanju", + "submission.import-external.preview.error.import.body": "Došlo je do greške tokom ulaznog procesa uvoza spoljašnjeg izvora.", + "submission.sections.describe.relationship-lookup.close": "Zatvori", + "submission.sections.describe.relationship-lookup.external-source.added": "Uspešno je dodat lokalni ulaz u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication": "Uvezite udaljenog autora", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal": "Uvezite udaljeni dnevnik", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Uvezite udaljeno izdanje časopisa", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Uvezite udaljeni opseg časopisa", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Projekat", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Uvezite udaljenu stavku", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Uvezite udaljeni događaj", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Uvezite udaljeni proizvod", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Uvezite udaljenu opremu", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Uvezite udaljenu organizacionu jedinicu", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Uvezite udaljeni fond", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Uvezite udaljenu osobu", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Uvezite udaljeni patent", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Uvezite udaljeni projekat", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Uvezite udaljenu publikaciju", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "Dodat je novi entitet!", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Projekat", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Finansiranje OpenAIRE API-ja", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Uvezi udaljenog autora", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity": "Lokalni autor je uspešno dodat u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity": "Spoljašnji autor je uspešno uvezen i dodat u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority": "Uprava", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new": "Uvezite kao novi ulaz lokalne uprave", + "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel": "Poništiti, otkazati", + "submission.sections.describe.relationship-lookup.external-source.import-modal.collection": "Izaberite kolekciju u koju ćete uvesti nove ulaze", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities": "Entiteti", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new": "Uvezite kao novi lokalni entitet", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname": "Uvezite iz LC imena", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid": "Uvezite iz ORCID-a", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal": "Uvezite iz časopisa Sherpa", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher": "Uvezite iz Sherpa izdavača", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed": "Uvezite iz PubMed-a", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv": "Uvezite iz arXiv", + "submission.sections.describe.relationship-lookup.external-source.import-modal.import": "Uvoz", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title": "Uvezite udaljeni časopis", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity": "Uspešno dodat lokalni časopis u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity": "Uspešno uvezen i dodat spoljašnji časopis u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Uvezite udaljeno izdanje časopisa", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Uspešno je dodat lokalni broj časopisa u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Uspešno uvezen i dodat spoljašnji broj časopisa u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Uvezite udaljeni opseg časopisa", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity": "Uspešno je dodat lokalni volumen časopisa u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity": "Uspešno uvezen i dodat spoljašnji opseg časopisa u izbor", + "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Izaberite lokalno podudaranje:", + "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Poništite sve", + "submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Opozovite izbor stranice", + "submission.sections.describe.relationship-lookup.search-tab.loading": "Učitavanje...", + "submission.sections.describe.relationship-lookup.search-tab.placeholder": "Upit za pretragu", + "submission.sections.describe.relationship-lookup.search-tab.search": "Idi", + "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Pretraga...", + "submission.sections.describe.relationship-lookup.search-tab.select-all": "Izaberi sve", + "submission.sections.describe.relationship-lookup.search-tab.select-page": "Izaberite stranicu", + "submission.sections.describe.relationship-lookup.selected": "Izabrane stavke {{ size }}", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Lokalni autori ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Lokalni časopisi ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Lokalni projekti ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication": "Lokalne publikacije ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person": "Lokalni autori ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit": "Lokalne organizacione jedinice ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage": "Lokalni paketi podataka ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile": "Lokalni fajlovi podataka ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Lokalni časopisi ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Lokalna izdanja časopisa ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Lokalna izdanja časopisa ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Lokalni opseg časopisa ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Lokalni opseg časopisa ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa časopisi ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "Sherpa izdavači({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid": "ORCID ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname": "LC imena ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.pubmed": "PubMed ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.arxiv": "arXiv ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfPublication": "Potražite finansijere", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication": "Potražite sredstva", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Potražite organizacione jedinice", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "Finansiranje OpenAIRE API-ja", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Projekti", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Finansijer projekta", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publikacija autora", + "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Finansiranje OpenAIRE API-ja", + "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Projekat", + "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Projekti", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Finansijer projekta", + "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Pretraga...", + "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Trenutni izbor ({{ count }})", + "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Izdanja časopisa", + "submission.sections.describe.relationship-lookup.title.JournalIssue": "Izdanja časopisa", + "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Sveske časopisa", + "submission.sections.describe.relationship-lookup.title.JournalVolume": "Sveske časopisa", + "submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Časopisi", + "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Autori", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Finansijska agencija", + "submission.sections.describe.relationship-lookup.title.Project": "Projekti", + "submission.sections.describe.relationship-lookup.title.Publication": "Publikacije", + "submission.sections.describe.relationship-lookup.title.Person": "Autori", + "submission.sections.describe.relationship-lookup.title.OrgUnit": "Organizacione jedinice", + "submission.sections.describe.relationship-lookup.title.DataPackage": "Paketi podataka", + "submission.sections.describe.relationship-lookup.title.DataFile": "Fajlovi sa podacima", + "submission.sections.describe.relationship-lookup.title.Funding Agency": "Finansijska agencija", + "submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Finansiranje", + "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Matična organizaciona jedinica", + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publikacija", + "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Uključite padajući meni", + "submission.sections.describe.relationship-lookup.selection-tab.settings": "Podešavanja", + "submission.sections.describe.relationship-lookup.selection-tab.no-selection": "Vaš izbor je trenutno prazan.", + "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication": "Izabrani autori", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Izabrani časopisi", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Izabrana sveska časopisa", + "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Izabrani projekti", + "submission.sections.describe.relationship-lookup.selection-tab.title.Publication": "Izabrane publikacije", + "submission.sections.describe.relationship-lookup.selection-tab.title.Person": "Izabrani autori", + "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit": "Izabrane organizacione jedinice", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage": "Izabrani paketi podataka", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile": "Izabrani fajlovi sa podacima", + "submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Izabrani časopisi", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Izabrano izdanje", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Izabrana sveska časopisa", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Izabrana finansijska agencija", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Izabrano finansiranje", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Izabrano izdanje", + "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Izabrana organizaciona jedinica", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcid": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.lcname": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.selection-tab.title": "Rezultati pretrage", + "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Da li želite da sačuvate \"{{ value }}\" kao varijantu imena za ovu osobu da biste vi i drugi mogli da ga ponovo koristite za buduće slanje? Ako to ne uradite, i dalje možete da ga koristite za ovaj podnesak.", + "submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Sačuvajte novu varijantu imena", + "submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Koristi se samo za ovaj podnesak", + "submission.sections.ccLicense.type": "Tip licence", + "submission.sections.ccLicense.select": "Izaberite tip licence…", + "submission.sections.ccLicense.change": "Promenite tip licence…", + "submission.sections.ccLicense.none": "Nema dostupnih licenci", + "submission.sections.ccLicense.option.select": "Izaberite opciju…", + "submission.sections.ccLicense.link": "Izabrali ste sledeću licencu:", + "submission.sections.ccLicense.confirmation": "Dodeljujem licencu iznad", + "submission.sections.general.add-more": "Dodajte još", + "submission.sections.general.cannot_deposit": "Prijava se ne može dovršiti zbog grešaka u obrascu.
Popunite sva obavezna polja da biste dovršili prijavu.", + "submission.sections.general.collection": "Kolekcija", + "submission.sections.general.deposit_error_notice": "Došlo je do problema prilikom slanja stavke, molimo pokušajte ponovo kasnije.", + "submission.sections.general.deposit_success_notice": "Prijava je uspešno podneta.", + "submission.sections.general.discard_error_notice": "Došlo je do problema pri odbacivanju stavke, molimo pokušajte ponovo kasnije.", + "submission.sections.general.discard_success_notice": "Slanje je uspešno odbačeno.", + "submission.sections.general.metadata-extracted": "Novi metapodaci su izdvojeni i dodati u odeljak {{sectionId}}.", + "submission.sections.general.metadata-extracted-new-section": "Novi odeljak {{sectionId}} je dodat u prijavu.", + "submission.sections.general.no-collection": "Nije pronađena kolekcija", + "submission.sections.general.no-sections": "Nema dostupnih opcija", + "submission.sections.general.save_error_notice": "Došlo je do problema prilikom čuvanja stavke, molimo pokušajte ponovo kasnije.", + "submission.sections.general.save_success_notice": "Prijava je uspešno sačuvana.", + "submission.sections.general.search-collection": "Potražite kolekciju", + "submission.sections.general.sections_not_valid": "Postoje nepotpuni odeljci.", + "submission.sections.identifiers.info": "Sledeći identifikatori će biti kreirani za vašu stavku:", + "submission.sections.identifiers.no_handle": "Za ovu stavku nije vezan handle.", + "submission.sections.identifiers.no_doi": "Nijedan DOIs nije vezan za ovu stavku.", + "submission.sections.identifiers.handle_label": "Handle:", + "submission.sections.identifiers.doi_label": "DOI:", + "submission.sections.identifiers.otherIdentifiers_label": "Ostali identifikatori:", + "submission.sections.submit.progressbar.accessCondition": "Uslovi pristupanja stavki", + "submission.sections.submit.progressbar.CClicense": "Creative Commons licenca", + "submission.sections.submit.progressbar.describe.recycle": "Reciklaža", + "submission.sections.submit.progressbar.describe.stepcustom": "Opisati", + "submission.sections.submit.progressbar.describe.stepone": "Opisati", + "submission.sections.submit.progressbar.describe.steptwo": "Opisati", + "submission.sections.submit.progressbar.detect-duplicate": "Potencijalni duplikati", + "submission.sections.submit.progressbar.identifiers": "Identifikatori", + "submission.sections.submit.progressbar.license": "Dozvola za depozit", + "submission.sections.submit.progressbar.sherpapolicy": "Sherpa propisi", + "submission.sections.submit.progressbar.upload": "Dodaj fajlove", + "submission.sections.submit.progressbar.sherpaPolicies": "Informacije o politici otvorenog pristupa izdavača", + "submission.sections.sherpa-policy.title-empty": "Nema dostupnih informacija o smernicama za izdavače. Ako vaš rad ima pridruženi ISSN, unesite ga iznad da biste videli sve povezane smernice otvorenog pristupa za izdavače.", + "submission.sections.status.errors.title": "Greške", + "submission.sections.status.valid.title": "Važeće", + "submission.sections.status.warnings.title": "Upozorenja", + "submission.sections.status.errors.aria": "Ima greške", + "submission.sections.status.valid.aria": "Važeće je", + "submission.sections.status.warnings.aria": "Ima upozorenja", + "submission.sections.status.info.title": "Dodatne Informacije", + "submission.sections.status.info.aria": "Dodatne Informacije", + "submission.sections.toggle.open": "Otvori odeljak", + "submission.sections.toggle.close": "Zatvori odeljak", + "submission.sections.toggle.aria.open": "Proširite {{sectionHeader}} odeljak", + "submission.sections.toggle.aria.close": "Skupite {{sectionHeader}} odeljak", + "submission.sections.upload.delete.confirm.cancel": "Poništiti, otkazati", + "submission.sections.upload.delete.confirm.info": "Ova operacija se ne može opozvati. Jeste li sigurni?", + "submission.sections.upload.delete.confirm.submit": "Da, siguran sam", + "submission.sections.upload.delete.confirm.title": "Izbrišite bitstream", + "submission.sections.upload.delete.submit": "Izbrišite", + "submission.sections.upload.download.title": "Preuzmite bitstream", + "submission.sections.upload.drop-message": "Spustite fajlove da biste ih priložili stavci", + "submission.sections.upload.edit.title": "Uredite bitstream", + "submission.sections.upload.form.access-condition-label": "Tip uslova pristupa", + "submission.sections.upload.form.access-condition-hint": "Izaberite uslov pristupa koji ćete primeniti na bitstream kada se stavka deponuje", + "submission.sections.upload.form.date-required": "Datum je obavezan.", + "submission.sections.upload.form.date-required-from": "Obavezno odobrenje pristupa od datuma.", + "submission.sections.upload.form.date-required-until": "Obavezno odobrenje pristupa do datuma.", + "submission.sections.upload.form.from-label": "Odobrenje pristupa od", + "submission.sections.upload.form.from-hint": "Izaberite datum od koga se primenjuje odgovarajući uslov pristupa", + "submission.sections.upload.form.from-placeholder": "Od", + "submission.sections.upload.form.group-label": "Grupa", + "submission.sections.upload.form.group-required": "Grupa je obavezna.", + "submission.sections.upload.form.until-label": "Odobrenje pristupa do", + "submission.sections.upload.form.until-hint": "Izaberite datum do kojeg se primenjuje odgovarajući uslov pristupa", + "submission.sections.upload.form.until-placeholder": "Sve dok", + "submission.sections.upload.header.policy.default.nolist": "Otpremljeni fajlovi u kolekciji {{collectionName}} biće dostupne prema sledećim grupama:", + "submission.sections.upload.header.policy.default.withlist": "Imajte na umu da će otpremljeni fajlovi u kolekciji {{collectionName}} biti dostupni, pored onoga što je izričito odlučeno za jedan fajl, sa sledećim grupama:", + "submission.sections.upload.info": "Ovde ćete pronaći sve fajlove koji se trenutno nalaze u stavci. Možete da ažurirate metapodatke fajla i uslove pristupa ili otpremite dodatne fajlove tako što ćete ih prevući i otpustiti bilo gde na stranici.", + "submission.sections.upload.no-entry": "Ne", + "submission.sections.upload.no-file-uploaded": "Još uvek nije otpremljen nijedan fajl.", + "submission.sections.upload.save-metadata": "Sačuvaj metapodatke", + "submission.sections.upload.undo": "Poništiti, otkazati", + "submission.sections.upload.upload-failed": "Otpremanje nije uspelo", + "submission.sections.upload.upload-successful": "Otpremanje je uspešno", + "submission.sections.accesses.form.discoverable-description": "Kada je označeno, ova stavka će biti vidljiva u pretrazi/pregledu. Kada nije označeno, stavka će biti dostupna samo preko direktne veze i nikada se neće pojaviti u pretrazi/pregledu.", + "submission.sections.accesses.form.discoverable-label": "Otkrivanje", + "submission.sections.accesses.form.access-condition-label": "Tip uslova pristupa", + "submission.sections.accesses.form.access-condition-hint": "Izaberite uslov pristupa koji ćete primeniti na stavku kada se deponuje", + "submission.sections.accesses.form.date-required": "Datum je obavezan.", + "submission.sections.accesses.form.date-required-from": "Obavezno odobrenje pristupa od datuma.", + "submission.sections.accesses.form.date-required-until": "Obavezno odobrenje pristupa do datuma.", + "submission.sections.accesses.form.from-label": "Odobrenje pristupa od", + "submission.sections.accesses.form.from-hint": "Izaberite datum od koga se primenjuje odgovarajući uslov pristupa", + "submission.sections.accesses.form.from-placeholder": "Od", + "submission.sections.accesses.form.group-label": "Grupa", + "submission.sections.accesses.form.group-required": "Grupa je obavezna.", + "submission.sections.accesses.form.until-label": "Odobrenje pristupa do", + "submission.sections.accesses.form.until-hint": "Izaberite datum do kojeg se primenjuje odgovarajući uslov pristupa", + "submission.sections.accesses.form.until-placeholder": "Sve dok", + "submission.sections.license.granted-label": "Potvrđujem gore navedenu licencu", + "submission.sections.license.required": "Morate prihvatiti licencu", + "submission.sections.license.notgranted": "Morate prihvatiti licencu", + "submission.sections.sherpa.publication.information": "Informacije o publikaciji", + "submission.sections.sherpa.publication.information.title": "Naslov", + "submission.sections.sherpa.publication.information.issns": "ISSN-ovi", + "submission.sections.sherpa.publication.information.url": "URL", + "submission.sections.sherpa.publication.information.publishers": "Izdavač", + "submission.sections.sherpa.publication.information.romeoPub": "Romeo Pub", + "submission.sections.sherpa.publication.information.zetoPub": "Zeto Pub", + "submission.sections.sherpa.publisher.policy": "Propis za izdavače", + "submission.sections.sherpa.publisher.policy.description": "Informacije u nastavku su pronađene preko SherpaRomea. Na osnovu smernica vašeg izdavača, on pruža savete o tome da li je embargo možda neophodan i/ili koje datoteke možete da otpremite. Ako imate pitanja, kontaktirajte svog administratora sajta putem obrasca za povratne informacije u podnožju.", + "submission.sections.sherpa.publisher.policy.openaccess": "Putevi otvorenog pristupa dozvoljeni politikom ovog časopisa navedeni su u nastavku prema verziji članka. Kliknite na putanju za detaljniji prikaz", + "submission.sections.sherpa.publisher.policy.more.information": "Za više informacija pogledajte sledeće linkove:", + "submission.sections.sherpa.publisher.policy.version": "Verzija", + "submission.sections.sherpa.publisher.policy.embargo": "Embargo", + "submission.sections.sherpa.publisher.policy.noembargo": "Nema embarga", + "submission.sections.sherpa.publisher.policy.nolocation": "Nijedan", + "submission.sections.sherpa.publisher.policy.license": "Licenca", + "submission.sections.sherpa.publisher.policy.prerequisites": "Preduslovi", + "submission.sections.sherpa.publisher.policy.location": "Lokacija", + "submission.sections.sherpa.publisher.policy.conditions": "Uslovi", + "submission.sections.sherpa.publisher.policy.refresh": "Osvežite", + "submission.sections.sherpa.record.information": "Zapišite informaciju", + "submission.sections.sherpa.record.information.id": "ID", + "submission.sections.sherpa.record.information.date.created": "Datum kreiranja", + "submission.sections.sherpa.record.information.date.modified": "Poslednja izmena", + "submission.sections.sherpa.record.information.uri": "URI", + "submission.sections.sherpa.error.message": "Došlo je do greške pri preuzimanju Sherpa informacija", + "submission.submit.breadcrumbs": "Novi podnesak", + "submission.submit.title": "Novi podnesak", + "submission.workflow.generic.delete": "Izbrišite", + "submission.workflow.generic.delete-help": "Izaberite ovu opciju da biste odbacili ovu stavku. Zatim će biti zatraženo da to potvrdite.", + "submission.workflow.generic.edit": "Uredite", + "submission.workflow.generic.edit-help": "Izaberite ovu opciju da biste promenili metapodatke stavke.", + "submission.workflow.generic.view": "Pogledajte", + "submission.workflow.generic.view-help": "Izaberite ovu opciju da biste videli metapodatke stavke.", + "submission.workflow.generic.submit_select_reviewer": "Izaberite recenzenta", + "submission.workflow.generic.submit_select_reviewer-help": "izaberite pomoć recenzenta", + "submission.workflow.generic.submit_score": "Ocena", + "submission.workflow.generic.submit_score-help": "rezultat-pomoć", + "submission.workflow.tasks.claimed.approve": "Odobriti", + "submission.workflow.tasks.claimed.approve_help": "Ako ste pregledali stavku i ako je pogodna za pridruživanje kolekciji, izaberite \"Odobriti\".", + "submission.workflow.tasks.claimed.edit": "Izmeniti", + "submission.workflow.tasks.claimed.edit_help": "Izaberite ovu opciju da biste promenili metapodatke stavke.", + "submission.workflow.tasks.claimed.decline": "Odbiti", + "submission.workflow.tasks.claimed.decline_help": "odbiti pomoć", + "submission.workflow.tasks.claimed.reject.reason.info": "Unesite razlog za odbijanje prijave u polje ispod, navodeći da li podnosilac može da reši problem i ponovo pošalje.", + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Opišite razlog odbijanja", + "submission.workflow.tasks.claimed.reject.reason.submit": "Odbacite stavku", + "submission.workflow.tasks.claimed.reject.reason.title": "Razlog", + "submission.workflow.tasks.claimed.reject.submit": "Odbiti", + "submission.workflow.tasks.claimed.reject_help": "Ako ste pregledali stavku i utvrdili da nije prikladna za pridruživanje kolekciji, izaberite \"Odbij\". Od vas će se zatim tražiti da unesete poruku koja navodi zašto je stavka neprikladna i da li podnosilac treba nešto da promeni i ponovo pošalje.", + "submission.workflow.tasks.claimed.return": "Povratak u grupu", + "submission.workflow.tasks.claimed.return_help": "Vratite zadatak u grupu tako da drugi korisnik može da izvrši zadatak.", + "submission.workflow.tasks.generic.error": "Došlo je do greške u radu...", + "submission.workflow.tasks.generic.processing": "Obrada...", + "submission.workflow.tasks.generic.submitter": "Podnosilac", + "submission.workflow.tasks.generic.success": "Operacija uspela", + "submission.workflow.tasks.pool.claim": "Potraživanje", + "submission.workflow.tasks.pool.claim_help": "Dodelite ovaj zadatak sebi.", + "submission.workflow.tasks.pool.hide-detail": "Sakriti detalje", + "submission.workflow.tasks.pool.show-detail": "Prikazati detalje", + "submission.workspace.generic.view": "Pogledati", + "submission.workspace.generic.view-help": "Izaberite ovu opciju da biste videli metapodatke stavke.", + "submitter.empty": "N/A", + "subscriptions.title": "Pretplate", + "subscriptions.item": "Pretplate na stavke", + "subscriptions.collection": "Pretplate na kolekcije", + "subscriptions.community": "Pretplate za zajednice", + "subscriptions.subscription_type": "Vrsta pretplate", + "subscriptions.frequency": "Učestalost pretplate", + "subscriptions.frequency.D": "Dnevno", + "subscriptions.frequency.M": "Mesečno", + "subscriptions.frequency.W": "Nedeljno", + "subscriptions.tooltip": "Pretplatiti se", + "subscriptions.modal.title": "Pretplate", + "subscriptions.modal.type-frequency": "Vrsta i učestalost", + "subscriptions.modal.close": "Zatvoriti", + "subscriptions.modal.delete-info": "Da biste uklonili ovu pretplatu, molimo posetite stranicu \"Pretplate\" ispod vašeg korisničkog profila", + "subscriptions.modal.new-subscription-form.type.content": "Sadržaj", + "subscriptions.modal.new-subscription-form.frequency.D": "Dnevno", + "subscriptions.modal.new-subscription-form.frequency.W": "Nedeljno", + "subscriptions.modal.new-subscription-form.frequency.M": "Mesečno", + "subscriptions.modal.new-subscription-form.submit": "Podnesi", + "subscriptions.modal.new-subscription-form.processing": "Obrada...", + "subscriptions.modal.create.success": "Uspešno ste pretplaćeni na {{ type }}.", + "subscriptions.modal.delete.success": "Pretplata je uspešno izbrisana", + "subscriptions.modal.update.success": "Pretplata na {{ type }} je uspešno ažurirana", + "subscriptions.modal.create.error": "Došlo je do greške tokom kreiranja pretplate", + "subscriptions.modal.delete.error": "Došlo je do greške tokom brisanja pretplate", + "subscriptions.modal.update.error": "Došlo je do greške tokom ažuriranja pretplate", + "subscriptions.table.dso": "Predmet", + "subscriptions.table.subscription_type": "Vrsta pretplate", + "subscriptions.table.subscription_frequency": "Učestalost pretplate", + "subscriptions.table.action": "Postupak", + "subscriptions.table.edit": "Izmeniti", + "subscriptions.table.delete": "Izbrisati", + "subscriptions.table.not-available": "Nije dostupno", + "subscriptions.table.not-available-message": "Pretplaćena stavka je izbrisana ili trenutno nemate dozvolu da je vidite", + "subscriptions.table.empty.message": "Trenutno nemate nijednu pretplatu. Da biste se pretplatili na ažuriranja putem email-a za zajednicu ili kolekciju, koristite dugme za pretplatu na stranici objekta.", + "thumbnail.default.alt": "Umanjena slika", + "thumbnail.default.placeholder": "Nema dostupnih umanjenih slika", + "thumbnail.project.alt": "Logo projekta", + "thumbnail.project.placeholder": "Slika referenta projekta", + "thumbnail.orgunit.alt": "Logo organizacione jedinice", + "thumbnail.orgunit.placeholder": "Slika referenta organizacione jedinice", + "thumbnail.person.alt": "Profilna slika", + "thumbnail.person.placeholder": "Slika profila nije dostupna", + "title": "DSpace", + "vocabulary-treeview.header": "Prikaz hijerarhijskog stabla", + "vocabulary-treeview.load-more": "Učitati još", + "vocabulary-treeview.search.form.reset": "Resetovati", + "vocabulary-treeview.search.form.search": "Pretraga", + "vocabulary-treeview.search.no-result": "Nije bilo stavki za prikaz", + "vocabulary-treeview.tree.description.nsi": "The Norwegian Science Index", + "vocabulary-treeview.tree.description.srsc": "Kategorije predmeta istraživanja", + "vocabulary-treeview.info": "Izaberite temu koju želite da dodate kao filter za pretragu", + "uploader.browse": "pretraži", + "uploader.drag-message": "Prevucite i stavite svoje fajlove ovde", + "uploader.delete.btn-title": "Obriši", + "uploader.or": ", ili", + "uploader.processing": "Obrada otpremljenih fajlova... (sada je bezbedno zatvoriti ovu stranicu)", + "uploader.queue-length": "Dužina reda", + "virtual-metadata.delete-item.info": "Izaberite tipove za koje želite da sačuvate virtuelne metapodatke kao stvarne metapodatke", + "virtual-metadata.delete-item.modal-head": "Virtuelni metapodaci ove relacije", + "virtual-metadata.delete-relationship.modal-head": "Izaberite stavke za koje želite da sačuvate virtuelne metapodatke kao stvarne metapodatke", + "supervisedWorkspace.search.results.head": "Nadzirane stavke", + "workspace.search.results.head": "Vaši podnesci", + "workflowAdmin.search.results.head": "Upravljanje radnim procesom", + "workflow.search.results.head": "Radni zadaci", + "supervision.search.results.head": "Zadaci radnog procesa i radnog prostora", + "workflow-item.edit.breadcrumbs": "Izmena stavke radnog procesa", + "workflow-item.edit.title": "Izmena stavke radnog procesa", + "workflow-item.delete.notification.success.title": "Izbrisano", + "workflow-item.delete.notification.success.content": "Ova stavka radnog procesa je uspešno izbrisana", + "workflow-item.delete.notification.error.title": "Nešto nije u redu", + "workflow-item.delete.notification.error.content": "Nije moguće izbrisati stavku procesa rada", + "workflow-item.delete.title": "Izbrišite stavku radnog procesa", + "workflow-item.delete.header": "Izbrišite stavku radnog procesa", + "workflow-item.delete.button.cancel": "Poništiti, otkazati", + "workflow-item.delete.button.confirm": "Izbrišite", + "workflow-item.send-back.notification.success.title": "Vraćeno podnosiocu", + "workflow-item.send-back.notification.success.content": "Ova stavka radnog procesa je uspešno vraćena podnosiocu", + "workflow-item.send-back.notification.error.title": "Nešto nije u redu", + "workflow-item.send-back.notification.error.content": "Stavka radnog procesa nije mogla da se vrati podnosiocu", + "workflow-item.send-back.title": "Vratite stavku radnog procesa podnosiocu", + "workflow-item.send-back.header": "Vratite stavku radnog procesa podnosiocu", + "workflow-item.send-back.button.cancel": "Poništiti, otkazati", + "workflow-item.send-back.button.confirm": "Vratiti", + "workflow-item.view.breadcrumbs": "Prikaz radnog procesa", + "workspace-item.view.breadcrumbs": "Prikaz radnog prostora", + "workspace-item.view.title": "Prikaz radnog prostora", + "workspace-item.delete.breadcrumbs": "Izbrišite radni prostor", + "workspace-item.delete.header": "Izbrišite stavku radnog prostora", + "workspace-item.delete.button.confirm": "Izbrišite", + "workspace-item.delete.button.cancel": "Poništiti, otkazati", + "workspace-item.delete.notification.success.title": "Izbrisan", + "workspace-item.delete.title": "Ova stavka radnog prostora je uspešno izbrisana", + "workspace-item.delete.notification.error.title": "Nešto nije u redu", + "workspace-item.delete.notification.error.content": "Nije moguće izbrisati stavku radnog prostora", + "workflow-item.advanced.title": "Napredni radni proces", + "workflow-item.selectrevieweraction.notification.success.title": "Izabrani recenzent", + "workflow-item.selectrevieweraction.notification.success.content": "Recenzent za ovu stavku radnog procesa je uspešno izabran", + "workflow-item.selectrevieweraction.notification.error.title": "Nešto nije u redu", + "workflow-item.selectrevieweraction.notification.error.content": "Nije moguće izabrati recenzenta za ovu stavku radnog procesa", + "workflow-item.selectrevieweraction.title": "Izaberite recenzenta", + "workflow-item.selectrevieweraction.header": "Izaberite recenzenta", + "workflow-item.selectrevieweraction.button.cancel": "Poništiti, otkazati", + "workflow-item.selectrevieweraction.button.confirm": "Potvrdite", + "workflow-item.scorereviewaction.notification.success.title": "Ocena pregleda", + "workflow-item.scorereviewaction.notification.success.content": "Ocena za ovu stavku radnog procesa je uspešno poslata", + "workflow-item.scorereviewaction.notification.error.title": "Nešto nije u redu", + "workflow-item.scorereviewaction.notification.error.content": "Nije moguće oceniti ovu stavku", + "workflow-item.scorereviewaction.title": "Ocenite ovu stavku", + "workflow-item.scorereviewaction.header": "Ocenite ovu stavku", + "workflow-item.scorereviewaction.button.cancel": "Poništiti, otkazati", + "workflow-item.scorereviewaction.button.confirm": "Potvrdite", + "idle-modal.header": "Sesija uskoro ističe", + "idle-modal.info": "Iz bezbednosnih razloga, korisničke sesije ističu posle {{ timeToExpire }} minuta neaktivnosti. Vaša sesija uskoro ističe. Da li želite da produžite ili da se odjavite?", + "idle-modal.log-out": "Odjaviti se", + "idle-modal.extend-session": "Produžite sesiju", + "researcher.profile.action.processing": "Obrada...", + "researcher.profile.associated": "Povezani profil istraživača", + "researcher.profile.change-visibility.fail": "Došlo je do neočekivane greške prilikom promene vidljivosti profila", + "researcher.profile.create.new": "Kreiraj novi", + "researcher.profile.create.success": "Profil istraživača je uspešno kreiran", + "researcher.profile.create.fail": "Došlo je do greške tokom kreiranja profila istraživača", + "researcher.profile.delete": "Izbrišite", + "researcher.profile.expose": "Izlaganje", + "researcher.profile.hide": "Sakrijte", + "researcher.profile.not.associated": "Profil istraživača još nije povezan", + "researcher.profile.view": "Pogled", + "researcher.profile.private.visibility": "PRIVATNO", + "researcher.profile.public.visibility": "JAVNO", + "researcher.profile.status": "Status:", + "researcherprofile.claim.not-authorized": "Niste ovlašćeni da potvrdite ovu stavku. Za više detalja kontaktirajte administratora(e).", + "researcherprofile.error.claim.body": "Došlo je do greške pri potvrđivanju profila, molimo vas pokušajte ponovo kasnije", + "researcherprofile.error.claim.title": "Greška", + "researcherprofile.success.claim.body": "Profil je uspešno potvrđen", + "researcherprofile.success.claim.title": "Uspešno", + "person.page.orcid.create": "Kreirajte ORCID ID", + "person.page.orcid.granted-authorizations": "Odobrena ovlašćenja", + "person.page.orcid.grant-authorizations": "Odobrite ovlašćenja", + "person.page.orcid.link": "Povežite se na ORCID ID", + "person.page.orcid.link.processing": "Povezivanje profila sa ORCID-om...", + "person.page.orcid.link.error.message": "Nešto je pošlo naopako pri povezivanju profila sa ORCID-om. Ako se problem i dalje javlja, kontaktirajte administratora.", + "person.page.orcid.orcid-not-linked-message": "ORCID ID ovog profila ({{ orcid }}) još uvek nije povezan sa nalogom u ORCID registru ili je veza istekla.", + "person.page.orcid.unlink": "Prekinite vezu sa ORCID-om", + "person.page.orcid.unlink.processing": "Obrada...", + "person.page.orcid.missing-authorizations": "Nedostaju ovlašćenja", + "person.page.orcid.missing-authorizations-message": "Nedostaju sledeća ovlašćenja:", + "person.page.orcid.no-missing-authorizations-message": "Divno! Ovo polje je prazno, tako da ste odobrili sva prava pristupa za korišćenje svih funkcija koje nudi vaša institucija.", + "person.page.orcid.no-orcid-message": "Još uvek nije povezan ORCID ID. Klikom na dugme ispod moguće je povezati ovaj profil sa ORCID nalogom.", + "person.page.orcid.profile-preferences": "Prioriteti profila", + "person.page.orcid.funding-preferences": "Prioriteti finansiranja", + "person.page.orcid.publications-preferences": "Prioriteti publikacije", + "person.page.orcid.remove-orcid-message": "Ako treba da uklonite svoj ORCID, kontaktirajte administratora repozitorijuma", + "person.page.orcid.save.preference.changes": "Podešavanja ažuriranja", + "person.page.orcid.sync-profile.affiliation": "Pripadnost", + "person.page.orcid.sync-profile.biographical": "Biografski podaci", + "person.page.orcid.sync-profile.education": "Obrazovanje", + "person.page.orcid.sync-profile.identifiers": "Identifikatori", + "person.page.orcid.sync-fundings.all": "Sva sredstva", + "person.page.orcid.sync-fundings.mine": "Moja sredstva", + "person.page.orcid.sync-fundings.my_selected": "Odabrana sredstva", + "person.page.orcid.sync-fundings.disabled": "Onemogućeno", + "person.page.orcid.sync-publications.all": "Sve publikacije", + "person.page.orcid.sync-publications.mine": "Moje publikacije", + "person.page.orcid.sync-publications.my_selected": "Izabrane publikacije", + "person.page.orcid.sync-publications.disabled": "Onemogućeno", + "person.page.orcid.sync-queue.discard": "Odbacite promenu i nemojte da se sinhronizujete sa ORCID registrom", + "person.page.orcid.sync-queue.discard.error": "Odbacivanje zapisa ORCID reda nije uspelo", + "person.page.orcid.sync-queue.discard.success": "Zapis ORCID reda je uspešno odbačen", + "person.page.orcid.sync-queue.empty-message": "Zapis ORCID registra je prazan", + "person.page.orcid.sync-queue.table.header.type": "Tip", + "person.page.orcid.sync-queue.table.header.description": "Opis", + "person.page.orcid.sync-queue.table.header.action": "Postupak", + "person.page.orcid.sync-queue.description.affiliation": "Pripadnosti", + "person.page.orcid.sync-queue.description.country": "Država", + "person.page.orcid.sync-queue.description.education": "Obrazovanja", + "person.page.orcid.sync-queue.description.external_ids": "Spoljašnji id", + "person.page.orcid.sync-queue.description.other_names": "Druga imena", + "person.page.orcid.sync-queue.description.qualification": "Kvalifikacije", + "person.page.orcid.sync-queue.description.researcher_urls": "URL-ovi istraživača", + "person.page.orcid.sync-queue.description.keywords": "Ključne reči", + "person.page.orcid.sync-queue.tooltip.insert": "Dodajte novi unos u ORCID registar", + "person.page.orcid.sync-queue.tooltip.update": "Ažurirajte ovaj unos u ORCID registru", + "person.page.orcid.sync-queue.tooltip.delete": "Uklonite ovaj unos iz ORCID registra", + "person.page.orcid.sync-queue.tooltip.publication": "Publikacija", + "person.page.orcid.sync-queue.tooltip.project": "Projekat", + "person.page.orcid.sync-queue.tooltip.affiliation": "Pripadnost", + "person.page.orcid.sync-queue.tooltip.education": "Оbrazovanje", + "person.page.orcid.sync-queue.tooltip.qualification": "Kvalifikacija", + "person.page.orcid.sync-queue.tooltip.other_names": "Drugo ime", + "person.page.orcid.sync-queue.tooltip.country": "Država", + "person.page.orcid.sync-queue.tooltip.keywords": "Ključna reč", + "person.page.orcid.sync-queue.tooltip.external_ids": "Spoljašnji identifikator", + "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL istraživača", + "person.page.orcid.sync-queue.send": "Sinhronizacija sa ORCID registrom", + "person.page.orcid.sync-queue.send.unauthorized-error.title": "Pristupanje ORCID-u nije uspelo zbog nedostajućih ovlašćenja.", + "person.page.orcid.sync-queue.send.unauthorized-error.content": "Kliknite ovde da ponovo dodelite potrebne dozvole. Ako se problem nastavi, kontaktirajte administratora", + "person.page.orcid.sync-queue.send.bad-request-error": "Slanje ORCID-u nije uspelo jer resurs poslat u ORCID registar nije važeći", + "person.page.orcid.sync-queue.send.error": "Slanje ORCID-u nije uspelo", + "person.page.orcid.sync-queue.send.conflict-error": "Slanje ORCID-u nije uspelo jer se resurs već nalazi u ORCID registru", + "person.page.orcid.sync-queue.send.not-found-warning": "Resurs se više ne nalazi u ORCID registru.", + "person.page.orcid.sync-queue.send.success": "Slanje ORCID-u je uspešno završeno", + "person.page.orcid.sync-queue.send.validation-error": "Podaci koje želite da sinhronizujete sa ORCID-om nisu ispravni", + "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "Valuta je obavezna", + "person.page.orcid.sync-queue.send.validation-error.external-id.required": "Resurs koji se šalje zahteva najmanje jedan identifikator", + "person.page.orcid.sync-queue.send.validation-error.title.required": "Naslov je obavezan", + "person.page.orcid.sync-queue.send.validation-error.type.required": "Dc.type je obavezan", + "person.page.orcid.sync-queue.send.validation-error.start-date.required": "Datum početka je obavezan", + "person.page.orcid.sync-queue.send.validation-error.funder.required": "Finansijer je neophodan", + "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Nevažeće 2 cifre ISO 3166 zemlja", + "person.page.orcid.sync-queue.send.validation-error.organization.required": "Potrebna je organizacija", + "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Naziv organizacije je obavezan", + "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "Datum objavljivanja mora biti godinu dana posle 1900. godine", + "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Organizacija zahteva adresu", + "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "Adresa organizacije koja se šalje zahteva grad", + "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "Adresa organizacije koja se šalje zahteva važeće 2 cifre ISO 3166 zemlje", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "Potreban je identifikator za nedvosmislenost organizacija. Podržani ID-ovi su GRID, Ringgold, Legal Entity identifiers (LEIs) i Crossref Funder Registry identifiers", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "Identifikatori organizacije zahtevaju vrednost", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "Identifikatorima organizacije je potreban izvor", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "Izvor jednog od identifikatora organizacije je nevažeći. Podržani izvori su RINGGOLD, GRID, LEI i FUNDREF", + "person.page.orcid.synchronization-mode": "Način sinhronizacije", + "person.page.orcid.synchronization-mode.batch": "Batch", + "person.page.orcid.synchronization-mode.label": "Način sinhronizacije", + "person.page.orcid.synchronization-mode-message": "Molimo izaberite kako želite da se sinhronizacija sa ORCID-om odvija. Opcije uključuju \"Manual\" (morate ručno da pošaljete svoje podatke ORCID-u) ili \"Batch\" (sistem će poslati vaše podatke ORCID-u preko planirane skripte).", + "person.page.orcid.synchronization-mode-funding-message": "Izaberite da li želite da pošaljete vaše povezane entitete projekta na listu informacija o finansiranju vašeg ORCID zapisa.", + "person.page.orcid.synchronization-mode-publication-message": "Izaberite da li želite da pošaljete vaše povezane entitete publikacije na listu radova vašeg ORCID zapisa.", + "person.page.orcid.synchronization-mode-profile-message": "Izaberite da li želite da pošaljete vaše biografske podatke ili lične identifikatore u vaš ORCID zapis.", + "person.page.orcid.synchronization-settings-update.success": "Podešavanja sinhronizacije su uspešno ažurirana", + "person.page.orcid.synchronization-settings-update.error": "Ažuriranje podešavanja sinhronizacije nije uspelo", + "person.page.orcid.synchronization-mode.manual": "Uputstvo", + "person.page.orcid.scope.authenticate": "Preuzmite svoj ORCID iD", + "person.page.orcid.scope.read-limited": "Čitajte svoje informacije uz vidljivost podešenu na Pouzdane strane", + "person.page.orcid.scope.activities-update": "Dodajte/ažurirajte vaše istraživačke aktivnosti", + "person.page.orcid.scope.person-update": "Dodajte/ažurirajte druge informacije o sebi", + "person.page.orcid.unlink.success": "Prekid veze između profila i ORCID registra je bio uspešan", + "person.page.orcid.unlink.error": "Došlo je do greške prilikom prekida veze između profila i ORCID registra. Pokušajte ponovo", + "person.orcid.sync.setting": "ORCID podešavanja sinhronizacije", + "person.orcid.registry.queue": "ORCID Registry Queue", + "person.orcid.registry.auth": "ORCID ovlašćenja", + "home.recent-submissions.head": "Nedavni podnesci", + "listable-notification-object.default-message": "Nije moguće preuzeti ovaj objekat", + "system-wide-alert-banner.retrieval.error": "Nešto nije u redu pri preuzimanju banera sistemskog upozorenja", + "system-wide-alert-banner.countdown.prefix": "U", + "system-wide-alert-banner.countdown.days": "{{days}} dan(i),", + "system-wide-alert-banner.countdown.hours": "{{hours}} sat(i) i", + "system-wide-alert-banner.countdown.minutes": "{{minutes}} minut(i):", + "menu.section.system-wide-alert": "Sistemsko upozorenje", + "system-wide-alert.form.header": "Sistemsko upozorenje", + "system-wide-alert-form.retrieval.error": "Nešto nije u redu pri preuzimanju sistemskog upozorenja", + "system-wide-alert.form.cancel": "Otkazati", + "system-wide-alert.form.save": "Sačuvati", + "system-wide-alert.form.label.active": "AKTIVNO", + "system-wide-alert.form.label.inactive": "NEAKTIVNO", + "system-wide-alert.form.error.message": "Sistemsko upozorenje mora sadržati poruku", + "system-wide-alert.form.label.message": "Poruka upozorenja", + "system-wide-alert.form.label.countdownTo.enable": "Uključite vremensko odbrojavanje", + "system-wide-alert.form.label.countdownTo.hint": "Savet: Podesite tajmer za odbrojavanje. Kada je uključen, datum se može podesiti u budućnosti i baner sistemskog upozorenja će izvršiti odbrojavanje do postavljenog datuma. Kada tajmer završi, nestaće iz upozorenja. Server NEĆE biti automatski zaustavljen.", + "system-wide-alert.form.label.preview": "Pregled sistemskog upozorenja", + "system-wide-alert.form.update.success": "Sistemsko upozorenje je uspešno ažurirano", + "system-wide-alert.form.update.error": "Nešto nije u redu sa ažuriranjem sistemskog upozorenja", + "system-wide-alert.form.create.success": "Sistemsko upozorenje je uspešno kreirano", + "system-wide-alert.form.create.error": "Nešto nije u redu sa kreiranjem sistemskog upozorenja", + "admin.system-wide-alert.breadcrumbs": "Sistemska upozorenja", + "admin.system-wide-alert.title": "Sistemska upozorenja", + "item-access-control-title": "Ovaj obrazac vam omogućava da izvršite promene uslova pristupa metapodacima stavke ili njenim bitstream-ovima.", + "collection-access-control-title": "Ovaj obrazac vam omogućava da izvršite izmene uslova pristupa svim stavkama ove kolekcije. Promene mogu da se izvrše ili na svim metapodacima stavke ili na celom sadržaju (bitstream-ova).", + "community-access-control-title": "Ovaj obrazac vam omogućava da izvršite promene uslova pristupa svim stavkama bilo koje kolekcije u ovoj zajednici. Promene mogu da se izvrše ili na svim metapodacima stavke ili na celom sadržaju (bitstream-ova).", + "access-control-item-header-toggle": "Metapodaci stavke", + "access-control-bitstream-header-toggle": "Bitstream-ovi", + "access-control-mode": "Način", + "access-control-access-conditions": "Uslovi pristupa", + "access-control-no-access-conditions-warning-message": "Trenutno nisu navedeni uslovi pristupa ispod. Ako se izvrši, to će zameniti trenutne uslove pristupa podrazumevanim uslovima pristupa nasleđenim iz vlasničke kolekcije.", + "access-control-replace-all": "Zamena uslova pristupa", + "access-control-add-to-existing": "Dodati postojećim", + "access-control-limit-to-specific": "Ograničite promene na određene bitstream-ove", + "access-control-process-all-bitstreams": "Ažurirajte sve bitstream-ove u stavci", + "access-control-bitstreams-selected": "izabrani bitstream-ovi", + "access-control-cancel": "Otkazati", + "access-control-execute": "Izvršiti", + "access-control-add-more": "Dodati još", + "access-control-select-bitstreams-modal.title": "Izaberite bitstream-ove", + "access-control-select-bitstreams-modal.no-items": "Nema stavki za prikaz.", + "access-control-select-bitstreams-modal.close": "Zatvoriti", + "access-control-option-label": "Vrsta uslova pristupa", + "access-control-option-note": "Izaberite uslov pristupa koji ćete primeniti na izabrane objekte.", + "access-control-option-start-date": "Pristup odobren od", + "access-control-option-start-date-note": "Izaberite datum od kojeg se primenjuje odgovarajući uslov pristupa", + "access-control-option-end-date": "Pristup odobren do", + "access-control-option-end-date-note": "Izaberite datum do kojeg se primenjuje odgovarajući uslov pristupa", +} diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index a6e9e092e46..523ccf4f504 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -229,6 +229,7 @@ export class DefaultAppConfig implements AppConfig { { code: 'pl', label: 'Polski', active: true }, { code: 'pt-PT', label: 'Português', active: true }, { code: 'pt-BR', label: 'Português do Brasil', active: true }, + { code: 'sr-lat', label: 'Srpski (lat)', active: true}, { code: 'fi', label: 'Suomi', active: true }, { code: 'sv', label: 'Svenska', active: true }, { code: 'tr', label: 'Türkçe', active: true }, From f53c77be8ec9d16ddd138fa362ca7811088370b6 Mon Sep 17 00:00:00 2001 From: AndreaBarbasso Date: Tue, 26 Sep 2023 09:22:30 +0200 Subject: [PATCH 073/196] Fix missing or wrong Italian translations (#2518) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [DURACOM-184] fix missing or wrong Italian translations --------- Co-authored-by: Andrea Barbasso <´andrea.barbasso@4science.com´> --- src/assets/i18n/it.json5 | 1405 ++++++++++++-------------------------- 1 file changed, 451 insertions(+), 954 deletions(-) diff --git a/src/assets/i18n/it.json5 b/src/assets/i18n/it.json5 index 4fc07cebdf7..7f410ce0b17 100644 --- a/src/assets/i18n/it.json5 +++ b/src/assets/i18n/it.json5 @@ -195,7 +195,6 @@ // "admin.registries.bitstream-formats.table.name": "Name", "admin.registries.bitstream-formats.table.name": "Nome", // "admin.registries.bitstream-formats.table.id": "ID", - // TODO New key - Add a translation "admin.registries.bitstream-formats.table.id": "ID", // "admin.registries.bitstream-formats.table.return": "Back", @@ -277,7 +276,6 @@ // "admin.registries.schema.fields.table.field": "Field", "admin.registries.schema.fields.table.field": "Campo", // "admin.registries.schema.fields.table.id": "ID", - // TODO New key - Add a translation "admin.registries.schema.fields.table.id": "ID", // "admin.registries.schema.fields.table.scopenote": "Scope Note", @@ -501,7 +499,6 @@ "admin.access-control.groups.addGroup.breadcrumbs": "Nuovo Gruppo", // "admin.access-control.groups.head": "Groups", - // TODO Source message changed - Revise the translation "admin.access-control.groups.head": "Gruppi/Ruoli", // "admin.access-control.groups.button.add": "Add group", @@ -538,8 +535,7 @@ "admin.access-control.groups.table.edit.buttons.edit": "Modifica \"{{name}}\"", // "admin.access-control.groups.table.edit.buttons.remove": "Delete \"{{name}}\"", - // TODO New key - Add a translation - "admin.access-control.groups.table.edit.buttons.remove": "Delete \"{{name}}\"", + "admin.access-control.groups.table.edit.buttons.remove": "Elimina \"{{name}}\"", // "admin.access-control.groups.no-items": "No groups found with this in their name or this as UUID", "admin.access-control.groups.no-items": "Nessun gruppo trovato con questo nel loro nome o questo come UUID", @@ -751,16 +747,13 @@ "admin.access-control.groups.form.return": "Indietro", // "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.", - // TODO New key - Add a translation - "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": "In questa pagina è possibile modificare le proprietà e i membri di un gruppo. Nella sezione in alto, è possibile modificare il nome e la descrizione del gruppo, a meno che non si tratti di un gruppo di amministratori di una collection o una community. In quel caso il nome e la descrizione del gruppo sono generati automaticamente e non possono essere modificati. Nelle sezioni successive è possibile modificare l'appartenenza al gruppo. Per maggiori dettagli, vedere [la wiki](https://wiki.lyrasis.org/display/DSDOC7x/Create+o+gestire+un+gruppo+utente)", // "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "To add or remove an EPerson to/from this group, either click the 'Browse All' button or use the search bar below to search for users (use the dropdown to the left of the search bar to choose whether to search by metadata or by email). Then click the plus icon for each user you wish to add in the list below, or the trash can icon for each user you wish to remove. The list below may have several pages: use the page controls below the list to navigate to the next pages. Once you are ready, save your changes by clicking the 'Save' button in the top section.", - // TODO New key - Add a translation - "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "To add or remove an EPerson to/from this group, either click the 'Browse All' button or use the search bar below to search for users (use the dropdown to the left of the search bar to choose whether to search by metadata or by email). Then click the plus icon for each user you wish to add in the list below, or the trash can icon for each user you wish to remove. The list below may have several pages: use the page controls below the list to navigate to the next pages. Once you are ready, save your changes by clicking the 'Save' button in the top section.", + "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Per aggiungere o rimuovere un EPerson a/da questo gruppo, cliccare sul pulsante 'Sfoglia tutti' o utilizzare la barra di ricerca in basso per cercare gli utenti (utilizzare il menu a tendina a sinistra della barra di ricerca per selezionare la ricerca per metadati o per e-mail). Cliccare quindi sull'icona + per ogni utente che si desidera aggiungere nell'elenco sottostante o sull'icona del cestino per ogni utente che si desidera rimuovere. L'elenco può avere diverse pagine: utilizzare i controlli di pagina in basso per spostarsi alle pagine successive. Per salvare le modifiche, cliccare sul pulsante 'Salvare' nella sezione in alto.", // "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "To add or remove a Subgroup to/from this group, either click the 'Browse All' button or use the search bar below to search for users. Then click the plus icon for each user you wish to add in the list below, or the trash can icon for each user you wish to remove. The list below may have several pages: use the page controls below the list to navigate to the next pages. Once you are ready, save your changes by clicking the 'Save' button in the top section.", - // TODO New key - Add a translation - "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "To add or remove a Subgroup to/from this group, either click the 'Browse All' button or use the search bar below to search for users. Then click the plus icon for each user you wish to add in the list below, or the trash can icon for each user you wish to remove. The list below may have several pages: use the page controls below the list to navigate to the next pages. Once you are ready, save your changes by clicking the 'Save' button in the top section.", + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Per aggiungere o rimuovere un Sottogruppo a/da questo gruppo, cliccare sul pulsante 'Sfoglia tutti' o utilizzare la barra di ricerca in basso per cercare gli utenti. Cliccare quindi sull'icona + per ogni utente che si desidera aggiungere nell'elenco sottostante o sull'icona del cestino per ogni utente che si desidera rimuovere. L'elenco può avere diverse pagine: utilizzare i controlli di pagina in basso per spostarsi alle pagine successive. Per salvare le modifiche, cliccare sul pulsante 'Salva' nella sezione in alto.", // "admin.search.breadcrumbs": "Administrative Search", "admin.search.breadcrumbs": "Ricerca amministrativa", @@ -811,7 +804,6 @@ "admin.workflow.item.workflow": "Flusso di lavoro", // "admin.workflow.item.workspace": "Workspace", - // TODO New key - Add a translation "admin.workflow.item.workspace": "Workspace", // "admin.workflow.item.delete": "Delete", @@ -821,12 +813,10 @@ "admin.workflow.item.send-back": "Rinviare", // "admin.workflow.item.policies": "Policies", - // TODO New key - Add a translation - "admin.workflow.item.policies": "Policies", + "admin.workflow.item.policies": "Policy", // "admin.workflow.item.supervision": "Supervision", - // TODO New key - Add a translation - "admin.workflow.item.supervision": "Supervision", + "admin.workflow.item.supervision": "Supervisione", @@ -834,43 +824,37 @@ "admin.metadata-import.breadcrumbs": "Importare metadati", // "admin.batch-import.breadcrumbs": "Import Batch", - // TODO New key - Add a translation - "admin.batch-import.breadcrumbs": "Import Batch", + "admin.batch-import.breadcrumbs": "Batch Import", // "admin.metadata-import.title": "Import Metadata", "admin.metadata-import.title": "Importare metadati", // "admin.batch-import.title": "Import Batch", - // TODO New key - Add a translation - "admin.batch-import.title": "Import Batch", + "admin.batch-import.title": "Batch Import", // "admin.metadata-import.page.header": "Import Metadata", "admin.metadata-import.page.header": "Importare metadati", // "admin.batch-import.page.header": "Import Batch", - // TODO New key - Add a translation - "admin.batch-import.page.header": "Import Batch", + "admin.batch-import.page.header": "Batch Import", // "admin.metadata-import.page.help": "You can drop or browse CSV files that contain batch metadata operations on files here", - "admin.metadata-import.page.help": "È possibile eliminare o sfogliare i file CSV che contengono operazioni di metadati batch sui file qui", + "admin.metadata-import.page.help": "È possibile rilasciare o sfogliare i file CSV che contengono operazioni di metadati batch sui file qui", // "admin.batch-import.page.help": "Select the Collection to import into. Then, drop or browse to a Simple Archive Format (SAF) zip file that includes the Items to import", - // TODO New key - Add a translation - "admin.batch-import.page.help": "Select the Collection to import into. Then, drop or browse to a Simple Archive Format (SAF) zip file that includes the Items to import", + "admin.batch-import.page.help": "Selezionare la Collection in cui effettuare l'import. Quindi, rilasciare o sfogliare un file zip Simple Archive Format (SAF) che include gli elementi da importare", // "admin.metadata-import.page.dropMsg": "Drop a metadata CSV to import", "admin.metadata-import.page.dropMsg": "Rilasciare un CSV di metadati da importare", // "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", - // TODO New key - Add a translation - "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", + "admin.batch-import.page.dropMsg": "Rilasciare un batch ZIP da importare", // "admin.metadata-import.page.dropMsgReplace": "Drop to replace the metadata CSV to import", - "admin.metadata-import.page.dropMsgReplace": "Rilascia per sostituire i metadati CSV da importare", + "admin.metadata-import.page.dropMsgReplace": "Rilasciare per sostituire i metadati CSV da importare", // "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", - // TODO New key - Add a translation - "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", + "admin.batch-import.page.dropMsgReplace": "Rilasciare per sostituire il batch ZIP da importare", // "admin.metadata-import.page.button.return": "Back", "admin.metadata-import.page.button.return": "Indietro", @@ -879,15 +863,13 @@ "admin.metadata-import.page.button.proceed": "Procedere", // "admin.metadata-import.page.button.select-collection": "Select Collection", - // TODO New key - Add a translation - "admin.metadata-import.page.button.select-collection": "Select Collection", + "admin.metadata-import.page.button.select-collection": "Selezionare una Collection", // "admin.metadata-import.page.error.addFile": "Select file first!", "admin.metadata-import.page.error.addFile": "Seleziona prima il file!", // "admin.batch-import.page.error.addFile": "Select Zip file first!", - // TODO New key - Add a translation - "admin.batch-import.page.error.addFile": "Select Zip file first!", + "admin.batch-import.page.error.addFile": "Seleziona prima il file ZIP!", // "admin.metadata-import.page.validateOnly": "Validate Only", "admin.metadata-import.page.validateOnly": "Solo Validazione", @@ -896,138 +878,105 @@ "admin.metadata-import.page.validateOnly.hint": "Una volta selezionato, il CSV caricato sarà validato. Riceverai un report delle modifiche rilevate, ma nessuna modifica verrà salvata.", // "advanced-workflow-action.rating.form.rating.label": "Rating", - // TODO New key - Add a translation - "advanced-workflow-action.rating.form.rating.label": "Rating", + "advanced-workflow-action.rating.form.rating.label": "Valutazione", // "advanced-workflow-action.rating.form.rating.error": "You must rate the item", - // TODO New key - Add a translation - "advanced-workflow-action.rating.form.rating.error": "You must rate the item", + "advanced-workflow-action.rating.form.rating.error": "È necessario valutare l'item", // "advanced-workflow-action.rating.form.review.label": "Review", - // TODO New key - Add a translation - "advanced-workflow-action.rating.form.review.label": "Review", + "advanced-workflow-action.rating.form.review.label": "Revisione", // "advanced-workflow-action.rating.form.review.error": "You must enter a review to submit this rating", - // TODO New key - Add a translation - "advanced-workflow-action.rating.form.review.error": "You must enter a review to submit this rating", + "advanced-workflow-action.rating.form.review.error": "Per inviare questa valutazione è necessario inserire una revisione", // "advanced-workflow-action.rating.description": "Please select a rating below", - // TODO New key - Add a translation - "advanced-workflow-action.rating.description": "Please select a rating below", + "advanced-workflow-action.rating.description": "Selezionare una valutazione qui sotto", // "advanced-workflow-action.rating.description-requiredDescription": "Please select a rating below and also add a review", - // TODO New key - Add a translation - "advanced-workflow-action.rating.description-requiredDescription": "Please select a rating below and also add a review", + "advanced-workflow-action.rating.description-requiredDescription": "Selezionare una valutazione qui sotto e aggiungere anche una revisione", // "advanced-workflow-action.select-reviewer.description-single": "Please select a single reviewer below before submitting", - // TODO New key - Add a translation - "advanced-workflow-action.select-reviewer.description-single": "Please select a single reviewer below before submitting", + "advanced-workflow-action.select-reviewer.description-single": "Selezionare un solo revisione prima di procedere con l'inserimento", // "advanced-workflow-action.select-reviewer.description-multiple": "Please select one or more reviewers below before submitting", - // TODO New key - Add a translation - "advanced-workflow-action.select-reviewer.description-multiple": "Please select one or more reviewers below before submitting", + "advanced-workflow-action.select-reviewer.description-multiple": "Selezionare uno o più revisori prima di procedere con l'inserimento", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", - // TODO New key - Add a translation "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Add EPeople", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Add EPeople", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Aggiungi EPeople", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Browse All", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Browse All", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Sfoglia tutto", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Current Members", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Current Members", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Membri attuali", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadata", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadata", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadati", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "E-mail (exact)", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "E-mail (exact)", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "E-mail (esatta)", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Search", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Search", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Ricerca", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", - // TODO New key - Add a translation "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Name", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Name", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Nome", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identity", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identity", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identità", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Email", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Email", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "E-mail", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", - // TODO New key - Add a translation "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Remove / Add", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Remove / Add", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Rimuovi / Aggiungi", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remove member with name \"{{name}}\"", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remove member with name \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Rimuovi membro con il nome \"{{name}}\"", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Successfully added member: \"{{name}}\"", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Successfully added member: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Membro inserito con successo: \"{{name}}\"", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Failed to add member: \"{{name}}\"", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Failed to add member: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Impossibile aggiungere il membro: \"{{name}}\"", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Successfully deleted member: \"{{name}}\"", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Successfully deleted member: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Membro eliminato con successo: \"{{name}}\"", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Failed to delete member: \"{{name}}\"", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Failed to delete member: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Impossibile eliminare il membro: \"{{name}}\"", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Add member with name \"{{name}}\"", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Add member with name \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Aggiungi membro con il nome \"{{name}}\"", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "No current active group, submit a name first.", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "No current active group, submit a name first.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Nessun gruppo attivo al momento, inserire prima un nome.", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "No members in group yet, search and add.", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "No members in group yet, search and add.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "Questo gruppo è vuoto, cercare e aggiungere membri.", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "No EPeople found in that search", - // TODO New key - Add a translation - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "No EPeople found in that search", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "La ricerca non ha trovato EPeople", // "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "No reviewer selected.", - // TODO New key - Add a translation - "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "No reviewer selected.", + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Nessun revisore selezionato.", // "admin.batch-import.page.validateOnly.hint": "When selected, the uploaded ZIP will be validated. You will receive a report of detected changes, but no changes will be saved.", - // TODO New key - Add a translation - "admin.batch-import.page.validateOnly.hint": "When selected, the uploaded ZIP will be validated. You will receive a report of detected changes, but no changes will be saved.", + "admin.batch-import.page.validateOnly.hint": "Una volta selezionato, il file ZIP caricato verrà convalidato. Si riceverà un rapporto sulle modifiche rilevate, ma non verrà salvata alcuna modifica.", // "admin.batch-import.page.remove": "remove", - // TODO New key - Add a translation - "admin.batch-import.page.remove": "remove", + "admin.batch-import.page.remove": "rimuovere", // "auth.errors.invalid-user": "Invalid email address or password.", "auth.errors.invalid-user": "Indirizzo e-mail o password non validi.", @@ -1043,8 +992,7 @@ // "bitstream.download.page": "Now downloading {{bitstream}}..." , "bitstream.download.page": "Sto scaricando {{bitstream}}...", - // "bitstream.download.page.back": "Back" , - // TODO Source message changed - Revise the translation + // "bitstream.download.page.back": "Back", "bitstream.download.page.back": "Indietro", @@ -1073,7 +1021,7 @@ "bitstream.edit.form.embargo.label": "Embargo fino a data specifica", // "bitstream.edit.form.fileName.hint": "Change the filename for the bitstream. Note that this will change the display bitstream URL, but old links will still resolve as long as the sequence ID does not change.", - "bitstream.edit.form.fileName.hint": "Modificare il nome del file per il bitstream. Si noti che questo cambierà il display bitstream URL , i vecchi collegamenti verranno comunque risolti finché il sequence ID non cambierà .", + "bitstream.edit.form.fileName.hint": "Modificare il nome del file per il bitstream. Si noti che questo cambierà il display bitstream URL, i vecchi collegamenti verranno comunque risolti finché il sequence ID non cambierà.", // "bitstream.edit.form.fileName.label": "Filename", "bitstream.edit.form.fileName.label": "Filename", @@ -1246,8 +1194,7 @@ "pagination.next.button.disabled.tooltip": "Non ci sono ulteriori pagine di risultati", // "browse.startsWith": ", starting with {{ startsWith }}", - // TODO New key - Add a translation - "browse.startsWith": ", starting with {{ startsWith }}", + "browse.startsWith": ", inizia per {{ startsWith }}", // "browse.startsWith.choose_start": "(Choose start)", "browse.startsWith.choose_start": "(Scegli start)", @@ -1323,8 +1270,7 @@ // "search.browse.item-back": "Back to Results", - // TODO New key - Add a translation - "search.browse.item-back": "Back to Results", + "search.browse.item-back": "Torna ai risultati", // "chips.remove": "Remove chip", @@ -1332,23 +1278,20 @@ // "claimed-approved-search-result-list-element.title": "Approved", - // TODO New key - Add a translation - "claimed-approved-search-result-list-element.title": "Approved", + "claimed-approved-search-result-list-element.title": "Approvato", // "claimed-declined-search-result-list-element.title": "Rejected, sent back to submitter", - // TODO New key - Add a translation - "claimed-declined-search-result-list-element.title": "Rejected, sent back to submitter", + "claimed-declined-search-result-list-element.title": "Respinto, rinviato al submitter", // "claimed-declined-task-search-result-list-element.title": "Declined, sent back to Review Manager's workflow", - // TODO New key - Add a translation - "claimed-declined-task-search-result-list-element.title": "Declined, sent back to Review Manager's workflow", + "claimed-declined-task-search-result-list-element.title": "Rifiutato, rinviato al flusso di lavoro del Responsabile delle revisioni", // "collection.create.head": "Create a Collection", "collection.create.head": "Creare una collection", // "collection.create.notifications.success": "Successfully created the Collection", - "collection.create.notifications.success": "Creata con successo la collection", + "collection.create.notifications.success": "Collection creata con successo", // "collection.create.sub-head": "Create a Collection for Community {{ parent }}", "collection.create.sub-head": "Creare una collection per la Community {{ parent }}", @@ -1478,8 +1421,6 @@ // "collection.edit.logo.upload": "Drop a Collection Logo to upload", "collection.edit.logo.upload": "Rilascia un logo della collection da caricare", - - // "collection.edit.notifications.success": "Successfully edited the Collection", "collection.edit.notifications.success": "Modificata correttamente la collection", @@ -1507,8 +1448,7 @@ "collection.edit.item.authorizations.load-more-button": "Carica più risorse", // "collection.edit.item.authorizations.show-bitstreams-button": "Show bitstream policies for bundle", - // TODO New key - Add a translation - "collection.edit.item.authorizations.show-bitstreams-button": "Show bitstream policies for bundle", + "collection.edit.item.authorizations.show-bitstreams-button": "Mostra le policy del bitstream per il bundle", // "collection.edit.tabs.metadata.head": "Edit Metadata", "collection.edit.tabs.metadata.head": "Modifica metadati", @@ -1559,8 +1499,7 @@ "collection.edit.tabs.source.notifications.discarded.content": "Le modifiche sono state annullate. Per ripristinarle, fai clic sul pulsante \"Annulla\"", // "collection.edit.tabs.source.notifications.discarded.title": "Changes discarded", - // TODO Source message changed - Revise the translation - "collection.edit.tabs.source.notifications.discarded.title": "Modifiche eliminate", + "collection.edit.tabs.source.notifications.discarded.title": "Modifiche annullate", // "collection.edit.tabs.source.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", "collection.edit.tabs.source.notifications.invalid.content": "Le modifiche non sono state salvate. Assicurati che tutti i campi siano validi prima di salvare.", @@ -1718,16 +1657,12 @@ // "collection.source.controls.reset.running": "Resetting and reimporting...", "collection.source.controls.reset.running": "Reimpostazione e reimportazione...", // "collection.source.controls.harvest.status": "Harvest status:", - // TODO New key - Add a translation - "collection.source.controls.harvest.status": "Harvest status:", + "collection.source.controls.harvest.status": "Stato dell'harvest:", // "collection.source.controls.harvest.start": "Harvest start time:", - // TODO New key - Add a translation - "collection.source.controls.harvest.start": "Harvest start time:", + "collection.source.controls.harvest.start": "Ora di inizio dell'harvest:", // "collection.source.controls.harvest.last": "Last time harvested:", - // TODO New key - Add a translation - "collection.source.controls.harvest.last": "Last time harvested:", + "collection.source.controls.harvest.last": "Ulimo harvest effettuato:", // "collection.source.controls.harvest.message": "Harvest info:", - // TODO New key - Add a translation "collection.source.controls.harvest.message": "Harvest info:", // "collection.source.controls.harvest.no-information": "N/A", "collection.source.controls.harvest.no-information": "N/D", @@ -1954,12 +1889,10 @@ // "comcol-role.edit.scorereviewers.name": "Score Reviewers", - // TODO New key - Add a translation - "comcol-role.edit.scorereviewers.name": "Score Reviewers", + "comcol-role.edit.scorereviewers.name": "Valutatori", // "comcol-role.edit.scorereviewers.description": "Reviewers are able to give a score to incoming submissions, this will define whether the submission will be rejected or not.", - // TODO New key - Add a translation - "comcol-role.edit.scorereviewers.description": "Reviewers are able to give a score to incoming submissions, this will define whether the submission will be rejected or not.", + "comcol-role.edit.scorereviewers.description": "I valutatori possono assegnare un punteggio ai contributi in entrata, questo definirà se il contributo verrà rifiutato o meno.", @@ -2026,12 +1959,10 @@ "cookies.consent.app.required.title": "(sempre obbligatorio)", // "cookies.consent.app.disable-all.description": "Use this switch to enable or disable all services.", - // TODO New key - Add a translation - "cookies.consent.app.disable-all.description": "Use this switch to enable or disable all services.", + "cookies.consent.app.disable-all.description": "Utilizzare questo interruttore per abilitare o disabilitare tutti i servizi.", // "cookies.consent.app.disable-all.title": "Enable or disable all services", - // TODO New key - Add a translation - "cookies.consent.app.disable-all.title": "Enable or disable all services", + "cookies.consent.app.disable-all.title": "Abilitare o disabilitare tutti i servizi", // "cookies.consent.update": "There were changes since your last visit, please update your consent.", "cookies.consent.update": "Ci sono stati dei cambiamenti dal tuo ultimo accesso, aggiorna il tuo consenso.", @@ -2043,23 +1974,19 @@ "cookies.consent.decline": "Declinare", // "cookies.consent.ok": "That's ok", - // TODO New key - Add a translation - "cookies.consent.ok": "That's ok", + "cookies.consent.ok": "Accetta", // "cookies.consent.save": "Save", - // TODO New key - Add a translation - "cookies.consent.save": "Save", + "cookies.consent.save": "Salvare", // "cookies.consent.content-notice.title": "Cookie Consent", - // TODO New key - Add a translation - "cookies.consent.content-notice.title": "Cookie Consent", + "cookies.consent.content-notice.title": "Consenso ai cookie", // "cookies.consent.content-notice.description": "We collect and process your personal information for the following purposes: Authentication, Preferences, Acknowledgement and Statistics.
To learn more, please read our {privacyPolicy}.", - "cookies.consent.content-notice.description": "Raccogliamo e processiamo le tue informazioni personali per i seguenti scopi: Autenticazione, Preferenze, Accettazione e Statistiche.
Per saperne di più, leggi la nostra {privacyPolicy}.", + "cookies.consent.content-notice.description": "Raccogliamo ed elaboriamo le tue informazioni personali per i seguenti scopi: Autenticazione, Preferenze, Accettazione e Statistiche.
Per saperne di più, leggi la nostra {privacyPolicy}.", // "cookies.consent.content-notice.description.no-privacy": "We collect and process your personal information for the following purposes: Authentication, Preferences, Acknowledgement and Statistics.", - // TODO New key - Add a translation - "cookies.consent.content-notice.description.no-privacy": "We collect and process your personal information for the following purposes: Authentication, Preferences, Acknowledgement and Statistics.", + "cookies.consent.content-notice.description.no-privacy": "Raccogliamo ed elaboriamo le tue informazioni personali per i seguenti scopi: Autenticazione, Preferenze, Accettazione e Statistiche.", // "cookies.consent.content-notice.learnMore": "Customize", "cookies.consent.content-notice.learnMore": "Personalizza", @@ -2077,12 +2004,10 @@ "cookies.consent.content-modal.title": "Informazioni che raccogliamo", // "cookies.consent.content-modal.services": "services", - // TODO New key - Add a translation - "cookies.consent.content-modal.services": "services", + "cookies.consent.content-modal.services": "servizi", // "cookies.consent.content-modal.service": "service", - // TODO New key - Add a translation - "cookies.consent.content-modal.service": "service", + "cookies.consent.content-modal.service": "servizio", // "cookies.consent.app.title.authentication": "Authentication", "cookies.consent.app.title.authentication": "Autenticazione", @@ -2116,12 +2041,10 @@ // "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", - // TODO New key - Add a translation "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", // "cookies.consent.app.description.google-recaptcha": "We use google reCAPTCHA service during registration and password recovery", - // TODO New key - Add a translation - "cookies.consent.app.description.google-recaptcha": "We use google reCAPTCHA service during registration and password recovery", + "cookies.consent.app.description.google-recaptcha": "Utilizziamo il servizio Google reCAPTCHA nelle fasi di registrazione e recupero password", // "cookies.consent.purpose.functional": "Functional", @@ -2131,18 +2054,15 @@ "cookies.consent.purpose.statistical": "Statistico", // "cookies.consent.purpose.registration-password-recovery": "Registration and Password recovery", - // TODO New key - Add a translation - "cookies.consent.purpose.registration-password-recovery": "Registration and Password recovery", + "cookies.consent.purpose.registration-password-recovery": "Registrazione e recupero password", // "cookies.consent.purpose.sharing": "Sharing", "cookies.consent.purpose.sharing": "Condivisione", // "curation-task.task.citationpage.label": "Generate Citation Page", - // TODO New key - Add a translation - "curation-task.task.citationpage.label": "Generate Citation Page", + "curation-task.task.citationpage.label": "Genera una pagina di citazioni", // "curation-task.task.checklinks.label": "Check Links in Metadata", - // TODO Source message changed - Revise the translation "curation-task.task.checklinks.label": "Controllare i collegamenti nei metadati", // "curation-task.task.noop.label": "NOOP", @@ -2160,9 +2080,8 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Scansione antivirus", - // "curation-task.task.registerdoi.label": "Register DOI", - // TODO New key - Add a translation - "curation-task.task.registerdoi.label": "Register DOI", + // "curation-task.task.register-doi.label": "Register DOI", + "curation-task.task.register-doi.label": "Registra DOI", @@ -2230,8 +2149,7 @@ "dso-selector.create.community.head": "Nuova Community", // "dso-selector.create.community.or-divider": "or", - // TODO New key - Add a translation - "dso-selector.create.community.or-divider": "or", + "dso-selector.create.community.or-divider": "oppure", // "dso-selector.create.community.sub-level": "Create a new community in", "dso-selector.create.community.sub-level": "Creare una nuova community in", @@ -2264,12 +2182,10 @@ "dso-selector.export-metadata.dspaceobject.head": "Esportare metadati da", // "dso-selector.export-batch.dspaceobject.head": "Export Batch (ZIP) from", - // TODO New key - Add a translation - "dso-selector.export-batch.dspaceobject.head": "Export Batch (ZIP) from", + "dso-selector.export-batch.dspaceobject.head": "Esporta batch (ZIP) da", // "dso-selector.import-batch.dspaceobject.head": "Import batch from", - // TODO New key - Add a translation - "dso-selector.import-batch.dspaceobject.head": "Import batch from", + "dso-selector.import-batch.dspaceobject.head": "Importa batch da", // "dso-selector.no-results": "No {{ type }} found", "dso-selector.no-results": "Nessun {{ type }} trovato", @@ -2287,8 +2203,7 @@ "dso-selector.set-scope.community.button": "Cerca in tutto DSpace", // "dso-selector.set-scope.community.or-divider": "or", - // TODO New key - Add a translation - "dso-selector.set-scope.community.or-divider": "or", + "dso-selector.set-scope.community.or-divider": "oppure", // "dso-selector.set-scope.community.input-header": "Search for a community or collection", "dso-selector.set-scope.community.input-header": "Cercare una community o una collection", @@ -2306,60 +2221,46 @@ "dso-selector.claim.item.create-from-scratch": "Crea uno nuovo profilo", // "dso-selector.results-could-not-be-retrieved": "Something went wrong, please refresh again ↻", - // TODO New key - Add a translation - "dso-selector.results-could-not-be-retrieved": "Something went wrong, please refresh again ↻", + "dso-selector.results-could-not-be-retrieved": "Qualcosa è andato storto, aggiorna di nuovo ↻", // "supervision-group-selector.header": "Supervision Group Selector", - // TODO New key - Add a translation - "supervision-group-selector.header": "Supervision Group Selector", + "supervision-group-selector.header": "Selezione del gruppo di supervisione", // "supervision-group-selector.select.type-of-order.label": "Select a type of Order", - // TODO New key - Add a translation - "supervision-group-selector.select.type-of-order.label": "Select a type of Order", + "supervision-group-selector.select.type-of-order.label": "Seleziona un tipo di ordine", // "supervision-group-selector.select.type-of-order.option.none": "NONE", - // TODO New key - Add a translation - "supervision-group-selector.select.type-of-order.option.none": "NONE", + "supervision-group-selector.select.type-of-order.option.none": "NESSUNO", // "supervision-group-selector.select.type-of-order.option.editor": "EDITOR", - // TODO New key - Add a translation - "supervision-group-selector.select.type-of-order.option.editor": "EDITOR", + "supervision-group-selector.select.type-of-order.option.editor": "EDITORE", // "supervision-group-selector.select.type-of-order.option.observer": "OBSERVER", - // TODO New key - Add a translation - "supervision-group-selector.select.type-of-order.option.observer": "OBSERVER", + "supervision-group-selector.select.type-of-order.option.observer": "OSSERVATORE", // "supervision-group-selector.select.group.label": "Select a Group", - // TODO New key - Add a translation - "supervision-group-selector.select.group.label": "Select a Group", + "supervision-group-selector.select.group.label": "Seleziona un gruppo", // "supervision-group-selector.button.cancel": "Cancel", - // TODO New key - Add a translation - "supervision-group-selector.button.cancel": "Cancel", + "supervision-group-selector.button.cancel": "Annulla", // "supervision-group-selector.button.save": "Save", - // TODO New key - Add a translation - "supervision-group-selector.button.save": "Save", + "supervision-group-selector.button.save": "Salva", // "supervision-group-selector.select.type-of-order.error": "Please select a type of order", - // TODO New key - Add a translation - "supervision-group-selector.select.type-of-order.error": "Please select a type of order", + "supervision-group-selector.select.type-of-order.error": "Seleziona un tipo di ordine", // "supervision-group-selector.select.group.error": "Please select a group", - // TODO New key - Add a translation - "supervision-group-selector.select.group.error": "Please select a group", + "supervision-group-selector.select.group.error": "Seleziona un gruppo", // "supervision-group-selector.notification.create.success.title": "Successfully created supervision order for group {{ name }}", - // TODO New key - Add a translation - "supervision-group-selector.notification.create.success.title": "Successfully created supervision order for group {{ name }}", + "supervision-group-selector.notification.create.success.title": "Ordine di supervisione per il gruppo {{ name }} creato con successo", // "supervision-group-selector.notification.create.failure.title": "Error", - // TODO New key - Add a translation - "supervision-group-selector.notification.create.failure.title": "Error", + "supervision-group-selector.notification.create.failure.title": "Errore", // "supervision-group-selector.notification.create.already-existing": "A supervision order already exists on this item for selected group", - // TODO New key - Add a translation - "supervision-group-selector.notification.create.already-existing": "A supervision order already exists on this item for selected group", + "supervision-group-selector.notification.create.already-existing": "Per questo item esiste già un ordine di supervisione per il gruppo selezionato", // "confirmation-modal.export-metadata.header": "Export metadata for {{ dsoName }}", "confirmation-modal.export-metadata.header": "Esportare i metadati per {{ dsoName }}", @@ -2374,20 +2275,16 @@ "confirmation-modal.export-metadata.confirm": "Export", // "confirmation-modal.export-batch.header": "Export batch (ZIP) for {{ dsoName }}", - // TODO New key - Add a translation - "confirmation-modal.export-batch.header": "Export batch (ZIP) for {{ dsoName }}", + "confirmation-modal.export-batch.header": "Esporta batch (ZIP) per {{ dsoName }}", // "confirmation-modal.export-batch.info": "Are you sure you want to export batch (ZIP) for {{ dsoName }}", - // TODO New key - Add a translation - "confirmation-modal.export-batch.info": "Are you sure you want to export batch (ZIP) for {{ dsoName }}", + "confirmation-modal.export-batch.info": "Sei sicuro di voler esportare batch (ZIP) per {{ dsoName }}?", // "confirmation-modal.export-batch.cancel": "Cancel", - // TODO New key - Add a translation - "confirmation-modal.export-batch.cancel": "Cancel", + "confirmation-modal.export-batch.cancel": "Annulla", // "confirmation-modal.export-batch.confirm": "Export", - // TODO New key - Add a translation - "confirmation-modal.export-batch.confirm": "Export", + "confirmation-modal.export-batch.confirm": "Esporta", // "confirmation-modal.delete-eperson.header": "Delete EPerson \"{{ dsoName }}\"", "confirmation-modal.delete-eperson.header": "Elimina EPerson \"{{ dsoName }}\"", @@ -2478,11 +2375,10 @@ "error.top-level-communities": "Errore durante il recupero delle community di primo livello", // "error.validation.license.notgranted": "You must grant this license to complete your submission. If you are unable to grant this license at this time you may save your work and return later or remove the submission.", - "error.validation.license.notgranted": "È necessario concedere questa licenza per completare la submission. Se non sei in grado di concedere questa licenza in questo momento, puoi salvare il tuo lavoro e tornare più tardi o rimuovere la submission.", + "error.validation.license.notgranted": "È necessario concedere questa licenza per completare l'immisione. Se non sei in grado di concedere questa licenza in questo momento, puoi salvare il tuo lavoro e tornare più tardi o rimuovere l'immissione.", // "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", - // TODO New key - Add a translation - "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", + "error.validation.pattern": "L'input è limitato dal pattern in uso: {{ pattern }}.", // "error.validation.filerequired": "The file upload is mandatory", "error.validation.filerequired": "Il caricamento del file è obbligatorio", @@ -2501,7 +2397,6 @@ // "feed.description": "Syndication feed", - // TODO New key - Add a translation "feed.description": "Syndication feed", @@ -2525,12 +2420,10 @@ // "footer.link.privacy-policy": "Privacy policy", "footer.link.privacy-policy": "Informativa sulla privacy", - // "footer.link.end-user-agreement": "End User Agreement", - // TODO Source message changed - Revise the translation + // "footer.link.end-user-agreement":"End User Agreement", "footer.link.end-user-agreement": "Accordo con l'utente finale", - // "footer.link.feedback": "Send Feedback", - // TODO Source message changed - Revise the translation + // "footer.link.feedback":"Send Feedback", "footer.link.feedback": "Invia Feedback", @@ -2539,8 +2432,7 @@ "forgot-email.form.header": "Password dimenticata", // "forgot-email.form.info": "Enter the email address associated with the account.", - // TODO Source message changed - Revise the translation - "forgot-email.form.info": "Accedi a registra un account per iscriverti alle collections, per ricevere aggiornamenti via email e per poter inserire nuovi item in DSpace.", + "forgot-email.form.info": "Inserisci l'indirizzo email associato all'account.", // "forgot-email.form.email": "Email Address *", "forgot-email.form.email": "Indirizzo email *", @@ -2549,31 +2441,25 @@ "forgot-email.form.email.error.required": "Si prega di inserire un indirizzo email", // "forgot-email.form.email.error.not-email-form": "Please fill in a valid email address", - // TODO New key - Add a translation - "forgot-email.form.email.error.not-email-form": "Please fill in a valid email address", + "forgot-email.form.email.error.not-email-form": "Si prega di inserire un idirizzo email valido", // "forgot-email.form.email.hint": "An email will be sent to this address with a further instructions.", - // TODO Source message changed - Revise the translation - "forgot-email.form.email.hint": "Questo indirizzo verrà verificato e utilizzato come login name.", + "forgot-email.form.email.hint": "Una email con ulteriori indicazioni sarà invita a questo indrizzo.", // "forgot-email.form.submit": "Reset password", - // TODO Source message changed - Revise the translation - "forgot-email.form.submit": "Salva", + "forgot-email.form.submit": "Reimposta la password", // "forgot-email.form.success.head": "Password reset email sent", - // TODO Source message changed - Revise the translation - "forgot-email.form.success.head": "Email di verifica inviata", + "forgot-email.form.success.head": "Email di reimpostazione password inviata", // "forgot-email.form.success.content": "An email has been sent to {{ email }} containing a special URL and further instructions.", "forgot-email.form.success.content": "È stata inviata un'email a {{ email }} contenente un URL speciale e ulteriori indicazioni.", // "forgot-email.form.error.head": "Error when trying to reset password", - // TODO Source message changed - Revise the translation - "forgot-email.form.error.head": "Errore durante il tentativo di registrare l'email", + "forgot-email.form.error.head": "Errore durante il tentativo di reimpostare la password", // "forgot-email.form.error.content": "An error occured when attempting to reset the password for the account associated with the following email address: {{ email }}", - // TODO New key - Add a translation - "forgot-email.form.error.content": "An error occured when attempting to reset the password for the account associated with the following email address: {{ email }}", + "forgot-email.form.error.content": "Si è verificato un errore durante il tentativo di reimpostare la password per l'account associato al seguente indirizzo email: {{ email }}", @@ -2584,8 +2470,7 @@ "forgot-password.form.head": "Password dimenticata", // "forgot-password.form.info": "Enter a new password in the box below, and confirm it by typing it again into the second box.", - // TODO Source message changed - Revise the translation - "forgot-password.form.info": "Inserisci una nuova password nella casella qui sotto e confermala digitandola di nuovo nella seconda casella. Dovrebbe avere una lunghezza di almeno sei caratteri.", + "forgot-password.form.info": "Inserisci una nuova password nella casella qui sotto e confermala digitandola di nuovo nella seconda casella.", // "forgot-password.form.card.security": "Security", "forgot-password.form.card.security": "Sicurezza", @@ -2651,21 +2536,14 @@ // "form.first-name": "First name", "form.first-name": "Nome", - // "form.group-collapse": "Collapse", - // TODO New key - Add a translation - "form.group-collapse": "Collapse", - - // "form.group-collapse-help": "Click here to collapse", - // TODO New key - Add a translation - "form.group-collapse-help": "Click here to collapse", + // "form.group.add": "Add", + "form.group.add": "Aggiungi", - // "form.group-expand": "Expand", - // TODO New key - Add a translation - "form.group-expand": "Expand", + // "form.group.close": "Close", + "form.group.close": "Chiudi", - // "form.group-expand-help": "Click here to expand and add more elements", - // TODO New key - Add a translation - "form.group-expand-help": "Click here to expand and add more elements", + // "form.group.set": "Set", + "form.group.set": "Set", // "form.last-name": "Last name", "form.last-name": "Cognome", @@ -2685,9 +2563,8 @@ // "form.no-value": "No value entered", "form.no-value": "Non è stato inserito nessun valore", - // "form.other-information": {}, - // TODO New key - Add a translation - "form.other-information": {}, + // "form.other-information": "", + "form.other-information": "", // "form.remove": "Remove", "form.remove": "Rimuovi", @@ -2708,8 +2585,7 @@ "form.submit": "Salva", // "form.create": "Create", - // TODO New key - Add a translation - "form.create": "Create", + "form.create": "Crea", // "form.repeatable.sort.tip": "Drop the item in the new position", "form.repeatable.sort.tip": "Rilascia l'item nella nuova posizione", @@ -2783,49 +2659,39 @@ // "health.breadcrumbs": "Health", - // TODO New key - Add a translation "health.breadcrumbs": "Health", // "health-page.heading": "Health", - // TODO New key - Add a translation "health-page.heading": "Health", // "health-page.info-tab": "Info", - // TODO New key - Add a translation - "health-page.info-tab": "Info", + "health-page.info-tab": "Informazioni", // "health-page.status-tab": "Status", - // TODO New key - Add a translation - "health-page.status-tab": "Status", + "health-page.status-tab": "Stato", // "health-page.error.msg": "The health check service is temporarily unavailable", "health-page.error.msg": "Il servizio di health check è temporaneamente non disponibile.", // "health-page.property.status": "Status code", - // TODO New key - Add a translation - "health-page.property.status": "Status code", + "health-page.property.status": "Codice di stato", // "health-page.section.db.title": "Database", "health-page.section.db.title": "Database", // "health-page.section.geoIp.title": "GeoIp", - // TODO New key - Add a translation "health-page.section.geoIp.title": "GeoIp", // "health-page.section.solrAuthorityCore.title": "Solr: authority core", - // TODO New key - Add a translation "health-page.section.solrAuthorityCore.title": "Solr: authority core", // "health-page.section.solrOaiCore.title": "Solr: oai core", - // TODO New key - Add a translation "health-page.section.solrOaiCore.title": "Solr: oai core", // "health-page.section.solrSearchCore.title": "Solr: search core", - // TODO New key - Add a translation "health-page.section.solrSearchCore.title": "Solr: search core", // "health-page.section.solrStatisticsCore.title": "Solr: statistics core", - // TODO New key - Add a translation "health-page.section.solrStatisticsCore.title": "Solr: statistics core", // "health-page.section-info.app.title": "Application Backend", @@ -2835,12 +2701,10 @@ "health-page.section-info.java.title": "Java", // "health-page.status": "Status", - // TODO New key - Add a translation - "health-page.status": "Status", + "health-page.status": "Stato", // "health-page.status.ok.info": "Operational", - // TODO New key - Add a translation - "health-page.status.ok.info": "Operational", + "health-page.status.ok.info": "Operativo", // "health-page.status.error.info": "Problems detected", "health-page.status.error.info": "Sono stati rilevati dei problemi", @@ -2849,7 +2713,6 @@ "health-page.status.warning.info": "Sono stati rilevati dei potenziali problemi", // "health-page.title": "Health", - // TODO New key - Add a translation "health-page.title": "Health", // "health-page.section.no-issues": "No issues detected", @@ -2869,10 +2732,9 @@ "home.title": "Home", // "home.top-level-communities.head": "Communities in DSpace", - "home.top-level-communities.head": "Community in DSpace", + "home.top-level-communities.head": "DSpace Communities", - // "home.top-level-communities.help": "Select a community to browse its collections.", - // TODO Source message changed - Revise the translation + // "home.top-level-communities.help": "Search for a collection", "home.top-level-communities.help": "Cerca una collection", @@ -2935,23 +2797,18 @@ "info.feedback.email-label": "La tua email", // "info.feedback.create.success": "Feedback Sent Successfully!", - // TODO Source message changed - Revise the translation "info.feedback.create.success": "Feedback inviato con successo!", // "info.feedback.error.email.required": "A valid email address is required", - // TODO Source message changed - Revise the translation "info.feedback.error.email.required": "Inserire un un indirizzo email valido", // "info.feedback.error.message.required": "A comment is required", - // TODO Source message changed - Revise the translation "info.feedback.error.message.required": "Inserire un commento", // "info.feedback.page-label": "Page", - // TODO Source message changed - Revise the translation "info.feedback.page-label": "Pagina", // "info.feedback.page_help": "Tha page related to your feedback", - // TODO Source message changed - Revise the translation "info.feedback.page_help": "In questa pagina trovi i tuoi feedback", @@ -2973,7 +2830,6 @@ // "item.badge.private": "Non-discoverable", - // TODO Source message changed - Revise the translation "item.badge.private": "Privato", // "item.badge.withdrawn": "Withdrawn", @@ -2985,14 +2841,12 @@ "item.bitstreams.upload.bundle": "Bundle", // "item.bitstreams.upload.bundle.placeholder": "Select a bundle or input new bundle name", - // TODO Source message changed - Revise the translation "item.bitstreams.upload.bundle.placeholder": "Seleziona un bundle o inserisci il nome di un nuovo bundle", // "item.bitstreams.upload.bundle.new": "Create bundle", "item.bitstreams.upload.bundle.new": "Crea un bundle", // "item.bitstreams.upload.bundles.empty": "This item doesn't contain any bundles to upload a bitstream to.", - // TODO Source message changed - Revise the translation "item.bitstreams.upload.bundles.empty": "Questo item non contiene alcun bundle in cui caricare un bitstream.", // "item.bitstreams.upload.cancel": "Cancel", @@ -3145,88 +2999,67 @@ "item.edit.tabs.item-mapper.title": "Modifica item - Mapper Collection", // "item.edit.identifiers.doi.status.UNKNOWN": "Unknown", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.UNKNOWN": "Unknown", + "item.edit.identifiers.doi.status.UNKNOWN": "Sconosciuto", // "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "Queued for registration", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "Queued for registration", + "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "In coda per la registrazione", // "item.edit.identifiers.doi.status.TO_BE_RESERVED": "Queued for reservation", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.TO_BE_RESERVED": "Queued for reservation", + "item.edit.identifiers.doi.status.TO_BE_RESERVED": "In coda per l'assegnazione", // "item.edit.identifiers.doi.status.IS_REGISTERED": "Registered", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.IS_REGISTERED": "Registered", + "item.edit.identifiers.doi.status.IS_REGISTERED": "Registrato", // "item.edit.identifiers.doi.status.IS_RESERVED": "Reserved", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.IS_RESERVED": "Reserved", + "item.edit.identifiers.doi.status.IS_RESERVED": "Assegnato", // "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Reserved (update queued)", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Reserved (update queued)", + "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Assegnato (aggiornamento in coda)", // "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Registered (update queued)", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Registered (update queued)", + "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Registrato (aggiornamento in coda)", // "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "Queued for update and registration", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "Queued for update and registration", + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "In coda per aggiornamento e registrazione", // "item.edit.identifiers.doi.status.TO_BE_DELETED": "Queued for deletion", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.TO_BE_DELETED": "Queued for deletion", + "item.edit.identifiers.doi.status.TO_BE_DELETED": "In coda per l'eliminazione", // "item.edit.identifiers.doi.status.DELETED": "Deleted", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.DELETED": "Deleted", + "item.edit.identifiers.doi.status.DELETED": "Eliminato", // "item.edit.identifiers.doi.status.PENDING": "Pending (not registered)", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.PENDING": "Pending (not registered)", + "item.edit.identifiers.doi.status.PENDING": "In sospeso (non registrato)", // "item.edit.identifiers.doi.status.MINTED": "Minted (not registered)", - // TODO New key - Add a translation - "item.edit.identifiers.doi.status.MINTED": "Minted (not registered)", + "item.edit.identifiers.doi.status.MINTED": "Creato (non registrato)", // "item.edit.tabs.status.buttons.register-doi.label": "Register a new or pending DOI", - // TODO New key - Add a translation - "item.edit.tabs.status.buttons.register-doi.label": "Register a new or pending DOI", + "item.edit.tabs.status.buttons.register-doi.label": "Registra un nuovo DOI o un DOI in sospeso", // "item.edit.tabs.status.buttons.register-doi.button": "Register DOI...", - // TODO New key - Add a translation - "item.edit.tabs.status.buttons.register-doi.button": "Register DOI...", + "item.edit.tabs.status.buttons.register-doi.button": "Registra DOI...", // "item.edit.register-doi.header": "Register a new or pending DOI", - // TODO New key - Add a translation - "item.edit.register-doi.header": "Register a new or pending DOI", + "item.edit.register-doi.header": "Registra un nuovo DOI o un DOI in sospeso", // "item.edit.register-doi.description": "Review any pending identifiers and item metadata below and click Confirm to proceed with DOI registration, or Cancel to back out", - // TODO New key - Add a translation - "item.edit.register-doi.description": "Review any pending identifiers and item metadata below and click Confirm to proceed with DOI registration, or Cancel to back out", + "item.edit.register-doi.description": "Esaminare gli identificatori e i metadati dell'item in sospeso e cliccare su Conferma per procedere con la registrazione DOI, oppure su Annulla per tornare indietro", // "item.edit.register-doi.confirm": "Confirm", - // TODO New key - Add a translation - "item.edit.register-doi.confirm": "Confirm", + "item.edit.register-doi.confirm": "Conferma", // "item.edit.register-doi.cancel": "Cancel", - // TODO New key - Add a translation - "item.edit.register-doi.cancel": "Cancel", + "item.edit.register-doi.cancel": "Annulla", // "item.edit.register-doi.success": "DOI queued for registration successfully.", - // TODO New key - Add a translation - "item.edit.register-doi.success": "DOI queued for registration successfully.", + "item.edit.register-doi.success": "DOI in coda per la registrazione.", // "item.edit.register-doi.error": "Error registering DOI", - // TODO New key - Add a translation - "item.edit.register-doi.error": "Error registering DOI", + "item.edit.register-doi.error": "Errore nella registrazione del DOI", // "item.edit.register-doi.to-update": "The following DOI has already been minted and will be queued for registration online", - // TODO New key - Add a translation - "item.edit.register-doi.to-update": "The following DOI has already been minted and will be queued for registration online", + "item.edit.register-doi.to-update": "Il seguente DOI è stato già creato e sarà inserito in coda per la registrazione online", // "item.edit.item-mapper.buttons.add": "Map item to selected collections", "item.edit.item-mapper.buttons.add": "Mappare l'item nelle collections selezionate", @@ -3291,12 +3124,10 @@ "item.edit.metadata.discard-button": "Annulla", // "item.edit.metadata.edit.buttons.confirm": "Confirm", - // TODO New key - Add a translation - "item.edit.metadata.edit.buttons.confirm": "Confirm", + "item.edit.metadata.edit.buttons.confirm": "Conferma", // "item.edit.metadata.edit.buttons.drag": "Drag to reorder", - // TODO New key - Add a translation - "item.edit.metadata.edit.buttons.drag": "Drag to reorder", + "item.edit.metadata.edit.buttons.drag": "Trascina per riordinare", // "item.edit.metadata.edit.buttons.edit": "Edit", "item.edit.metadata.edit.buttons.edit": "Edita", @@ -3311,8 +3142,7 @@ "item.edit.metadata.edit.buttons.unedit": "Interrompi la modifica", // "item.edit.metadata.edit.buttons.virtual": "This is a virtual metadata value, i.e. a value inherited from a related entity. It can’t be modified directly. Add or remove the corresponding relationship in the \"Relationships\" tab", - // TODO New key - Add a translation - "item.edit.metadata.edit.buttons.virtual": "This is a virtual metadata value, i.e. a value inherited from a related entity. It can’t be modified directly. Add or remove the corresponding relationship in the \"Relationships\" tab", + "item.edit.metadata.edit.buttons.virtual": "Si tratta di un valore virtuale di metadati, cioè un valore ereditato da un'entità correlata. Non può essere modificato direttamente. Aggiungere o rimuovere la relazione corrispondente nella scheda 'Relazioni'.", // "item.edit.metadata.empty": "The item currently doesn't contain any metadata. Click Add to start adding a metadata value.", "item.edit.metadata.empty": "Attualmente l'item non contiene metadati. Fai clic su Aggiungi per iniziare ad aggiungere il valore di un metadata.", @@ -3330,8 +3160,7 @@ "item.edit.metadata.headers.value": "Valore", // "item.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", - // TODO New key - Add a translation - "item.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", + "item.edit.metadata.metadatafield.error": "Si è verificato un errore nella validazione del campo dei metadati", // "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", "item.edit.metadata.metadatafield.invalid": "Scegli un campo di metadati valido", @@ -3340,7 +3169,6 @@ "item.edit.metadata.notifications.discarded.content": "Le modifiche sono state annullate. Per ripristinarle, fai clic sul pulsante \"Annulla\"", // "item.edit.metadata.notifications.discarded.title": "Changes discarded", - // TODO Source message changed - Revise the translation "item.edit.metadata.notifications.discarded.title": "Modifiche eliminate", // "item.edit.metadata.notifications.error.title": "An error occurred", @@ -3356,7 +3184,6 @@ "item.edit.metadata.notifications.outdated.content": "L'item su cui stai attualmente lavorando è stato modificato da un altro utente. Le modifiche correnti verranno eliminate per evitare conflitti", // "item.edit.metadata.notifications.outdated.title": "Changes outdated", - // TODO Source message changed - Revise the translation "item.edit.metadata.notifications.outdated.title": "Modifiche obsolete", // "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", @@ -3369,8 +3196,7 @@ "item.edit.metadata.reinstate-button": "Annulla", // "item.edit.metadata.reset-order-button": "Undo reorder", - // TODO New key - Add a translation - "item.edit.metadata.reset-order-button": "Undo reorder", + "item.edit.metadata.reset-order-button": "Annulla il riordinamento", // "item.edit.metadata.save-button": "Save", "item.edit.metadata.save-button": "Salva", @@ -3433,16 +3259,13 @@ "item.edit.private.cancel": "Annulla", // "item.edit.private.confirm": "Make it non-discoverable", - // TODO Source message changed - Revise the translation "item.edit.private.confirm": "Rendilo privato", // "item.edit.private.description": "Are you sure this item should be made non-discoverable in the archive?", - // TODO Source message changed - Revise the translation - "item.edit.private.description": "Sei sicuro che questo oggetto debba essere reso privato nell'archivio?", + "item.edit.private.description": "Sei sicuro che questo item debba essere reso privato nell'archivio?", // "item.edit.private.error": "An error occurred while making the item non-discoverable", - // TODO Source message changed - Revise the translation - "item.edit.private.error": "Si è verificato un errore durante la creazione di un item privato", + "item.edit.private.error": "Si è verificato un errore durante la modifica dell'item in privato", // "item.edit.private.header": "Make item non-discoverable: {{ id }}", "item.edit.private.header": "Rendi privato l'item: {{ id }}", @@ -3456,22 +3279,18 @@ "item.edit.public.cancel": "Annulla", // "item.edit.public.confirm": "Make it discoverable", - // TODO Source message changed - Revise the translation "item.edit.public.confirm": "Rendilo pubblico", // "item.edit.public.description": "Are you sure this item should be made discoverable in the archive?", - // TODO Source message changed - Revise the translation - "item.edit.public.description": "Sei sicuro che questo articolo debba essere reso pubblico nell'archivio?", + "item.edit.public.description": "Sei sicuro che questo item debba essere reso pubblico nell'archivio?", // "item.edit.public.error": "An error occurred while making the item discoverable", - // TODO Source message changed - Revise the translation - "item.edit.public.error": "Si è verificato un errore durante la creazione di un item pubblico", + "item.edit.public.error": "Si è verificato un errore durante la modifica dell'item in pubblico", // "item.edit.public.header": "Make item discoverable: {{ id }}", "item.edit.public.header": "Rendi pubblico l'item: {{ id }}", // "item.edit.public.success": "The item is now discoverable", - // TODO Source message changed - Revise the translation "item.edit.public.success": "L'item è ora pubblico", @@ -3558,7 +3377,6 @@ // "item.edit.tabs.curate.title": "Item Edit - Curate", "item.edit.tabs.curate.title": "Modifica item - Curate", // "item.edit.curate.title": "Curate Item: {{item}}", - // TODO New key - Add a translation "item.edit.curate.title": "Curate Item: {{item}}", // "item.edit.tabs.metadata.head": "Metadata", @@ -3592,26 +3410,21 @@ "item.edit.tabs.status.buttons.mappedCollections.label": "Gestire le collections mappate", // "item.edit.tabs.status.buttons.move.button": "Move this Item to a different Collection", - // TODO Source message changed - Revise the translation - "item.edit.tabs.status.buttons.move.button": "Sposta...", + "item.edit.tabs.status.buttons.move.button": "Sposta questo item in un'altra collection...", // "item.edit.tabs.status.buttons.move.label": "Move item to another collection", "item.edit.tabs.status.buttons.move.label": "Spostare l'item in un'altra collection", // "item.edit.tabs.status.buttons.private.button": "Make it non-discoverable...", - // TODO Source message changed - Revise the translation - "item.edit.tabs.status.buttons.private.button": "...", + "item.edit.tabs.status.buttons.private.button": "Rendilo privato...", // "item.edit.tabs.status.buttons.private.label": "Make item non-discoverable", - // TODO Source message changed - Revise the translation "item.edit.tabs.status.buttons.private.label": "Rendere l'item privato", // "item.edit.tabs.status.buttons.public.button": "Make it discoverable...", - // TODO Source message changed - Revise the translation - "item.edit.tabs.status.buttons.public.button": "...", + "item.edit.tabs.status.buttons.public.button": "Rendilo pubblico...", // "item.edit.tabs.status.buttons.public.label": "Make item discoverable", - // TODO Source message changed - Revise the translation "item.edit.tabs.status.buttons.public.label": "Rendere l'item pubblico", // "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", @@ -3624,8 +3437,7 @@ "item.edit.tabs.status.buttons.unauthorized": "Non sei autorizzato a eseguire questa azione", // "item.edit.tabs.status.buttons.withdraw.button": "Withdraw this item", - // TODO Source message changed - Revise the translation - "item.edit.tabs.status.buttons.withdraw.button": "Rimozione...", + "item.edit.tabs.status.buttons.withdraw.button": "Rimuovi questo item", // "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", "item.edit.tabs.status.buttons.withdraw.label": "Rimuovere l'item dal repository", @@ -3724,36 +3536,28 @@ "item.truncatable-part.show-less": "Riduci", // "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order", - // TODO New key - Add a translation - "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order", + "workflow-item.search.result.delete-supervision.modal.header": "Elimina l'ordine di supervisione", // "workflow-item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order", - // TODO New key - Add a translation - "workflow-item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order", + "workflow-item.search.result.delete-supervision.modal.info": "Sei sicuro di voler eliminare l'ordine di supervisione?", // "workflow-item.search.result.delete-supervision.modal.cancel": "Cancel", - // TODO New key - Add a translation - "workflow-item.search.result.delete-supervision.modal.cancel": "Cancel", + "workflow-item.search.result.delete-supervision.modal.cancel": "Annulla", // "workflow-item.search.result.delete-supervision.modal.confirm": "Delete", - // TODO New key - Add a translation - "workflow-item.search.result.delete-supervision.modal.confirm": "Delete", + "workflow-item.search.result.delete-supervision.modal.confirm": "Elimina", // "workflow-item.search.result.notification.deleted.success": "Successfully deleted supervision order \"{{name}}\"", - // TODO New key - Add a translation - "workflow-item.search.result.notification.deleted.success": "Successfully deleted supervision order \"{{name}}\"", + "workflow-item.search.result.notification.deleted.success": "Ordine di supervisione \"{{name}}\" eliminato con successo", // "workflow-item.search.result.notification.deleted.failure": "Failed to delete supervision order \"{{name}}\"", - // TODO New key - Add a translation - "workflow-item.search.result.notification.deleted.failure": "Failed to delete supervision order \"{{name}}\"", + "workflow-item.search.result.notification.deleted.failure": "Impossibile eliminare l'ordine di supervisione \"{{name}}\"", // "workflow-item.search.result.list.element.supervised-by": "Supervised by:", - // TODO New key - Add a translation - "workflow-item.search.result.list.element.supervised-by": "Supervised by:", + "workflow-item.search.result.list.element.supervised-by": "Supervisionato da:", // "workflow-item.search.result.list.element.supervised.remove-tooltip": "Remove supervision group", - // TODO New key - Add a translation - "workflow-item.search.result.list.element.supervised.remove-tooltip": "Remove supervision group", + "workflow-item.search.result.list.element.supervised.remove-tooltip": "Rimuovi gruppo di supervisione", @@ -3848,11 +3652,9 @@ "item.page.bitstreams.collapse": "Riduci", // "item.page.filesection.original.bundle": "Original bundle", - // TODO New key - Add a translation "item.page.filesection.original.bundle": "Original bundle", // "item.page.filesection.license.bundle": "License bundle", - // TODO New key - Add a translation "item.page.filesection.license.bundle": "License bundle", // "item.page.return": "Back", @@ -3889,8 +3691,7 @@ "item.preview.dc.language.iso": "Lingua:", // "item.preview.dc.subject": "Subjects:", - // TODO New key - Add a translation - "item.preview.dc.subject": "Subjects:", + "item.preview.dc.subject": "Soggetti:", // "item.preview.dc.title": "Title:", "item.preview.dc.title": "Titolo:", @@ -3899,30 +3700,24 @@ "item.preview.dc.type": "Tipologia:", // "item.preview.oaire.citation.issue": "Issue", - // TODO Source message changed - Revise the translation "item.preview.oaire.citation.issue": "Fascicolo", // "item.preview.oaire.citation.volume": "Volume", - // TODO Source message changed - Revise the translation "item.preview.oaire.citation.volume": "Volume", // "item.preview.dc.relation.issn": "ISSN", - // TODO Source message changed - Revise the translation "item.preview.dc.relation.issn": "ISSN", // "item.preview.dc.identifier.isbn": "ISBN", - // TODO Source message changed - Revise the translation "item.preview.dc.identifier.isbn": "ISBN", // "item.preview.dc.identifier": "Identifier:", "item.preview.dc.identifier": "Identificativo:", // "item.preview.dc.relation.ispartof": "Journal or Serie", - // TODO Source message changed - Revise the translation "item.preview.dc.relation.ispartof": "Periodico or Serie", // "item.preview.dc.identifier.doi": "DOI", - // TODO Source message changed - Revise the translation "item.preview.dc.identifier.doi": "DOI", // "item.preview.person.familyName": "Surname:", @@ -3944,8 +3739,7 @@ "item.preview.oaire.awardNumber": "ID del finanziamento:", // "item.preview.dc.title.alternative": "Acronym:", - // TODO New key - Add a translation - "item.preview.dc.title.alternative": "Acronym:", + "item.preview.dc.title.alternative": "Acronimo:", // "item.preview.dc.coverage.spatial": "Jurisdiction:", "item.preview.dc.coverage.spatial": "Giurisdizione:", @@ -4070,15 +3864,12 @@ "item.version.create.modal.submitted.text": "La nuova versione è in fase di creazione. Questa operazione potrebbe richiedere un po' di temo se l'item ha molte relazioni.", // "item.version.create.notification.success": "New version has been created with version number {{version}}", - // TODO Source message changed - Revise the translation "item.version.create.notification.success": "È stata creata una nuova versione con il numero {{version}}", // "item.version.create.notification.failure": "New version has not been created", - // TODO Source message changed - Revise the translation "item.version.create.notification.failure": "Non è stata creata una nuova versione", // "item.version.create.notification.inProgress": "A new version cannot be created because there is an inprogress submission in the version history", - // TODO Source message changed - Revise the translation "item.version.create.notification.inProgress": "Non è possibile creare una nuova versione perchè c'è già una submission in progress nella cronologia delle versioni", @@ -4101,131 +3892,100 @@ "item.version.delete.modal.button.cancel.tooltip": "Non eliminare questa versione", // "item.version.delete.notification.success": "Version number {{version}} has been deleted", - // TODO Source message changed - Revise the translation "item.version.delete.notification.success": "La versione numero {{version}} è stata eliminata", // "item.version.delete.notification.failure": "Version number {{version}} has not been deleted", - // TODO Source message changed - Revise the translation "item.version.delete.notification.failure": "La versione numero {{version}} non è stata eliminata", // "item.version.edit.notification.success": "The summary of version number {{version}} has been changed", - // TODO Source message changed - Revise the translation "item.version.edit.notification.success": "Il riepilogo della versione numero {{version}} è stato modificato", // "item.version.edit.notification.failure": "The summary of version number {{version}} has not been changed", - // TODO Source message changed - Revise the translation "item.version.edit.notification.failure": "Il riepilogo della versione numero {{version}} non è stato modificato", // "itemtemplate.edit.metadata.add-button": "Add", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.add-button": "Add", + "itemtemplate.edit.metadata.add-button": "Aggiungi", // "itemtemplate.edit.metadata.discard-button": "Discard", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.discard-button": "Discard", + "itemtemplate.edit.metadata.discard-button": "Elimina", // "itemtemplate.edit.metadata.edit.buttons.confirm": "Confirm", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.edit.buttons.confirm": "Confirm", + "itemtemplate.edit.metadata.edit.buttons.confirm": "Conferma", // "itemtemplate.edit.metadata.edit.buttons.drag": "Drag to reorder", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.edit.buttons.drag": "Drag to reorder", + "itemtemplate.edit.metadata.edit.buttons.drag": "Trascina per riordinare", // "itemtemplate.edit.metadata.edit.buttons.edit": "Edit", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.edit.buttons.edit": "Edit", + "itemtemplate.edit.metadata.edit.buttons.edit": "Modifica", // "itemtemplate.edit.metadata.edit.buttons.remove": "Remove", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.edit.buttons.remove": "Remove", + "itemtemplate.edit.metadata.edit.buttons.remove": "Rimuovi", // "itemtemplate.edit.metadata.edit.buttons.undo": "Undo changes", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.edit.buttons.undo": "Undo changes", + "itemtemplate.edit.metadata.edit.buttons.undo": "Annulla le modifiche", // "itemtemplate.edit.metadata.edit.buttons.unedit": "Stop editing", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.edit.buttons.unedit": "Stop editing", + "itemtemplate.edit.metadata.edit.buttons.unedit": "Smetti di modificare", // "itemtemplate.edit.metadata.empty": "The item template currently doesn't contain any metadata. Click Add to start adding a metadata value.", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.empty": "The item template currently doesn't contain any metadata. Click Add to start adding a metadata value.", + "itemtemplate.edit.metadata.empty": "Il template dell'item al momento non contiene nessun metadato. Clicca su 'Aggiungi' per inserire un metadato.", // "itemtemplate.edit.metadata.headers.edit": "Edit", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.headers.edit": "Edit", + "itemtemplate.edit.metadata.headers.edit": "Modifica", // "itemtemplate.edit.metadata.headers.field": "Field", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.headers.field": "Field", + "itemtemplate.edit.metadata.headers.field": "Campo", // "itemtemplate.edit.metadata.headers.language": "Lang", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.headers.language": "Lang", + "itemtemplate.edit.metadata.headers.language": "Lingua", // "itemtemplate.edit.metadata.headers.value": "Value", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.headers.value": "Value", + "itemtemplate.edit.metadata.headers.value": "Valore", // "itemtemplate.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", + "itemtemplate.edit.metadata.metadatafield.error": "Si è verificato un errore durante la validazione del campo dei metadati", // "itemtemplate.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + "itemtemplate.edit.metadata.metadatafield.invalid": "Si prega di scegliere un campo di metadati valido", // "itemtemplate.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + "itemtemplate.edit.metadata.notifications.discarded.content": "Le tue modifiche sono state eliminate. Per riprtinarle, cliccare sul tasto 'Annulla'", - // "itemtemplate.edit.metadata.notifications.discarded.title": "Changes discarded", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.discarded.title": "Changes discarded", + // "itemtemplate.edit.metadata.notifications.discarded.title": "Changed discarded", + "itemtemplate.edit.metadata.notifications.discarded.title": "Modifiche eliminate", // "itemtemplate.edit.metadata.notifications.error.title": "An error occurred", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.error.title": "An error occurred", + "itemtemplate.edit.metadata.notifications.error.title": "Si è verificato un errore", // "itemtemplate.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", + "itemtemplate.edit.metadata.notifications.invalid.content": "Le tue modifiche non sono state salvate. Assicurati che tutti i campi siano validi prima di salvare.", // "itemtemplate.edit.metadata.notifications.invalid.title": "Metadata invalid", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.invalid.title": "Metadata invalid", + "itemtemplate.edit.metadata.notifications.invalid.title": "Metadati non validi", // "itemtemplate.edit.metadata.notifications.outdated.content": "The item template you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.outdated.content": "The item template you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + "itemtemplate.edit.metadata.notifications.outdated.content": "Il template dell'item su cui stai lavorando è stato modificato da un altro utente. Le tue ultime modifiche sono state eliminate per prevenire conflitti", - // "itemtemplate.edit.metadata.notifications.outdated.title": "Changes outdated", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.outdated.title": "Changes outdated", + // "itemtemplate.edit.metadata.notifications.outdated.title": "Changed outdated", + "itemtemplate.edit.metadata.notifications.outdated.title": "Modifiche obsolete", // "itemtemplate.edit.metadata.notifications.saved.content": "Your changes to this item template's metadata were saved.", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.saved.content": "Your changes to this item template's metadata were saved.", + "itemtemplate.edit.metadata.notifications.saved.content": "Le tue modifiche ai metadati di questo template sono state salvate.", // "itemtemplate.edit.metadata.notifications.saved.title": "Metadata saved", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.notifications.saved.title": "Metadata saved", + "itemtemplate.edit.metadata.notifications.saved.title": "Metadati salvati", // "itemtemplate.edit.metadata.reinstate-button": "Undo", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.reinstate-button": "Undo", + "itemtemplate.edit.metadata.reinstate-button": "Annulla", // "itemtemplate.edit.metadata.reset-order-button": "Undo reorder", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.reset-order-button": "Undo reorder", + "itemtemplate.edit.metadata.reset-order-button": "Annulla riordinamento", // "itemtemplate.edit.metadata.save-button": "Save", - // TODO New key - Add a translation - "itemtemplate.edit.metadata.save-button": "Save", + "itemtemplate.edit.metadata.save-button": "Salva", @@ -4492,27 +4252,22 @@ // "menu.section.browse_global": "All of DSpace", // TODO New key - Add a translation - "menu.section.browse_global": "All of DSpace", + "menu.section.browse_global": "Tutto DSpace", // "menu.section.browse_global_by_author": "By Author", - // TODO New key - Add a translation - "menu.section.browse_global_by_author": "By Author", + "menu.section.browse_global_by_author": "Per autore", // "menu.section.browse_global_by_dateissued": "By Issue Date", - // TODO New key - Add a translation - "menu.section.browse_global_by_dateissued": "By Issue Date", + "menu.section.browse_global_by_dateissued": "Per data di pubblicazione", // "menu.section.browse_global_by_subject": "By Subject", - // TODO New key - Add a translation - "menu.section.browse_global_by_subject": "By Subject", + "menu.section.browse_global_by_subject": "Per argomento", // "menu.section.browse_global_by_title": "By Title", - // TODO New key - Add a translation - "menu.section.browse_global_by_title": "By Title", + "menu.section.browse_global_by_title": "Per titolo", // "menu.section.browse_global_communities_and_collections": "Communities & Collections", - // TODO New key - Add a translation - "menu.section.browse_global_communities_and_collections": "Communities & Collections", + "menu.section.communities_and_collections": "Community & Collezioni", @@ -4554,7 +4309,6 @@ "menu.section.export_metadata": "Metadati", // "menu.section.export_batch": "Batch Export (ZIP)", - // TODO New key - Add a translation "menu.section.export_batch": "Batch Export (ZIP)", @@ -4580,8 +4334,7 @@ "menu.section.icon.find": "Trova sezione menu", // "menu.section.icon.health": "Health check menu section", - // TODO New key - Add a translation - "menu.section.icon.health": "Health check menu section", + "menu.section.icon.health": "Sezione del menu Health check", // "menu.section.icon.import": "Import menu section", "menu.section.icon.import": "Sezione del menu Importa", @@ -4593,8 +4346,7 @@ "menu.section.icon.pin": "Fissa la barra laterale", // "menu.section.icon.processes": "Processes Health", - // TODO Source message changed - Revise the translation - "menu.section.icon.processes": "Sezione del menu Processi", + "menu.section.icon.processes": "Processi", // "menu.section.icon.registries": "Registries menu section", "menu.section.icon.registries": "Sezione del menu Registri", @@ -4810,8 +4562,7 @@ "mydspace.show.workspace": "I tuoi contributi", // "mydspace.show.supervisedWorkspace": "Supervised items", - // TODO New key - Add a translation - "mydspace.show.supervisedWorkspace": "Supervised items", + "mydspace.show.supervisedWorkspace": "Item supervisionati", // "mydspace.status.mydspaceArchived": "Archived", "mydspace.status.mydspaceArchived": "Archiviati", @@ -4855,8 +4606,7 @@ "nav.community-browse.header": "Per Community", // "nav.context-help-toggle": "Toggle context help", - // TODO New key - Add a translation - "nav.context-help-toggle": "Toggle context help", + "nav.context-help-toggle": "Attivare la guida contestuale", // "nav.language": "Language switch", "nav.language": "Cambio di lingua", @@ -4865,12 +4615,10 @@ "nav.login": "Accedi", // "nav.user-profile-menu-and-logout": "User profile menu and Log Out", - // TODO New key - Add a translation - "nav.user-profile-menu-and-logout": "User profile menu and Log Out", + "nav.user-profile-menu-and-logout": "Menu profilo utente e Disconnetti", // "nav.logout": "Log Out", - // TODO Source message changed - Revise the translation - "nav.logout": "Menu profilo utente e Disconnetti", + "nav.logout": "Disconnetti", // "nav.main.description": "Main navigation bar", "nav.main.description": "Barra di navigazione principale", @@ -4885,8 +4633,7 @@ "nav.search": "Ricerca", // "nav.search.button": "Submit search", - // TODO New key - Add a translation - "nav.search.button": "Submit search", + "nav.search.button": "Invia ricerca", // "nav.statistics.header": "Statistics", @@ -4896,27 +4643,23 @@ "nav.stop-impersonating": "Smetti di impersonare EPerson", // "nav.subscriptions": "Subscriptions", - // TODO New key - Add a translation - "nav.subscriptions": "Subscriptions", + "nav.subscriptions": "Subscription", // "nav.toggle": "Toggle navigation", - // TODO New key - Add a translation - "nav.toggle": "Toggle navigation", + "nav.toggle": "Attivare la navigazione", // "nav.user.description": "User profile bar", - // TODO New key - Add a translation - "nav.user.description": "User profile bar", + "nav.user.description": "Barra del profilo utente", // "none.listelement.badge": "Item", - "none.listelement.badge": "Articolo", + "none.listelement.badge": "Item", // "orgunit.listelement.badge": "Organizational Unit", "orgunit.listelement.badge": "Unità organizzativa", // "orgunit.listelement.no-title": "Untitled", - // TODO New key - Add a translation - "orgunit.listelement.no-title": "Untitled", + "orgunit.listelement.no-title": "Senza titolo", // "orgunit.page.city": "City", "orgunit.page.city": "Città", @@ -4937,8 +4680,7 @@ "orgunit.page.id": "ID", // "orgunit.page.titleprefix": "Organizational Unit: ", - // TODO New key - Add a translation - "orgunit.page.titleprefix": "Organizational Unit: ", + "orgunit.page.titleprefix": "Unità organizzativa: ", @@ -4984,8 +4726,7 @@ "person.page.lastname": "Cognome", // "person.page.name": "Name", - // TODO New key - Add a translation - "person.page.name": "Name", + "person.page.name": "Nome", // "person.page.link.full": "Show all metadata", "person.page.link.full": "Mostra tutti i metadati", @@ -5000,11 +4741,10 @@ "person.page.titleprefix": "Persona: ", // "person.search.results.head": "Person Search Results", - "person.search.results.head": "Risultati della ricerca per Ricercatore", + "person.search.results.head": "Risultati della ricerca per persona", // "person-relationships.search.results.head": "Person Search Results", - // TODO New key - Add a translation - "person-relationships.search.results.head": "Person Search Results", + "person-relationships.search.results.head": "Risultati della ricerca per persona", // "person.search.title": "Person Search", "person.search.title": "Cerca i Ricercatori", @@ -5045,8 +4785,7 @@ "process.new.parameter.type.file": "file", // "process.new.parameter.required.missing": "The following parameters are required but still missing:", - // TODO New key - Add a translation - "process.new.parameter.required.missing": "The following parameters are required but still missing:", + "process.new.parameter.required.missing": "I seguenti parametri mancanti sono obbligatori:", // "process.new.notification.success.title": "Success", "process.new.notification.success.title": "Successo", @@ -5061,8 +4800,7 @@ "process.new.notification.error.content": "Si è verificato un errore durante la creazione di questo processo", // "process.new.notification.error.max-upload.content": "The file exceeds the maximum upload size", - // TODO New key - Add a translation - "process.new.notification.error.max-upload.content": "The file exceeds the maximum upload size", + "process.new.notification.error.max-upload.content": "Il file è più grande della dimensione massima di upload", // "process.new.header": "Create a new process", "process.new.header": "Creare un nuovo processo", @@ -5076,20 +4814,16 @@ // "process.detail.arguments": "Arguments", - // TODO New key - Add a translation - "process.detail.arguments": "Arguments", + "process.detail.arguments": "Parametri", // "process.detail.arguments.empty": "This process doesn't contain any arguments", - // TODO New key - Add a translation - "process.detail.arguments.empty": "This process doesn't contain any arguments", + "process.detail.arguments.empty": "Questo processo non contiene alcun parametro", // "process.detail.back": "Back", - // TODO New key - Add a translation - "process.detail.back": "Back", + "process.detail.back": "Indietro", // "process.detail.output": "Process Output", - // TODO New key - Add a translation - "process.detail.output": "Process Output", + "process.detail.output": "Output del processo", // "process.detail.logs.button": "Retrieve process output", "process.detail.logs.button": "Recupera l'output del processo", @@ -5101,94 +4835,72 @@ "process.detail.logs.none": "Questo processo non ha output", // "process.detail.output-files": "Output Files", - // TODO New key - Add a translation - "process.detail.output-files": "Output Files", + "process.detail.output-files": "File di output", // "process.detail.output-files.empty": "This process doesn't contain any output files", - // TODO New key - Add a translation - "process.detail.output-files.empty": "This process doesn't contain any output files", + "process.detail.output-files.empty": "Questo processo non contiene nessun file di output", // "process.detail.script": "Script", - // TODO New key - Add a translation "process.detail.script": "Script", // "process.detail.title": "Process: {{ id }} - {{ name }}", - // TODO New key - Add a translation - "process.detail.title": "Process: {{ id }} - {{ name }}", + "process.detail.title": "Processo: {{ id }} - {{ name }}", // "process.detail.start-time": "Start time", - // TODO New key - Add a translation - "process.detail.start-time": "Start time", + "process.detail.start-time": "Orario di inizio", // "process.detail.end-time": "Finish time", - // TODO New key - Add a translation - "process.detail.end-time": "Finish time", + "process.detail.end-time": "Orario di fine", // "process.detail.status": "Status", - // TODO New key - Add a translation - "process.detail.status": "Status", + "process.detail.status": "Stato", // "process.detail.create": "Create similar process", - // TODO New key - Add a translation - "process.detail.create": "Create similar process", + "process.detail.create": "Crea un processo analogo", // "process.detail.actions": "Actions", - // TODO New key - Add a translation - "process.detail.actions": "Actions", + "process.detail.actions": "Azioni", // "process.detail.delete.button": "Delete process", - // TODO New key - Add a translation - "process.detail.delete.button": "Delete process", + "process.detail.delete.button": "Elimina processo", // "process.detail.delete.header": "Delete process", - // TODO New key - Add a translation - "process.detail.delete.header": "Delete process", + "process.detail.delete.header": "Elimina processo", // "process.detail.delete.body": "Are you sure you want to delete the current process?", - // TODO New key - Add a translation - "process.detail.delete.body": "Are you sure you want to delete the current process?", + "process.detail.delete.body": "Sei sicuro di voler eliminare il processo corrente?", // "process.detail.delete.cancel": "Cancel", - // TODO New key - Add a translation - "process.detail.delete.cancel": "Cancel", + "process.detail.delete.cancel": "Annulla", // "process.detail.delete.confirm": "Delete process", - // TODO New key - Add a translation - "process.detail.delete.confirm": "Delete process", + "process.detail.delete.confirm": "Elimina processo", // "process.detail.delete.success": "The process was successfully deleted.", - // TODO New key - Add a translation - "process.detail.delete.success": "The process was successfully deleted.", + "process.detail.delete.success": "Il processo è stato eliminato con successo", // "process.detail.delete.error": "Something went wrong when deleting the process", - // TODO New key - Add a translation - "process.detail.delete.error": "Something went wrong when deleting the process", + "process.detail.delete.error": "Qualcosa è andato storto durante l'elininazione del processo", // "process.overview.table.finish": "Finish time (UTC)", - // TODO New key - Add a translation - "process.overview.table.finish": "Finish time (UTC)", + "process.overview.table.finish": "Orario di fine (UTC)", // "process.overview.table.id": "Process ID", - // TODO New key - Add a translation - "process.overview.table.id": "Process ID", + "process.overview.table.id": "ID del processo", // "process.overview.table.name": "Name", - // TODO New key - Add a translation - "process.overview.table.name": "Name", + "process.overview.table.name": "Nome", // "process.overview.table.start": "Start time (UTC)", - // TODO New key - Add a translation - "process.overview.table.start": "Start time (UTC)", + "process.overview.table.start": "Orario di inizio (UTC)", // "process.overview.table.status": "Status", - // TODO New key - Add a translation - "process.overview.table.status": "Status", + "process.overview.table.status": "Stato", // "process.overview.table.user": "User", - // TODO New key - Add a translation - "process.overview.table.user": "User", + "process.overview.table.user": "Utente", // "process.overview.title": "Processes Overview", "process.overview.title": "Panoramica dei processi", @@ -5200,40 +4912,31 @@ "process.overview.new": "Nuovo", // "process.overview.table.actions": "Actions", - // TODO New key - Add a translation - "process.overview.table.actions": "Actions", + "process.overview.table.actions": "Azioni", // "process.overview.delete": "Delete {{count}} processes", - // TODO New key - Add a translation - "process.overview.delete": "Delete {{count}} processes", + "process.overview.delete": "Elimina {{count}} processi", // "process.overview.delete.clear": "Clear delete selection", - // TODO New key - Add a translation - "process.overview.delete.clear": "Clear delete selection", + "process.overview.delete.clear": "Ripulisci la sezione Elimina", // "process.overview.delete.processing": "{{count}} process(es) are being deleted. Please wait for the deletion to fully complete. Note that this can take a while.", - // TODO New key - Add a translation - "process.overview.delete.processing": "{{count}} process(es) are being deleted. Please wait for the deletion to fully complete. Note that this can take a while.", + "process.overview.delete.processing": "{{count}} processi sono in fase di eliminazione. Attendere che l'attività sia completata. Potrebbe volerci qualche minuto.", // "process.overview.delete.body": "Are you sure you want to delete {{count}} process(es)?", - // TODO New key - Add a translation - "process.overview.delete.body": "Are you sure you want to delete {{count}} process(es)?", + "process.overview.delete.body": "Sei sicuro di voler eliminare {{count}} processo/i?", // "process.overview.delete.header": "Delete processes", - // TODO New key - Add a translation - "process.overview.delete.header": "Delete processes", + "process.overview.delete.header": "Elimina processi", // "process.bulk.delete.error.head": "Error on deleteing process", - // TODO New key - Add a translation - "process.bulk.delete.error.head": "Error on deleteing process", + "process.bulk.delete.error.head": "Errore nell'eliminazione dei processi", // "process.bulk.delete.error.body": "The process with ID {{processId}} could not be deleted. The remaining processes will continue being deleted. ", - // TODO New key - Add a translation - "process.bulk.delete.error.body": "The process with ID {{processId}} could not be deleted. The remaining processes will continue being deleted. ", + "process.bulk.delete.error.body": "Il processo con l'ID {{processId}} non può essere eliminato. I restanti processi saranno eliminati.", // "process.bulk.delete.success": "{{count}} process(es) have been succesfully deleted", - // TODO New key - Add a translation - "process.bulk.delete.success": "{{count}} process(es) have been succesfully deleted", + "process.bulk.delete.success": "{{count}} processi sono stati eliminati con successo", @@ -5246,16 +4949,14 @@ // "profile.card.security": "Security", "profile.card.security": "Sicurezza", - // "profile.form.submit": "Save", - // TODO Source message changed - Revise the translation + // "profile.form.submit": "Update Profile", "profile.form.submit": "Aggiorna profilo", // "profile.groups.head": "Authorization groups you belong to", "profile.groups.head": "Gruppi di autorizzazione a cui appartieni", // "profile.special.groups.head": "Authorization special groups you belong to", - // TODO New key - Add a translation - "profile.special.groups.head": "Authorization special groups you belong to", + "profile.special.groups.head": "Gruppi speciali di autorizzazione a cui appartieni", // "profile.head": "Update Profile", "profile.head": "Aggiorna profilo", @@ -5297,8 +4998,7 @@ "profile.security.form.error.matching-passwords": "Le password non corrispondono.", // "profile.security.form.info": "Optionally, you can enter a new password in the box below, and confirm it by typing it again into the second box.", - // TODO Source message changed - Revise the translation - "profile.security.form.info": "Facoltativamente, è possibile inserire una nuova password nella casella qui sotto e confermarla digitandola nuovamente nella seconda casella. Dovrebbe essere lungo almeno sei caratteri.", + "profile.security.form.info": "Facoltativamente, è possibile inserire una nuova password nella casella qui sotto e confermarla digitandola nuovamente nella seconda casella.", // "profile.security.form.label.password": "Password", "profile.security.form.label.password": "Password", @@ -5307,8 +5007,7 @@ "profile.security.form.label.passwordrepeat": "Ridigitare per confermare", // "profile.security.form.label.current-password": "Current password", - // TODO New key - Add a translation - "profile.security.form.label.current-password": "Current password", + "profile.security.form.label.current-password": "Password corrente", // "profile.security.form.notifications.success.content": "Your changes to the password were saved.", "profile.security.form.notifications.success.content": "Le modifiche apportate alla password sono state salvate.", @@ -5320,15 +5019,13 @@ "profile.security.form.notifications.error.title": "Errore durante la modifica delle password", // "profile.security.form.notifications.error.change-failed": "An error occurred while trying to change the password. Please check if the current password is correct.", - // TODO New key - Add a translation - "profile.security.form.notifications.error.change-failed": "An error occurred while trying to change the password. Please check if the current password is correct.", + "profile.security.form.notifications.error.change-failed": "Si è verificato un errore durante la modifica della password. Assicurati che la password corrente sia corretta.", // "profile.security.form.notifications.error.not-same": "The provided passwords are not the same.", "profile.security.form.notifications.error.not-same": "Le password fornite non sono le stesse.", // "profile.security.form.notifications.error.general": "Please fill required fields of security form.", - // TODO New key - Add a translation - "profile.security.form.notifications.error.general": "Please fill required fields of security form.", + "profile.security.form.notifications.error.general": "Si prega di inserire i campi richiesti nel modulo di sicurezza.", // "profile.title": "Update Profile", "profile.title": "Aggiorna profilo", @@ -5364,15 +5061,13 @@ "project.page.status": "Parole chiave", // "project.page.titleprefix": "Research Project: ", - // TODO New key - Add a translation - "project.page.titleprefix": "Research Project: ", + "project.page.titleprefix": "Progetto di ricerca: ", // "project.search.results.head": "Project Search Results", - "project.search.results.head": "Progetto di ricerca: ", + "project.search.results.head": "Risultati della ricerca per progetti", // "project-relationships.search.results.head": "Project Search Results", - // TODO New key - Add a translation - "project-relationships.search.results.head": "Project Search Results", + "project-relationships.search.results.head": "Risultati della ricerca per progetti", @@ -5395,18 +5090,16 @@ "publication.page.publisher": "Editore", // "publication.page.titleprefix": "Publication: ", - // TODO New key - Add a translation - "publication.page.titleprefix": "Publication: ", + "publication.page.titleprefix": "Pubblicazione: ", // "publication.page.volume-title": "Volume Title", "publication.page.volume-title": "Titolo volume", // "publication.search.results.head": "Publication Search Results", - "publication.search.results.head": "Risultati della ricerca di pubblicazioni", + "publication.search.results.head": "Risultati della ricerca per pubblicazioni", // "publication-relationships.search.results.head": "Publication Search Results", - // TODO New key - Add a translation - "publication-relationships.search.results.head": "Publication Search Results", + "publication-relationships.search.results.head": "Risultati della ricerca per pubblicazioni", // "publication.search.title": "Publication Search", "publication.search.title": "Ricerca pubblicazione", @@ -5456,8 +5149,7 @@ "register-page.create-profile.security.header": "Sicurezza", // "register-page.create-profile.security.info": "Please enter a password in the box below, and confirm it by typing it again into the second box.", - // TODO Source message changed - Revise the translation - "register-page.create-profile.security.info": "Inserisci una password nella casella qui sotto e confermala digitandola nuovamente nella seconda casella. Dovrebbe essere lungo almeno sei caratteri.", + "register-page.create-profile.security.info": "Inserisci una password nella casella qui sotto e confermala digitandola nuovamente nella seconda casella.", // "register-page.create-profile.security.label.password": "Password *", "register-page.create-profile.security.label.password": "Password *", @@ -5500,12 +5192,10 @@ "register-page.registration.email.error.required": "Inserire un indirizzo e-mail", // "register-page.registration.email.error.not-email-form": "Please fill in a valid email address.", - // TODO New key - Add a translation - "register-page.registration.email.error.not-email-form": "Please fill in a valid email address.", + "register-page.registration.email.error.not-email-form": "Inserisci un indirizzo e-mail valido.", // "register-page.registration.email.error.not-valid-domain": "Use email with allowed domains: {{ domains }}", - // TODO New key - Add a translation - "register-page.registration.email.error.not-valid-domain": "Use email with allowed domains: {{ domains }}", + "register-page.registration.email.error.not-valid-domain": "Utilizza una e-mail con un dominio valido: {{ domains }}", // "register-page.registration.email.hint": "This address will be verified and used as your login name.", "register-page.registration.email.hint": "Questo indirizzo verrà verificato e utilizzato come nome di accesso.", @@ -5523,39 +5213,30 @@ "register-page.registration.error.head": "Errore durante il tentativo di registrazione dell'e-mail", // "register-page.registration.error.content": "An error occured when registering the following email address: {{ email }}", - // TODO New key - Add a translation - "register-page.registration.error.content": "An error occured when registering the following email address: {{ email }}", + "register-page.registration.error.content": "Si è verificato un errore durante la registrazione del seguente indirizzo e-mail: {{ email }}", // "register-page.registration.error.recaptcha": "Error when trying to authenticate with recaptcha", - // TODO New key - Add a translation - "register-page.registration.error.recaptcha": "Error when trying to authenticate with recaptcha", + "register-page.registration.error.recaptcha": "Errore durante l'autenticazione con reCaptcha", // "register-page.registration.google-recaptcha.must-accept-cookies": "In order to register you must accept the Registration and Password recovery (Google reCaptcha) cookies.", - // TODO New key - Add a translation - "register-page.registration.google-recaptcha.must-accept-cookies": "In order to register you must accept the Registration and Password recovery (Google reCaptcha) cookies.", + "register-page.registration.google-recaptcha.must-accept-cookies": "Per registrarsi è obbligatorio accettare i cookie Registration and Password recovery (Google reCaptcha).", // "register-page.registration.error.maildomain": "This email address is not on the list of domains who can register. Allowed domains are {{ domains }}", - // TODO New key - Add a translation - "register-page.registration.error.maildomain": "This email address is not on the list of domains who can register. Allowed domains are {{ domains }}", + "register-page.registration.error.maildomain": "Questo indirizzo e-mail non è nella lista dei dominii che possono essere registrati. I domini validi sono {{ domains }}", // "register-page.registration.google-recaptcha.open-cookie-settings": "Open cookie settings", - // TODO New key - Add a translation - "register-page.registration.google-recaptcha.open-cookie-settings": "Open cookie settings", + "register-page.registration.google-recaptcha.open-cookie-settings": "Aprire le impostazioni dei cookie", // "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", - // TODO New key - Add a translation "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", // "register-page.registration.google-recaptcha.notification.message.error": "An error occurred during reCaptcha verification", - // TODO New key - Add a translation - "register-page.registration.google-recaptcha.notification.message.error": "An error occurred during reCaptcha verification", + "register-page.registration.google-recaptcha.notification.message.error": "Si è verificato un errore durante la verifica reCaptcha", // "register-page.registration.google-recaptcha.notification.message.expired": "Verification expired. Please verify again.", - // TODO New key - Add a translation - "register-page.registration.google-recaptcha.notification.message.expired": "Verification expired. Please verify again.", + "register-page.registration.google-recaptcha.notification.message.expired": "Verifica scaduta. Si prega di verificare di nuovo.", // "register-page.registration.info.maildomain": "Accounts can be registered for mail addresses of the domains", - // TODO New key - Add a translation - "register-page.registration.info.maildomain": "Accounts can be registered for mail addresses of the domains", + "register-page.registration.info.maildomain": "Gli account possono essere registrati per gli indirizzi e-mail dei dominii", // "relationships.add.error.relationship-type.content": "No suitable match could be found for relationship type {{ type }} between the two items", "relationships.add.error.relationship-type.content": "Non è stata trovata alcuna corrispondenza adatta per il tipo di relazione {{ type }} tra i due item", @@ -5625,7 +5306,6 @@ "repository.image.logo": "Logo del repository", // "repository.title.prefix": "DSpace Angular :: ", - // TODO New key - Add a translation "repository.title.prefix": "DSpace Angular :: ", // "repository.title.prefixDSpace": "DSpace Angular ::", @@ -5636,60 +5316,58 @@ "resource-policies.add.button": "Aggiungi", // "resource-policies.add.for.": "Add a new policy", - "resource-policies.add.for.": "Aggiungi un nuovo criterio", + "resource-policies.add.for.": "Aggiungi una nuova policy", // "resource-policies.add.for.bitstream": "Add a new Bitstream policy", - "resource-policies.add.for.bitstream": "Aggiungi un nuovo criterio Bitstream", + "resource-policies.add.for.bitstream": "Aggiungi una nuova policy di Bitstream", // "resource-policies.add.for.bundle": "Add a new Bundle policy", - "resource-policies.add.for.bundle": "Aggiungi un nuovo criterio Bundle", + "resource-policies.add.for.bundle": "Aggiungi una nuova policy di Bundle", // "resource-policies.add.for.item": "Add a new Item policy", - "resource-policies.add.for.item": "Aggiungi un nuovo criterio item", + "resource-policies.add.for.item": "Aggiungi una nuova policy di Item", // "resource-policies.add.for.community": "Add a new Community policy", - "resource-policies.add.for.community": "Aggiungere un nuovo criterio comunitario", + "resource-policies.add.for.community": "Aggiungi una nuova policy di community", // "resource-policies.add.for.collection": "Add a new Collection policy", - "resource-policies.add.for.collection": "Aggiungere un nuovo criterio di collezione", + "resource-policies.add.for.collection": "Aggiungi una nuova policy di collezione", // "resource-policies.create.page.heading": "Create new resource policy for ", - "resource-policies.create.page.heading": "Creare nuovi criteri di risorsa per ", + "resource-policies.create.page.heading": "Creare una nuova policy di risorsa per ", // "resource-policies.create.page.failure.content": "An error occurred while creating the resource policy.", - "resource-policies.create.page.failure.content": "Si è verificato un errore durante la creazione del criterio della risorsa.", + "resource-policies.create.page.failure.content": "Si è verificato un errore durante la creazione della policy di risorsa.", // "resource-policies.create.page.success.content": "Operation successful", "resource-policies.create.page.success.content": "Operazione riuscita", // "resource-policies.create.page.title": "Create new resource policy", - "resource-policies.create.page.title": "Creare nuovi criteri risorse", + "resource-policies.create.page.title": "Creare nuove policy di risorsa", // "resource-policies.delete.btn": "Delete selected", "resource-policies.delete.btn": "Elimina selezionato", // "resource-policies.delete.btn.title": "Delete selected resource policies", - "resource-policies.delete.btn.title": "Elimina criteri risorse selezionati", + "resource-policies.delete.btn.title": "Elimina le policy di risorsa selezionate", // "resource-policies.delete.failure.content": "An error occurred while deleting selected resource policies.", - "resource-policies.delete.failure.content": "Si è verificato un errore durante l'eliminazione dei criteri delle risorse selezionati.", + "resource-policies.delete.failure.content": "Si è verificato un errore durante l'eliminazione delle policy di risorsa selezionate.", // "resource-policies.delete.success.content": "Operation successful", "resource-policies.delete.success.content": "Operazione riuscita", // "resource-policies.edit.page.heading": "Edit resource policy ", - "resource-policies.edit.page.heading": "Modifica criterio risorse", + "resource-policies.edit.page.heading": "Modifica policy di risorsa", // "resource-policies.edit.page.failure.content": "An error occurred while editing the resource policy.", - "resource-policies.edit.page.failure.content": "Si è verificato un errore durante la modifica del criterio delle risorse.", + "resource-policies.edit.page.failure.content": "Si è verificato un errore durante la modifica della policy di risorsa.", // "resource-policies.edit.page.target-failure.content": "An error occurred while editing the target (ePerson or group) of the resource policy.", - // TODO New key - Add a translation - "resource-policies.edit.page.target-failure.content": "An error occurred while editing the target (ePerson or group) of the resource policy.", + "resource-policies.edit.page.target-failure.content": "Si è verificato un errore durante la modifica dell'obiettivo (ePerson o gruppo) della policy di risorsa.", // "resource-policies.edit.page.other-failure.content": "An error occurred while editing the resource policy. The target (ePerson or group) has been successfully updated.", - // TODO New key - Add a translation - "resource-policies.edit.page.other-failure.content": "An error occurred while editing the resource policy. The target (ePerson or group) has been successfully updated.", + "resource-policies.edit.page.other-failure.content": "Si è verificato un errore durante la modifica della policy di risorsa. L'obiettio (ePerson o gruppo) è stato aggiornato con successo.", // "resource-policies.edit.page.success.content": "Operation successful", "resource-policies.edit.page.success.content": "Operazione riuscita", @@ -5725,20 +5403,16 @@ "resource-policies.form.eperson-group-list.table.headers.name": "Nome", // "resource-policies.form.eperson-group-list.modal.header": "Cannot change type", - // TODO New key - Add a translation - "resource-policies.form.eperson-group-list.modal.header": "Cannot change type", + "resource-policies.form.eperson-group-list.modal.header": "Impossibile modificare il tipo", // "resource-policies.form.eperson-group-list.modal.text1.toGroup": "It is not possible to replace an ePerson with a group.", - // TODO New key - Add a translation - "resource-policies.form.eperson-group-list.modal.text1.toGroup": "It is not possible to replace an ePerson with a group.", + "resource-policies.form.eperson-group-list.modal.text1.toGroup": "Impossibile sostituire una ePerson con un gruppo.", // "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "It is not possible to replace a group with an ePerson.", - // TODO New key - Add a translation - "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "It is not possible to replace a group with an ePerson.", + "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "Impossibile sostituire un gruppo con una ePerson.", // "resource-policies.form.eperson-group-list.modal.text2": "Delete the current resource policy and create a new one with the desired type.", - // TODO New key - Add a translation - "resource-policies.form.eperson-group-list.modal.text2": "Delete the current resource policy and create a new one with the desired type.", + "resource-policies.form.eperson-group-list.modal.text2": "Elimina la policy di risorsa corrente e creane una nuova con il tipo desiderato.", // "resource-policies.form.eperson-group-list.modal.close": "Ok", "resource-policies.form.eperson-group-list.modal.close": "Ok", @@ -5840,7 +5514,6 @@ "search.filters.applied.f.dateSubmitted": "Data di invio", // "search.filters.applied.f.discoverable": "Non-discoverable", - // TODO Source message changed - Revise the translation "search.filters.applied.f.discoverable": "Privato", // "search.filters.applied.f.entityType": "Item Type", @@ -5856,23 +5529,22 @@ "search.filters.applied.f.namedresourcetype": "Stato", // "search.filters.applied.f.subject": "Subject", - "search.filters.applied.f.subject": "Oggetto", + "search.filters.applied.f.subject": "Soggetto", // "search.filters.applied.f.submitter": "Submitter", - "search.filters.applied.f.submitter": "Mittente", + "search.filters.applied.f.submitter": "Submitter", // "search.filters.applied.f.jobTitle": "Job Title", - "search.filters.applied.f.jobTitle": "Titolo di lavoro", + "search.filters.applied.f.jobTitle": "Ruolo", // "search.filters.applied.f.birthDate.max": "End birth date", - "search.filters.applied.f.birthDate.max": "Data di fine nascita", + "search.filters.applied.f.birthDate.max": "Data di nascita finale", // "search.filters.applied.f.birthDate.min": "Start birth date", "search.filters.applied.f.birthDate.min": "Data di nascita iniziale", // "search.filters.applied.f.supervisedBy": "Supervised by", - // TODO New key - Add a translation - "search.filters.applied.f.supervisedBy": "Supervised by", + "search.filters.applied.f.supervisedBy": "Supervisionato da", // "search.filters.applied.f.withdrawn": "Withdrawn", "search.filters.applied.f.withdrawn": "Ritirato", @@ -5961,7 +5633,6 @@ "search.filters.filter.dateSubmitted.label": "Data di ricerca inviata", // "search.filters.filter.discoverable.head": "Non-discoverable", - // TODO Source message changed - Revise the translation "search.filters.filter.discoverable.head": "Privato", // "search.filters.filter.withdrawn.head": "Withdrawn", @@ -5974,7 +5645,7 @@ "search.filters.filter.entityType.placeholder": "Tipo di item", // "search.filters.filter.entityType.label": "Search item type", - "search.filters.filter.entityType.label": "Tipo di item di ricerca", + "search.filters.filter.entityType.label": "Cerca tipo di item", // "search.filters.filter.expand": "Expand filter", "search.filters.filter.expand": "Espandi filtro", @@ -6010,13 +5681,13 @@ "search.filters.filter.knowsLanguage.label": "Cerca nella lingua nota", // "search.filters.filter.namedresourcetype.head": "Status", - "search.filters.filter.namedresourcetype.head": "Status", + "search.filters.filter.namedresourcetype.head": "Stato", // "search.filters.filter.namedresourcetype.placeholder": "Status", - "search.filters.filter.namedresourcetype.placeholder": "Status", + "search.filters.filter.namedresourcetype.placeholder": "Stato", // "search.filters.filter.namedresourcetype.label": "Search status", - "search.filters.filter.namedresourcetype.label": "Status Ricerca", + "search.filters.filter.namedresourcetype.label": "Cerca stato", // "search.filters.filter.objectpeople.head": "People", "search.filters.filter.objectpeople.head": "Ricercatori", @@ -6088,20 +5759,19 @@ "search.filters.filter.submitter.label": "Mittente della ricerca", // "search.filters.filter.show-tree": "Browse {{ name }} tree", - // TODO New key - Add a translation - "search.filters.filter.show-tree": "Browse {{ name }} tree", + "search.filters.filter.show-tree": "Sfoglia l'albero di {{ name }}", // "search.filters.filter.supervisedBy.head": "Supervised By", - // TODO New key - Add a translation - "search.filters.filter.supervisedBy.head": "Supervised By", + "search.filters.filter.supervisedBy.head": "Supervisionato da", // "search.filters.filter.supervisedBy.placeholder": "Supervised By", - // TODO New key - Add a translation - "search.filters.filter.supervisedBy.placeholder": "Supervised By", + "search.filters.filter.supervisedBy.placeholder": "Supervisionato da", // "search.filters.filter.supervisedBy.label": "Search Supervised By", - // TODO New key - Add a translation - "search.filters.filter.supervisedBy.label": "Search Supervised By", + "search.filters.filter.supervisedBy.label": "Cerca supervisionato da", + + // "search.filters.filter.types.head": "Type", + "search.filters.filter.types.head": "Tipo", @@ -6168,19 +5838,16 @@ "search.results.empty": "La tua ricerca non ha prodotto risultati.", // "search.results.view-result": "View", - // TODO New key - Add a translation - "search.results.view-result": "View", + "search.results.view-result": "Vedi", // "search.results.response.500": "An error occurred during query execution, please try again later", - // TODO New key - Add a translation - "search.results.response.500": "An error occurred during query execution, please try again later", + "search.results.response.500": "Si è verificato un errore durante l'esecuzione, si prega di riprovare più tardi", // "default.search.results.head": "Search Results", "default.search.results.head": "Risultati della ricerca", // "default-relationships.search.results.head": "Search Results", - // TODO New key - Add a translation - "default-relationships.search.results.head": "Search Results", + "default-relationships.search.results.head": "Risultati della ricerca", // "search.sidebar.close": "Back to results", @@ -6218,13 +5885,13 @@ // "sorting.ASC": "Ascending", - "sorting.ASC": "Ascendente", + "sorting.ASC": "Crescente", // "sorting.DESC": "Descending", - "sorting.DESC": "Discendente", + "sorting.DESC": "Decrescente", // "sorting.dc.title.ASC": "Title Ascending", - "sorting.dc.title.ASC": "Titolo ascendente", + "sorting.dc.title.ASC": "Titolo crescente", // "sorting.dc.title.DESC": "Title Descending", "sorting.dc.title.DESC": "Titolo decrescente", @@ -6270,32 +5937,25 @@ "statistics.table.no-data": "Nessun dato disponibile", // "statistics.table.title.TotalVisits": "Total visits", - // TODO New key - Add a translation - "statistics.table.title.TotalVisits": "Total visits", + "statistics.table.rppublicationsReports.title.TotalVisits": "Visite totali", // "statistics.table.title.TotalVisitsPerMonth": "Total visits per month", - // TODO New key - Add a translation - "statistics.table.title.TotalVisitsPerMonth": "Total visits per month", + "statistics.table.title.TotalVisitsPerMonth": "Visite totali al mese", // "statistics.table.title.TotalDownloads": "File Visits", - // TODO New key - Add a translation - "statistics.table.title.TotalDownloads": "File Visits", + "statistics.table.title.TotalDownloads": "Download", // "statistics.table.title.TopCountries": "Top country views", - // TODO New key - Add a translation - "statistics.table.title.TopCountries": "Top country views", + "statistics.table.title.TopCountries": "Migliori nazioni", // "statistics.table.title.TopCities": "Top city views", - // TODO New key - Add a translation - "statistics.table.title.TopCities": "Top city views", + "statistics.table.title.TopCities": "Migliori città", // "statistics.table.header.views": "Views", - // TODO New key - Add a translation - "statistics.table.header.views": "Views", + "statistics.table.header.views": "Visite", // "statistics.table.no-name": "(object name could not be loaded)", - // TODO New key - Add a translation - "statistics.table.no-name": "(object name could not be loaded)", + "statistics.table.no-name": "(il nome dell'oggetto non può essere caricato)", @@ -6403,7 +6063,6 @@ "submission.import-external.source.crossref": "CrossRef", // "submission.import-external.source.datacite": "DataCite", - // TODO New key - Add a translation "submission.import-external.source.datacite": "DataCite", // "submission.import-external.source.scielo": "SciELO", @@ -6452,22 +6111,19 @@ "submission.import-external.source.lcname": "Nomi della Biblioteca del Congresso", // "submission.import-external.preview.title": "Item Preview", - // TODO New key - Add a translation - "submission.import-external.preview.title": "Item Preview", + "submission.import-external.preview.title": "Anteprima item", // "submission.import-external.preview.title.Publication": "Publication Preview", "submission.import-external.preview.title.Publication": "Anteprima pubblicazione", // "submission.import-external.preview.title.none": "Item Preview", - // TODO New key - Add a translation - "submission.import-external.preview.title.none": "Item Preview", + "submission.import-external.preview.title.none": "Anteprima item", // "submission.import-external.preview.title.Journal": "Journal Preview", "submission.import-external.preview.title.Journal": "Anteprima journal", // "submission.import-external.preview.title.OrgUnit": "Organizational Unit Preview", - // TODO Source message changed - Revise the translation - "submission.import-external.preview.title.OrgUnit": "Anteprima editore", + "submission.import-external.preview.title.OrgUnit": "Anteprima struttura", // "submission.import-external.preview.title.Person": "Person Preview", "submission.import-external.preview.title.Person": "Anteprima persona", @@ -6509,8 +6165,7 @@ "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Progetto", // "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Import remote item", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Import remote item", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Importa item remoti", // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Import remote event", "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Importa evento remoto", @@ -6522,8 +6177,7 @@ "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Importare apparecchiature remote", // "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Import remote organizational unit", - // TODO Source message changed - Revise the translation - "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Importa editore remoto", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Importa unitá remota", // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Import remote fund", "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Importa fondo remoto", @@ -6625,8 +6279,7 @@ "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity": "Importato e aggiunto con successo volume di journal esterno alla selezione", // "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Select a local match:", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Select a local match:", + "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Seleziona una corrispondenza locale:", // "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Deselect all", "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Deseleziona tutto", @@ -6728,8 +6381,7 @@ "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Finanziatore del progetto", // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publication of the Author", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publication of the Author", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Pubblicazioni dell'autore", // "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Funding OpenAIRE API", "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Finanziamento dell'API OpenAIRE", @@ -6798,11 +6450,10 @@ "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Unità organizzativa padre", // "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publication", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publication", + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Pubblicazioni", // "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Toggle dropdown", - "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Toggle dropdown", + "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Attiva dropdown", // "submission.sections.describe.relationship-lookup.selection-tab.settings": "Settings", "submission.sections.describe.relationship-lookup.selection-tab.settings": "Impostazioni", @@ -6894,8 +6545,7 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title": "Search Results", "submission.sections.describe.relationship-lookup.selection-tab.title": "Risultati della ricerca", - // "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Would you like to save \"{{ value }}\" as a name variant for this person so you and others can reuse it for future submissions? If you don't you can still use it for this submission.", - // TODO Source message changed - Revise the translation + // "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Would you like to save \"{{ value }}\" as a name variant for this person so you and others can reuse it for future submissions? If you don\'t you can still use it for this submission.", "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Desideri salvare \"{{ value }}\" come variante del nome per questa persona in modo che tu e altri possiate riutilizzarlo per immissioni future? Se non lo fai, puoi comunque usarlo per questa immissione.", // "submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Save a new name variant", @@ -6920,8 +6570,7 @@ "submission.sections.ccLicense.option.select": "Seleziona un'opzione...", // "submission.sections.ccLicense.link": "You’ve selected the following license:", - // TODO New key - Add a translation - "submission.sections.ccLicense.link": "You’ve selected the following license:", + "submission.sections.ccLicense.link": "Hai selezionato la seguente licenza:", // "submission.sections.ccLicense.confirmation": "I grant the license above", "submission.sections.ccLicense.confirmation": "Concedo la licenza di cui sopra", @@ -6930,14 +6579,13 @@ "submission.sections.general.add-more": "Aggiungi altro", // "submission.sections.general.cannot_deposit": "Deposit cannot be completed due to errors in the form.
Please fill out all required fields to complete the deposit.", - // TODO New key - Add a translation - "submission.sections.general.cannot_deposit": "Deposit cannot be completed due to errors in the form.
Please fill out all required fields to complete the deposit.", + "submission.sections.general.cannot_deposit": "L'immissione non può essere competata a causa di errori nel modulo.
Si prega di compilare tutti i campi obbligatori.", // "submission.sections.general.collection": "Collection", - "submission.sections.general.collection": "collezione", + "submission.sections.general.collection": "Collezione", // "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.", - "submission.sections.general.deposit_error_notice": "Si è verificato un problema durante l'immissione dell'articolo, riprova più tardi.", + "submission.sections.general.deposit_error_notice": "Si è verificato un problema durante l'immissione dell'item, riprova più tardi.", // "submission.sections.general.deposit_success_notice": "Submission deposited successfully.", "submission.sections.general.deposit_success_notice": "Immissione depositata con successo.", @@ -6960,8 +6608,7 @@ // "submission.sections.general.no-sections": "No options available", "submission.sections.general.no-sections": "Nessuna opzione disponibile", - // "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.", - // TODO Source message changed - Revise the translation + // "submission.sections.general.save_error_notice": "There was an unexpected error when saving the item. Refresh the page and try again. After refreshing unsaved modifications could be lost.", "submission.sections.general.save_error_notice": "Si è verificato un errore imprevisto durante il salvataggio dell'item. Aggiorna la pagina e riprova. Dopo aver aggiornato le modifiche non salvate potrebbero andare perse.", // "submission.sections.general.save_success_notice": "Submission saved successfully.", @@ -6974,28 +6621,22 @@ "submission.sections.general.sections_not_valid": "Ci sono sezioni incomplete.", // "submission.sections.identifiers.info": "The following identifiers will be created for your item:", - // TODO New key - Add a translation - "submission.sections.identifiers.info": "The following identifiers will be created for your item:", + "submission.sections.identifiers.info": "Per questo item saranno generati i seguenti identificativi:", // "submission.sections.identifiers.no_handle": "No handles have been minted for this item.", - // TODO New key - Add a translation - "submission.sections.identifiers.no_handle": "No handles have been minted for this item.", + "submission.sections.identifiers.no_handle": "Non sono stati generati handle per questo item.", // "submission.sections.identifiers.no_doi": "No DOIs have been minted for this item.", - // TODO New key - Add a translation - "submission.sections.identifiers.no_doi": "No DOIs have been minted for this item.", + "submission.sections.identifiers.no_doi": "Non sono stati generati DOI per questo item.", // "submission.sections.identifiers.handle_label": "Handle: ", - // TODO New key - Add a translation "submission.sections.identifiers.handle_label": "Handle: ", // "submission.sections.identifiers.doi_label": "DOI: ", - // TODO New key - Add a translation "submission.sections.identifiers.doi_label": "DOI: ", // "submission.sections.identifiers.otherIdentifiers_label": "Other identifiers: ", - // TODO New key - Add a translation - "submission.sections.identifiers.otherIdentifiers_label": "Other identifiers: ", + "submission.sections.identifiers.otherIdentifiers_label": "Altri identificativi: ", // "submission.sections.submit.progressbar.accessCondition": "Item access conditions", "submission.sections.submit.progressbar.accessCondition": "Condizioni di accesso all'item", @@ -7019,27 +6660,23 @@ "submission.sections.submit.progressbar.detect-duplicate": "Potenziali duplicati", // "submission.sections.submit.progressbar.identifiers": "Identifiers", - // TODO New key - Add a translation - "submission.sections.submit.progressbar.identifiers": "Identifiers", + "submission.sections.submit.progressbar.identifiers": "Identificativi", // "submission.sections.submit.progressbar.license": "Deposit license", "submission.sections.submit.progressbar.license": "Licenza di deposito", // "submission.sections.submit.progressbar.sherpapolicy": "Sherpa policies", - // TODO New key - Add a translation - "submission.sections.submit.progressbar.sherpapolicy": "Sherpa policies", + "submission.sections.submit.progressbar.sherpapolicy": "Policy di Sherpa", // "submission.sections.submit.progressbar.upload": "Upload files", "submission.sections.submit.progressbar.upload": "Carica file", // "submission.sections.submit.progressbar.sherpaPolicies": "Publisher open access policy information", - // TODO New key - Add a translation - "submission.sections.submit.progressbar.sherpaPolicies": "Publisher open access policy information", + "submission.sections.submit.progressbar.sherpaPolicies": "Informazioni sulla policy di open access dell'editore", // "submission.sections.sherpa-policy.title-empty": "No publisher policy information available. If your work has an associated ISSN, please enter it above to see any related publisher open access policies.", - // TODO New key - Add a translation - "submission.sections.sherpa-policy.title-empty": "No publisher policy information available. If your work has an associated ISSN, please enter it above to see any related publisher open access policies.", + "submission.sections.sherpa-policy.title-empty": "Non sono disponibili informazioni sulle policy dell'editore. Se il lavoro ha un ISSN associato, si prega di inserirlo qui sopra per vedere le policy di open access dell'editore.", // "submission.sections.status.errors.title": "Errors", "submission.sections.status.errors.title": "Errori", @@ -7060,12 +6697,10 @@ "submission.sections.status.warnings.aria": "ha avvisi", // "submission.sections.status.info.title": "Additional Information", - // TODO New key - Add a translation - "submission.sections.status.info.title": "Additional Information", + "submission.sections.status.info.title": "Informazioni aggiuntive", // "submission.sections.status.info.aria": "Additional Information", - // TODO New key - Add a translation - "submission.sections.status.info.aria": "Additional Information", + "submission.sections.status.info.aria": "Informazioni aggiuntive", // "submission.sections.toggle.open": "Open section", "submission.sections.toggle.open": "Apri sezione", @@ -7143,16 +6778,13 @@ "submission.sections.upload.form.until-placeholder": "Fino a quando", // "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", - // TODO New key - Add a translation - "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", + "submission.sections.upload.header.policy.default.nolist": "I file caricati nella collection {{collectionName}} saranno accessibili in base ai seguenti gruppi:", // "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", - // TODO New key - Add a translation - "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", + "submission.sections.upload.header.policy.default.withlist": "Si prega di notare che i file caricati nella collection {{collectionName}} saranno accessibili, in aggiunta a quanto esplicitamente deciso per il singolo file, con i seguenti gruppi:", // "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the file metadata and access conditions or upload additional files by dragging & dropping them anywhere on the page.", - // TODO Source message changed - Revise the translation - "submission.sections.upload.info": "Qui troverai tutti i file attualmente presenti nell'articolo. È possibile aggiornare i metadati dei file e le condizioni di accesso o upload di file aggiuntivi semplicemente trascinandoli e rilasciandoli ovunque nella pagina", + "submission.sections.upload.info": "Qui troverai tutti i file attualmente presenti nell'item. È possibile aggiornare i metadati dei file e le condizioni di accesso o caricare file aggiuntivi semplicemente trascinandoli e rilasciandoli ovunque nella pagina", // "submission.sections.upload.no-entry": "No", "submission.sections.upload.no-entry": "No", @@ -7218,121 +6850,92 @@ "submission.sections.accesses.form.until-placeholder": "Fino a quando", // "submission.sections.license.granted-label": "I confirm the license above", - // TODO New key - Add a translation - "submission.sections.license.granted-label": "I confirm the license above", + "submission.sections.license.granted-label": "Confermo la licenza di cui sopra", // "submission.sections.license.required": "You must accept the license", - // TODO New key - Add a translation - "submission.sections.license.required": "You must accept the license", + "submission.sections.license.required": "È necessario accettare la licenza", // "submission.sections.license.notgranted": "You must accept the license", - // TODO New key - Add a translation - "submission.sections.license.notgranted": "You must accept the license", + "submission.sections.license.notgranted": "È necessario accettare la licenza", // "submission.sections.sherpa.publication.information": "Publication information", - // TODO New key - Add a translation - "submission.sections.sherpa.publication.information": "Publication information", + "submission.sections.sherpa.publication.information": "Informazioni sulla pubblicazione", // "submission.sections.sherpa.publication.information.title": "Title", - // TODO New key - Add a translation - "submission.sections.sherpa.publication.information.title": "Title", + "submission.sections.sherpa.publication.information.title": "Titolo", // "submission.sections.sherpa.publication.information.issns": "ISSNs", - // TODO New key - Add a translation - "submission.sections.sherpa.publication.information.issns": "ISSNs", + "submission.sections.sherpa.publication.information.issns": "ISSN", // "submission.sections.sherpa.publication.information.url": "URL", - // TODO New key - Add a translation "submission.sections.sherpa.publication.information.url": "URL", // "submission.sections.sherpa.publication.information.publishers": "Publisher", - // TODO New key - Add a translation - "submission.sections.sherpa.publication.information.publishers": "Publisher", + "submission.sections.sherpa.publication.information.publishers": "Editore", // "submission.sections.sherpa.publication.information.romeoPub": "Romeo Pub", - // TODO New key - Add a translation "submission.sections.sherpa.publication.information.romeoPub": "Romeo Pub", // "submission.sections.sherpa.publication.information.zetoPub": "Zeto Pub", - // TODO New key - Add a translation "submission.sections.sherpa.publication.information.zetoPub": "Zeto Pub", // "submission.sections.sherpa.publisher.policy": "Publisher Policy", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy": "Publisher Policy", + "submission.sections.sherpa.publisher.policy": "Policy dell'editore", // "submission.sections.sherpa.publisher.policy.description": "The below information was found via Sherpa Romeo. Based on the policies of your publisher, it provides advice regarding whether an embargo may be necessary and/or which files you are allowed to upload. If you have questions, please contact your site administrator via the feedback form in the footer.", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.description": "The below information was found via Sherpa Romeo. Based on the policies of your publisher, it provides advice regarding whether an embargo may be necessary and/or which files you are allowed to upload. If you have questions, please contact your site administrator via the feedback form in the footer.", + "submission.sections.sherpa.publisher.policy.description": "Le informazioni riportate di seguito sono state reperite tramite Sherpa Romeo. In base alle policy del vostro editore, fornisce consigli sull'eventuale necessità di un embargo e/o su quali file è possibile caricare. In caso di domande, contattare l'amministratore del sito tramite il modulo di feedback nel piè di pagina.", // "submission.sections.sherpa.publisher.policy.openaccess": "Open Access pathways permitted by this journal's policy are listed below by article version. Click on a pathway for a more detailed view", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.openaccess": "Open Access pathways permitted by this journal's policy are listed below by article version. Click on a pathway for a more detailed view", + "submission.sections.sherpa.publisher.policy.openaccess": "I percorsi open access consentiti dalle policy di questa rivista sono elencati di seguito per versione dell'articolo. Clicca su un percorso per vederlo nel dettaglio", // "submission.sections.sherpa.publisher.policy.more.information": "For more information, please see the following links:", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.more.information": "For more information, please see the following links:", + "submission.sections.sherpa.publisher.policy.more.information": "Per maggiori informazioni si prega di consultare il seguente link:", // "submission.sections.sherpa.publisher.policy.version": "Version", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.version": "Version", + "submission.sections.sherpa.publisher.policy.version": "Versione", // "submission.sections.sherpa.publisher.policy.embargo": "Embargo", - // TODO New key - Add a translation "submission.sections.sherpa.publisher.policy.embargo": "Embargo", // "submission.sections.sherpa.publisher.policy.noembargo": "No Embargo", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.noembargo": "No Embargo", + "submission.sections.sherpa.publisher.policy.noembargo": "Nessun embargo", // "submission.sections.sherpa.publisher.policy.nolocation": "None", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.nolocation": "None", + "submission.sections.sherpa.publisher.policy.nolocation": "Nessuno", // "submission.sections.sherpa.publisher.policy.license": "License", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.license": "License", + "submission.sections.sherpa.publisher.policy.license": "Licenza", // "submission.sections.sherpa.publisher.policy.prerequisites": "Prerequisites", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.prerequisites": "Prerequisites", + "submission.sections.sherpa.publisher.policy.prerequisites": "Prerequisiti", // "submission.sections.sherpa.publisher.policy.location": "Location", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.location": "Location", + "submission.sections.sherpa.publisher.policy.location": "Località", // "submission.sections.sherpa.publisher.policy.conditions": "Conditions", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.conditions": "Conditions", + "submission.sections.sherpa.publisher.policy.conditions": "Condizioni", // "submission.sections.sherpa.publisher.policy.refresh": "Refresh", - // TODO New key - Add a translation - "submission.sections.sherpa.publisher.policy.refresh": "Refresh", + "submission.sections.sherpa.publisher.policy.refresh": "Ricarica", // "submission.sections.sherpa.record.information": "Record Information", - // TODO New key - Add a translation - "submission.sections.sherpa.record.information": "Record Information", + "submission.sections.sherpa.record.information": "Informazioni sulla registrazione", // "submission.sections.sherpa.record.information.id": "ID", - // TODO New key - Add a translation "submission.sections.sherpa.record.information.id": "ID", // "submission.sections.sherpa.record.information.date.created": "Date Created", - // TODO New key - Add a translation - "submission.sections.sherpa.record.information.date.created": "Date Created", + "submission.sections.sherpa.record.information.date.created": "Data di creazione", // "submission.sections.sherpa.record.information.date.modified": "Last Modified", - // TODO New key - Add a translation - "submission.sections.sherpa.record.information.date.modified": "Last Modified", + "submission.sections.sherpa.record.information.date.modified": "Ultima modifica", // "submission.sections.sherpa.record.information.uri": "URI", - // TODO New key - Add a translation "submission.sections.sherpa.record.information.uri": "URI", // "submission.sections.sherpa.error.message": "There was an error retrieving sherpa informations", - // TODO New key - Add a translation - "submission.sections.sherpa.error.message": "There was an error retrieving sherpa informations", + "submission.sections.sherpa.error.message": "Si è verificato un errore nel recuperare le informazioni da Sherpa", @@ -7347,8 +6950,7 @@ // "submission.workflow.generic.delete": "Delete", "submission.workflow.generic.delete": "Elimina", - // "submission.workflow.generic.delete-help": "Select this option to discard this item. You will then be asked to confirm it.", - // TODO Source message changed - Revise the translation + // "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\". You will then be asked to confirm it.", "submission.workflow.generic.delete-help": "Se si desidera eliminare questo item, selezionare \"Elimina\". Ti verrà quindi chiesto di confermarlo.", // "submission.workflow.generic.edit": "Edit", @@ -7365,20 +6967,16 @@ // "submission.workflow.generic.submit_select_reviewer": "Select Reviewer", - // TODO New key - Add a translation - "submission.workflow.generic.submit_select_reviewer": "Select Reviewer", + "submission.workflow.generic.submit_select_reviewer": "Seleziona revisore", // "submission.workflow.generic.submit_select_reviewer-help": "", - // TODO New key - Add a translation "submission.workflow.generic.submit_select_reviewer-help": "", // "submission.workflow.generic.submit_score": "Rate", - // TODO New key - Add a translation - "submission.workflow.generic.submit_score": "Rate", + "submission.workflow.generic.submit_score": "Valuta", // "submission.workflow.generic.submit_score-help": "", - // TODO New key - Add a translation "submission.workflow.generic.submit_score-help": "", @@ -7395,11 +6993,9 @@ "submission.workflow.tasks.claimed.edit_help": "Selezionare questa opzione per modificare i metadati dell'item.", // "submission.workflow.tasks.claimed.decline": "Decline", - // TODO New key - Add a translation - "submission.workflow.tasks.claimed.decline": "Decline", + "submission.workflow.tasks.claimed.decline": "Rifiuta", // "submission.workflow.tasks.claimed.decline_help": "", - // TODO New key - Add a translation "submission.workflow.tasks.claimed.decline_help": "", // "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.", @@ -7490,72 +7086,55 @@ "subscriptions.frequency.W": "Settimanale", // "subscriptions.tooltip": "Subscribe", - // TODO New key - Add a translation - "subscriptions.tooltip": "Subscribe", + "subscriptions.tooltip": "Sottoscrivi", // "subscriptions.modal.title": "Subscriptions", - // TODO New key - Add a translation - "subscriptions.modal.title": "Subscriptions", + "subscriptions.modal.title": "Sottoscrizioni", // "subscriptions.modal.type-frequency": "Type and frequency", - // TODO New key - Add a translation - "subscriptions.modal.type-frequency": "Type and frequency", + "subscriptions.modal.type-frequency": "Tipo e frequenza", // "subscriptions.modal.close": "Close", - // TODO New key - Add a translation - "subscriptions.modal.close": "Close", + "subscriptions.modal.close": "Chiudi", // "subscriptions.modal.delete-info": "To remove this subscription, please visit the \"Subscriptions\" page under your user profile", - // TODO New key - Add a translation - "subscriptions.modal.delete-info": "To remove this subscription, please visit the \"Subscriptions\" page under your user profile", + "subscriptions.modal.delete-info": "Per rimuovere questa sottoscrizione si prega di visitare la pagina \"Sottoscrizioni\" nel proprio profilo utente", // "subscriptions.modal.new-subscription-form.type.content": "Content", - // TODO New key - Add a translation - "subscriptions.modal.new-subscription-form.type.content": "Content", + "subscriptions.modal.new-subscription-form.type.content": "Contenuto", // "subscriptions.modal.new-subscription-form.frequency.D": "Daily", - // TODO New key - Add a translation - "subscriptions.modal.new-subscription-form.frequency.D": "Daily", + "subscriptions.modal.new-subscription-form.frequency.D": "Giornaliero", // "subscriptions.modal.new-subscription-form.frequency.W": "Weekly", - // TODO New key - Add a translation - "subscriptions.modal.new-subscription-form.frequency.W": "Weekly", + "subscriptions.modal.new-subscription-form.frequency.W": "Settimanale", // "subscriptions.modal.new-subscription-form.frequency.M": "Monthly", - // TODO New key - Add a translation - "subscriptions.modal.new-subscription-form.frequency.M": "Monthly", + "subscriptions.modal.new-subscription-form.frequency.M": "Mensile", // "subscriptions.modal.new-subscription-form.submit": "Submit", - // TODO New key - Add a translation - "subscriptions.modal.new-subscription-form.submit": "Submit", + "subscriptions.modal.new-subscription-form.submit": "Invia", // "subscriptions.modal.new-subscription-form.processing": "Processing...", - // TODO New key - Add a translation - "subscriptions.modal.new-subscription-form.processing": "Processing...", + "subscriptions.modal.new-subscription-form.processing": "Elaborazione...", // "subscriptions.modal.create.success": "Subscribed to {{ type }} successfully.", - // TODO New key - Add a translation - "subscriptions.modal.create.success": "Subscribed to {{ type }} successfully.", + "subscriptions.modal.create.success": "Sottoscrzione a {{ type }} avvenuta con successo.", // "subscriptions.modal.delete.success": "Subscription deleted successfully", - // TODO New key - Add a translation - "subscriptions.modal.delete.success": "Subscription deleted successfully", + "subscriptions.modal.delete.success": "Sottoscrizione eliminata con successo", // "subscriptions.modal.update.success": "Subscription to {{ type }} updated successfully", - // TODO New key - Add a translation - "subscriptions.modal.update.success": "Subscription to {{ type }} updated successfully", + "subscriptions.modal.update.success": "Sottoscrizione a {{ type }} aggiornata con successo", // "subscriptions.modal.create.error": "An error occurs during the subscription creation", - // TODO New key - Add a translation - "subscriptions.modal.create.error": "An error occurs during the subscription creation", + "subscriptions.modal.create.error": "Si è verificato un errore durante la creazione della sottoscrizione", // "subscriptions.modal.delete.error": "An error occurs during the subscription delete", - // TODO New key - Add a translation - "subscriptions.modal.delete.error": "An error occurs during the subscription delete", + "subscriptions.modal.delete.error": "Si è verificato un errore durante l'eliminazione della sottoscrizione", // "subscriptions.modal.update.error": "An error occurs during the subscription update", - // TODO New key - Add a translation - "subscriptions.modal.update.error": "An error occurs during the subscription update", + "subscriptions.modal.update.error": "Si è verificato un errore durante l'aggiornamento della sottoscrizione", // "subscriptions.table.dso": "Subject", "subscriptions.table.dso": "Oggetto", @@ -7570,24 +7149,19 @@ "subscriptions.table.action": "Azione", // "subscriptions.table.edit": "Edit", - // TODO New key - Add a translation - "subscriptions.table.edit": "Edit", + "subscriptions.table.edit": "Modifica", // "subscriptions.table.delete": "Delete", - // TODO New key - Add a translation - "subscriptions.table.delete": "Delete", + "subscriptions.table.delete": "Elimina", // "subscriptions.table.not-available": "Not available", - // TODO New key - Add a translation - "subscriptions.table.not-available": "Not available", + "subscriptions.table.not-available": "Non disponibile", // "subscriptions.table.not-available-message": "The subscribed item has been deleted, or you don't currently have the permission to view it", - // TODO New key - Add a translation - "subscriptions.table.not-available-message": "The subscribed item has been deleted, or you don't currently have the permission to view it", + "subscriptions.table.not-available-message": "L'elemento sottoscritto è stato cancellato o non si ha l'autorizzazione per visualizzarlo.", // "subscriptions.table.empty.message": "You do not have any subscriptions at this time. To subscribe to email updates for a Community or Collection, use the subscription button on the object's page.", - // TODO Source message changed - Revise the translation - "subscriptions.table.empty.message": "Non hai ancora sottoscritto alcuna notifica. Per sottoscrivere la notifica relativa a un oggetto, usa il menu contestuale nella pagina di dettaglio dell'oggetto", + "subscriptions.table.empty.message": "Al momento non ci sono sottoscrizioni. Per ricevere aggiornamenti via e-mail di una Community o di una Collection, utilizzare il pulsante di sottoscrizione sulla pagina dell'oggetto", // "thumbnail.default.alt": "Thumbnail Image", @@ -7643,8 +7217,7 @@ "vocabulary-treeview.tree.description.srsc": "Categorie di argomenti di ricerca", // "vocabulary-treeview.info": "Select a subject to add as search filter", - // TODO New key - Add a translation - "vocabulary-treeview.info": "Select a subject to add as search filter", + "vocabulary-treeview.info": "Seleziona un soggetto da aggiungere come filtro di ricerca", // "uploader.browse": "browse", "uploader.browse": "sfoglia", @@ -7659,8 +7232,7 @@ "uploader.or": ", oppure ", // "uploader.processing": "Processing uploaded file(s)... (it's now safe to close this page)", - // TODO Source message changed - Revise the translation - "uploader.processing": "Elaborazione", + "uploader.processing": "Elaborazione dei file caricati... (è ora possibile chiudere questa pagina)", // "uploader.queue-length": "Queue length", "uploader.queue-length": "Lunghezza coda", @@ -7677,8 +7249,7 @@ // "supervisedWorkspace.search.results.head": "Supervised Items", - // TODO New key - Add a translation - "supervisedWorkspace.search.results.head": "Supervised Items", + "supervisedWorkspace.search.results.head": "Item supervisionati", // "workspace.search.results.head": "Your submissions", "workspace.search.results.head": "I tuoi invii", @@ -7690,8 +7261,7 @@ "workflow.search.results.head": "Task del workflow", // "supervision.search.results.head": "Workflow and Workspace tasks", - // TODO New key - Add a translation - "supervision.search.results.head": "Workflow and Workspace tasks", + "supervision.search.results.head": "Task del workflow e del workspace", @@ -7761,74 +7331,57 @@ // "workflow-item.advanced.title": "Advanced workflow", - // TODO New key - Add a translation - "workflow-item.advanced.title": "Advanced workflow", + "workflow-item.advanced.title": "Workflow avanzato", // "workflow-item.selectrevieweraction.notification.success.title": "Selected reviewer", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.notification.success.title": "Selected reviewer", + "workflow-item.selectrevieweraction.notification.success.title": "Revisore selezionato", // "workflow-item.selectrevieweraction.notification.success.content": "The reviewer for this workflow item has been successfully selected", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.notification.success.content": "The reviewer for this workflow item has been successfully selected", + "workflow-item.selectrevieweraction.notification.success.content": "Il revisore per questo item nel workflow è stato selezionato con successo", // "workflow-item.selectrevieweraction.notification.error.title": "Something went wrong", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.notification.error.title": "Something went wrong", + "workflow-item.selectrevieweraction.notification.error.title": "Qualcosa è andato storto", // "workflow-item.selectrevieweraction.notification.error.content": "Couldn't select the reviewer for this workflow item", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.notification.error.content": "Couldn't select the reviewer for this workflow item", + "workflow-item.selectrevieweraction.notification.error.content": "Non è stato possibile selezionare il revisore per questo item nel workflow", // "workflow-item.selectrevieweraction.title": "Select Reviewer", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.title": "Select Reviewer", + "workflow-item.selectrevieweraction.title": "Seleziona revisore", // "workflow-item.selectrevieweraction.header": "Select Reviewer", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.header": "Select Reviewer", + "workflow-item.selectrevieweraction.header": "Seleziona revisore", // "workflow-item.selectrevieweraction.button.cancel": "Cancel", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.button.cancel": "Cancel", + "workflow-item.selectrevieweraction.button.cancel": "Annulla", // "workflow-item.selectrevieweraction.button.confirm": "Confirm", - // TODO New key - Add a translation - "workflow-item.selectrevieweraction.button.confirm": "Confirm", + "workflow-item.selectrevieweraction.button.confirm": "Conferma", // "workflow-item.scorereviewaction.notification.success.title": "Rating review", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.notification.success.title": "Rating review", + "workflow-item.scorereviewaction.notification.success.title": "Valuta revisione", // "workflow-item.scorereviewaction.notification.success.content": "The rating for this item workflow item has been successfully submitted", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.notification.success.content": "The rating for this item workflow item has been successfully submitted", + "workflow-item.scorereviewaction.notification.success.content": "La valutazione per il workflow di questo item è stata inserita con successo", // "workflow-item.scorereviewaction.notification.error.title": "Something went wrong", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.notification.error.title": "Something went wrong", + "workflow-item.scorereviewaction.notification.error.title": "Qualcosa è andato storto", // "workflow-item.scorereviewaction.notification.error.content": "Couldn't rate this item", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.notification.error.content": "Couldn't rate this item", + "workflow-item.scorereviewaction.notification.error.content": "Non è stato possibile valutare questo item", // "workflow-item.scorereviewaction.title": "Rate this item", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.title": "Rate this item", + "workflow-item.scorereviewaction.title": "Valuta questo item", // "workflow-item.scorereviewaction.header": "Rate this item", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.header": "Rate this item", + "workflow-item.scorereviewaction.header": "Valuta questo item", // "workflow-item.scorereviewaction.button.cancel": "Cancel", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.button.cancel": "Cancel", + "workflow-item.scorereviewaction.button.cancel": "Annulla", // "workflow-item.scorereviewaction.button.confirm": "Confirm", - // TODO New key - Add a translation - "workflow-item.scorereviewaction.button.confirm": "Confirm", + "workflow-item.scorereviewaction.button.confirm": "Conferma", // "idle-modal.header": "Session will expire soon", "idle-modal.header": "La sessione scadrà presto", @@ -7843,7 +7396,6 @@ "idle-modal.extend-session": "Estendi sessione", // "researcher.profile.action.processing": "Processing...", - // TODO Source message changed - Revise the translation "researcher.profile.action.processing": "Elaborazione...", // "researcher.profile.associated": "Researcher profile associated", @@ -7877,11 +7429,9 @@ "researcher.profile.view": "Visualizza", // "researcher.profile.private.visibility": "PRIVATE", - // TODO Source message changed - Revise the translation "researcher.profile.private.visibility": "PRIVATO", // "researcher.profile.public.visibility": "PUBLIC", - // TODO Source message changed - Revise the translation "researcher.profile.public.visibility": "PUBBLICO", // "researcher.profile.status": "Status:", @@ -7891,19 +7441,15 @@ "researcherprofile.claim.not-authorized": "Non sei autorizzato a richiedere questo item. Per maggiori dettagli contattare l'amministratore/i", // "researcherprofile.error.claim.body": "An error occurred while claiming the profile, please try again later", - // TODO Source message changed - Revise the translation "researcherprofile.error.claim.body": "Si è verificato un errore durante l'associazione del profilo, prova più tardi", // "researcherprofile.error.claim.title": "Error", - // TODO Source message changed - Revise the translation "researcherprofile.error.claim.title": "Errore", // "researcherprofile.success.claim.body": "Profile claimed with success", - // TODO Source message changed - Revise the translation "researcherprofile.success.claim.body": "Profilo associato con successo", // "researcherprofile.success.claim.title": "Success", - // TODO Source message changed - Revise the translation "researcherprofile.success.claim.title": "Successo", // "person.page.orcid.create": "Create an ORCID ID", @@ -7913,7 +7459,6 @@ "person.page.orcid.granted-authorizations": "Autorizzazioni concesse", // "person.page.orcid.grant-authorizations": "Grant authorizations", - // TODO Source message changed - Revise the translation "person.page.orcid.grant-authorizations": "Concedere autorizzazioni", // "person.page.orcid.link": "Connect to ORCID ID", @@ -7962,55 +7507,42 @@ "person.page.orcid.save.preference.changes": "Impostazioni di aggiornamento", // "person.page.orcid.sync-profile.affiliation": "Affiliation", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-profile.affiliation": "Affiliazione", // "person.page.orcid.sync-profile.biographical": "Biographical data", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-profile.biographical": "Riferimenti biografici", // "person.page.orcid.sync-profile.education": "Education", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-profile.education": "Educazione", // "person.page.orcid.sync-profile.identifiers": "Identifiers", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-profile.identifiers": "Identificativi", // "person.page.orcid.sync-fundings.all": "All fundings", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-fundings.all": "Tutti i finanziamenti", // "person.page.orcid.sync-fundings.mine": "My fundings", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-fundings.mine": "I miei finanziamenti", // "person.page.orcid.sync-fundings.my_selected": "Selected fundings", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-fundings.my_selected": "Finanziamenti selezionati", // "person.page.orcid.sync-fundings.disabled": "Disabled", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-fundings.disabled": "Disabilitato", // "person.page.orcid.sync-publications.all": "All publications", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-publications.all": "Tutte le pubblicazioni", // "person.page.orcid.sync-publications.mine": "My publications", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-publications.mine": "Le mie pubblicazioni", // "person.page.orcid.sync-publications.my_selected": "Selected publications", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-publications.my_selected": "Pubblicazioni selezionate", // "person.page.orcid.sync-publications.disabled": "Disabled", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-publications.disabled": "Disabilitato", // "person.page.orcid.sync-queue.discard": "Discard the change and do not synchronize with the ORCID registry", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.discard": "Scarta la modifica e non sincronizzarla con il registro ORCID.", // "person.page.orcid.sync-queue.discard.error": "The discarding of the ORCID queue record failed", @@ -8023,15 +7555,12 @@ "person.page.orcid.sync-queue.empty-message": "Il Registro di sistema della coda ORCID è vuoto", // "person.page.orcid.sync-queue.table.header.type": "Type", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.table.header.type": "Tipo", // "person.page.orcid.sync-queue.table.header.description": "Description", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.table.header.description": "Descrizione", // "person.page.orcid.sync-queue.table.header.action": "Action", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.table.header.action": "Azione", // "person.page.orcid.sync-queue.description.affiliation": "Affiliations", @@ -8098,7 +7627,6 @@ "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL ricercatore", // "person.page.orcid.sync-queue.send": "Synchronize with ORCID registry", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.send": "Sincronizza con il registro ORCID", // "person.page.orcid.sync-queue.send.unauthorized-error.title": "The submission to ORCID failed for missing authorizations.", @@ -8135,7 +7663,6 @@ "person.page.orcid.sync-queue.send.validation-error.title.required": "Il titolo è obbligatorio", // "person.page.orcid.sync-queue.send.validation-error.type.required": "The dc.type is required", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.send.validation-error.type.required": "Il tipo è obbligatorio", // "person.page.orcid.sync-queue.send.validation-error.start-date.required": "The start date is required", @@ -8154,7 +7681,6 @@ "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Il nome dell'organizzazione è obbligatorio", // "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "The publication date must be one year after 1900", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "La data di pubblicazione deve partire dal 1900", // "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "The organization to be sent requires an address", @@ -8164,7 +7690,6 @@ "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "L'indirizzo dell'organizzazione da inviare richiede una città", // "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "The address of the organization to be sent requires a valid 2 digits ISO 3166 country", - // TODO Source message changed - Revise the translation "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "L'indirizzo dell'organizzazione da inviare richiede un paese (inserire 2 cifre secondo l'ISO 3166)", // "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "An identifier to disambiguate organizations is required. Supported ids are GRID, Ringgold, Legal Entity identifiers (LEIs) and Crossref Funder Registry identifiers", @@ -8189,8 +7714,7 @@ "person.page.orcid.synchronization-mode.label": "Sincronizzazione", // "person.page.orcid.synchronization-mode-message": "Please select how you would like synchronization to ORCID to occur. The options include \"Manual\" (you must send your data to ORCID manually), or \"Batch\" (the system will send your data to ORCID via a scheduled script).", - // TODO Source message changed - Revise the translation - "person.page.orcid.synchronization-mode-message": "Abilitare la modalità di sincronizzazione \"manuale\" per disabilitare la sincronizzazione batch in modo da dover inviare manualmente i dati al Registro ORCID", + "person.page.orcid.synchronization-mode-message": "Selezionare la modalità di sincronizzazione con ORCID. Le opzioni includono 'Manuale' (sarà necessario inviare i dati a ORCID manualmente) o 'Batch' (il sistema invierà i dati a ORCID tramite uno script programmato).", // "person.page.orcid.synchronization-mode-funding-message": "Select whether to send your linked Project entities to your ORCID record's list of funding information.", "person.page.orcid.synchronization-mode-funding-message": "Scegli se sincronizzare i tuoi Progetti con la lista delle informazioni dei progetti sul profilo ORCID.", @@ -8237,107 +7761,80 @@ // "person.orcid.registry.auth": "ORCID Authorizations", "person.orcid.registry.auth": "Autorizzazioni ORCID", // "home.recent-submissions.head": "Recent Submissions", - // TODO New key - Add a translation - "home.recent-submissions.head": "Recent Submissions", + "home.recent-submissions.head": "Immissioni recenti", // "listable-notification-object.default-message": "This object couldn't be retrieved", - // TODO New key - Add a translation - "listable-notification-object.default-message": "This object couldn't be retrieved", + "listable-notification-object.default-message": "Questo oggetto non può essere recuperato", // "system-wide-alert-banner.retrieval.error": "Something went wrong retrieving the system-wide alert banner", - // TODO New key - Add a translation - "system-wide-alert-banner.retrieval.error": "Something went wrong retrieving the system-wide alert banner", + "system-wide-alert-banner.retrieval.error": "Qualcosa è andato storto nel recupero del banner di allarme di sistema", // "system-wide-alert-banner.countdown.prefix": "In", - // TODO New key - Add a translation - "system-wide-alert-banner.countdown.prefix": "In", + "system-wide-alert-banner.countdown.prefix": "Tra", // "system-wide-alert-banner.countdown.days": "{{days}} day(s),", - // TODO New key - Add a translation - "system-wide-alert-banner.countdown.days": "{{days}} day(s),", + "system-wide-alert-banner.countdown.days": "{{days}} giorni,", // "system-wide-alert-banner.countdown.hours": "{{hours}} hour(s) and", - // TODO New key - Add a translation - "system-wide-alert-banner.countdown.hours": "{{hours}} hour(s) and", + "system-wide-alert-banner.countdown.hours": "{{hours}} ore e", // "system-wide-alert-banner.countdown.minutes": "{{minutes}} minute(s):", - // TODO New key - Add a translation - "system-wide-alert-banner.countdown.minutes": "{{minutes}} minute(s):", - - + "system-wide-alert-banner.countdown.minutes": "{{minutes}} minuti:", // "menu.section.system-wide-alert": "System-wide Alert", - // TODO New key - Add a translation - "menu.section.system-wide-alert": "System-wide Alert", + "menu.section.system-wide-alert": "Allarme di sistema", // "system-wide-alert.form.header": "System-wide Alert", - // TODO New key - Add a translation - "system-wide-alert.form.header": "System-wide Alert", + "system-wide-alert.form.header": "Allarme di sistema", // "system-wide-alert-form.retrieval.error": "Something went wrong retrieving the system-wide alert", - // TODO New key - Add a translation - "system-wide-alert-form.retrieval.error": "Something went wrong retrieving the system-wide alert", + "system-wide-alert-form.retrieval.error": "Qualcosa è andato storto nel recupero dell'allarme di sistema", // "system-wide-alert.form.cancel": "Cancel", - // TODO New key - Add a translation - "system-wide-alert.form.cancel": "Cancel", + "system-wide-alert.form.cancel": "Annulla", // "system-wide-alert.form.save": "Save", - // TODO New key - Add a translation - "system-wide-alert.form.save": "Save", + "system-wide-alert.form.save": "Salva", // "system-wide-alert.form.label.active": "ACTIVE", - // TODO New key - Add a translation - "system-wide-alert.form.label.active": "ACTIVE", + "system-wide-alert.form.label.active": "ATTIVO", // "system-wide-alert.form.label.inactive": "INACTIVE", - // TODO New key - Add a translation - "system-wide-alert.form.label.inactive": "INACTIVE", + "system-wide-alert.form.label.inactive": "DISATTIVO", // "system-wide-alert.form.error.message": "The system wide alert must have a message", - // TODO New key - Add a translation - "system-wide-alert.form.error.message": "The system wide alert must have a message", + "system-wide-alert.form.error.message": "L'allarme di sistema deve avere un messaggio", // "system-wide-alert.form.label.message": "Alert message", - // TODO New key - Add a translation - "system-wide-alert.form.label.message": "Alert message", + "system-wide-alert.form.label.message": "Messaggio di allarme", // "system-wide-alert.form.label.countdownTo.enable": "Enable a countdown timer", - // TODO New key - Add a translation - "system-wide-alert.form.label.countdownTo.enable": "Enable a countdown timer", + "system-wide-alert.form.label.countdownTo.enable": "Attiva un conto alla rovescia", // "system-wide-alert.form.label.countdownTo.hint": "Hint: Set a countdown timer. When enabled, a date can be set in the future and the system-wide alert banner will perform a countdown to the set date. When this timer ends, it will disappear from the alert. The server will NOT be automatically stopped.", - // TODO New key - Add a translation - "system-wide-alert.form.label.countdownTo.hint": "Hint: Set a countdown timer. When enabled, a date can be set in the future and the system-wide alert banner will perform a countdown to the set date. When this timer ends, it will disappear from the alert. The server will NOT be automatically stopped.", + "system-wide-alert.form.label.countdownTo.hint": "Suggerimento: Imposta un conto alla rovescia. Se abilitato, è possibile impostare una data futura e il banner di allarme di sistema eseguirà un conto alla rovescia fino alla data impostata. Quando il timer terminerà, l'avviso scomparirà. Il server NON verrà arrestato automaticamente.", // "system-wide-alert.form.label.preview": "System-wide alert preview", - // TODO New key - Add a translation - "system-wide-alert.form.label.preview": "System-wide alert preview", + "system-wide-alert.form.label.preview": "Anteprima dell'allarme di sistema", // "system-wide-alert.form.update.success": "The system-wide alert was successfully updated", - // TODO New key - Add a translation - "system-wide-alert.form.update.success": "The system-wide alert was successfully updated", + "system-wide-alert.form.update.success": "L'allarme di sistema è stato aggiornato con successo", // "system-wide-alert.form.update.error": "Something went wrong when updating the system-wide alert", - // TODO New key - Add a translation - "system-wide-alert.form.update.error": "Something went wrong when updating the system-wide alert", + "system-wide-alert.form.update.error": "Qualcosa è andato storto durante l'aggiornamento dell'allarme di sistema", // "system-wide-alert.form.create.success": "The system-wide alert was successfully created", - // TODO New key - Add a translation - "system-wide-alert.form.create.success": "The system-wide alert was successfully created", + "system-wide-alert.form.create.success": "L'allarme di sistema è stato creato con successo", // "system-wide-alert.form.create.error": "Something went wrong when creating the system-wide alert", - // TODO New key - Add a translation - "system-wide-alert.form.create.error": "Something went wrong when creating the system-wide alert", + "system-wide-alert.form.create.error": "Qualcosa è andato storto nella creazione dell'allarme di sistema", // "admin.system-wide-alert.breadcrumbs": "System-wide Alerts", - // TODO New key - Add a translation - "admin.system-wide-alert.breadcrumbs": "System-wide Alerts", + "admin.system-wide-alert.breadcrumbs": "Allarmi di sistema", // "admin.system-wide-alert.title": "System-wide Alerts", - // TODO New key - Add a translation - "admin.system-wide-alert.title": "System-wide Alerts", + "admin.system-wide-alert.title": "Allarmi di sistema", } From 32fc28ec54af589b5813321490703896b1843fff Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Tue, 26 Sep 2023 14:44:13 +0200 Subject: [PATCH 074/196] fix dev mode issue where retrieving the login options fails --- .../core/server-check/server-check.guard.spec.ts | 14 ++++++++++---- src/app/core/server-check/server-check.guard.ts | 6 ++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/app/core/server-check/server-check.guard.spec.ts b/src/app/core/server-check/server-check.guard.spec.ts index f18b3867538..044609ef427 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -20,7 +20,8 @@ describe('ServerCheckGuard', () => { }); rootDataServiceStub = jasmine.createSpyObj('RootDataService', { checkServerAvailability: jasmine.createSpy('checkServerAvailability'), - invalidateRootCache: jasmine.createSpy('invalidateRootCache') + invalidateRootCache: jasmine.createSpy('invalidateRootCache'), + findRoot: jasmine.createSpy('findRoot') }); redirectUrlTree = new UrlTree(); router = { @@ -63,18 +64,23 @@ describe('ServerCheckGuard', () => { }); describe(`listenForRouteChanges`, () => { - it(`should invalidate the root cache when the method is first called, and then on every NavigationStart event`, () => { + it(`should retrieve the root endpoint, without using the cache, when the method is first called`, () => { testScheduler.run(() => { guard.listenForRouteChanges(); - expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(1); + expect(rootDataServiceStub.findRoot).toHaveBeenCalledWith(false); + }); + }); + it(`should invalidate the root cache on every NavigationStart event`, () => { + testScheduler.run(() => { + guard.listenForRouteChanges(); eventSubject.next(new NavigationStart(1,'')); eventSubject.next(new NavigationEnd(1,'', '')); eventSubject.next(new NavigationStart(2,'')); eventSubject.next(new NavigationEnd(2,'', '')); eventSubject.next(new NavigationStart(3,'')); }); - expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(4); + expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(3); }); }); }); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index 1cea5f36bab..65ca2b0c498 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -53,8 +53,10 @@ export class ServerCheckGuard implements CanActivateChild { */ listenForRouteChanges(): void { // we'll always be too late for the first NavigationStart event with the router subscribe below, - // so this statement is for the very first route operation - this.rootDataService.invalidateRootCache(); + // so this statement is for the very first route operation. A `find` without using the cache, + // rather than an invalidateRootCache, because invalidating as the app is bootstrapping can + // break other features + this.rootDataService.findRoot(false); this.router.events.pipe( filter(event => event instanceof NavigationStart), From 6a99185214f836271fe42d6ad73a14dbeb95a648 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Tue, 26 Sep 2023 16:56:07 +0200 Subject: [PATCH 075/196] roll back unintended change to the responseMsToLive for RootDataservice --- src/app/core/data/root-data.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/data/root-data.service.ts b/src/app/core/data/root-data.service.ts index 88cffdf6cf2..5431a2d1fb2 100644 --- a/src/app/core/data/root-data.service.ts +++ b/src/app/core/data/root-data.service.ts @@ -25,7 +25,7 @@ export class RootDataService extends BaseDataService { protected objectCache: ObjectCacheService, protected halService: HALEndpointService, ) { - super('', requestService, rdbService, objectCache, halService, 60 * 1000); + super('', requestService, rdbService, objectCache, halService, 6 * 60 * 60 * 1000); } /** From d0b4e15db42298aec6803d640916c951b97eab55 Mon Sep 17 00:00:00 2001 From: Jens Vannerum Date: Fri, 29 Sep 2023 15:54:34 +0200 Subject: [PATCH 076/196] Fix browse by visual bug --- .../browse-by-metadata-page.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts index 113bc67c924..75dbfcfc82a 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.ts @@ -161,7 +161,11 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy { this.value = ''; } - if (typeof params.startsWith === 'string'){ + if (params.startsWith === undefined || params.startsWith === '') { + this.startsWith = undefined; + } + + if (typeof params.startsWith === 'string'){ this.startsWith = params.startsWith.trim(); } From 2ca2a3881f701b7668258c8607e1180ebfeb9828 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 29 Sep 2023 21:40:29 +0200 Subject: [PATCH 077/196] Added new variables for the expandable navbar section --- .../expandable-navbar-section.component.scss | 7 ++++++- src/styles/_custom_variables.scss | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.scss b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.scss index 1bc80d32c57..28db981f115 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.scss +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.scss @@ -6,15 +6,20 @@ } .dropdown-menu { - background-color: var(--ds-navbar-bg); + background-color: var(--ds-expandable-navbar-bg); overflow: hidden; min-width: 100%; border-top-left-radius: 0; border-top-right-radius: 0; ::ng-deep a.nav-link { + color: var(--ds-expandable-navbar-link-color) !important; padding-right: var(--bs-spacer); padding-left: var(--bs-spacer); white-space: nowrap; + + &:hover, &:focus { + color: var(--ds-expandable-navbar-link-color-hover) !important; + } } } diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 4abe91c368c..778ef6e9e3a 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -29,6 +29,9 @@ --ds-header-navbar-border-bottom-color: #{$gray-400}; --ds-navbar-link-color: #{$cyan}; --ds-navbar-link-color-hover: #{darken($cyan, 15%)}; + --ds-expandable-navbar-bg: var(--ds-navbar-bg); + --ds-expandable-navbar-link-color: var(--ds-navbar-link-color); + --ds-expandable-navbar-link-color-hover: var(--ds-navbar-link-color-hover); $admin-sidebar-bg: darken(#2B4E72, 17%); $admin-sidebar-active-bg: darken($admin-sidebar-bg, 3%); From 9f2a1d048bd3a9a413cc15492ce6bbf6c4dd65b2 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Tue, 26 Sep 2023 11:50:29 +0200 Subject: [PATCH 078/196] Use gap instead of individual paddings for header icons --- .../context-help-toggle.component.ts | 19 ++++++++--- src/app/header/header.component.html | 4 +-- src/app/header/header.component.scss | 4 +++ src/app/header/header.component.spec.ts | 5 ++- src/app/header/header.component.ts | 14 +++++--- .../search-navbar.component.html | 4 +-- .../search-navbar.component.scss | 1 + src/app/shared/animations/slide.ts | 2 +- .../auth-nav-menu.component.html | 4 +-- .../impersonate-navbar.component.html | 2 +- .../impersonate-navbar.component.spec.ts | 3 +- .../impersonate-navbar.component.ts | 33 ++++++++++++------- .../lang-switch/lang-switch.component.html | 2 +- .../lang-switch/lang-switch.component.ts | 8 +++-- src/styles/_global-styles.scss | 26 +++++++++++++++ 15 files changed, 97 insertions(+), 34 deletions(-) diff --git a/src/app/header/context-help-toggle/context-help-toggle.component.ts b/src/app/header/context-help-toggle/context-help-toggle.component.ts index 6685df71063..de7c994faa5 100644 --- a/src/app/header/context-help-toggle/context-help-toggle.component.ts +++ b/src/app/header/context-help-toggle/context-help-toggle.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ElementRef } from '@angular/core'; import { ContextHelpService } from '../../shared/context-help.service'; -import { Observable } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; /** @@ -15,12 +15,23 @@ import { map } from 'rxjs/operators'; export class ContextHelpToggleComponent implements OnInit { buttonVisible$: Observable; + subscriptions: Subscription[] = []; + constructor( - private contextHelpService: ContextHelpService, - ) { } + protected elRef: ElementRef, + protected contextHelpService: ContextHelpService, + ) { + } ngOnInit(): void { this.buttonVisible$ = this.contextHelpService.tooltipCount$().pipe(map(x => x > 0)); + this.subscriptions.push(this.buttonVisible$.subscribe((showContextHelpToggle: boolean) => { + if (showContextHelpToggle) { + this.elRef.nativeElement.classList.remove('d-none'); + } else { + this.elRef.nativeElement.classList.add('d-none'); + } + })); } onClick() { diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index 4d879835235..425f52c6017 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -11,8 +11,8 @@ -
- diff --git a/src/app/search-navbar/search-navbar.component.scss b/src/app/search-navbar/search-navbar.component.scss index cf46c25d914..a276482b535 100644 --- a/src/app/search-navbar/search-navbar.component.scss +++ b/src/app/search-navbar/search-navbar.component.scss @@ -12,6 +12,7 @@ input[type="text"] { cursor: pointer; position: sticky; top: 0; + border: 0 !important; color: var(--ds-header-icon-color); &:hover, &:focus { diff --git a/src/app/shared/animations/slide.ts b/src/app/shared/animations/slide.ts index 310ddbbfde9..9d18817ee39 100644 --- a/src/app/shared/animations/slide.ts +++ b/src/app/shared/animations/slide.ts @@ -55,7 +55,7 @@ export const slideSidebarPadding = trigger('slideSidebarPadding', [ export const expandSearchInput = trigger('toggleAnimation', [ state('collapsed', style({ - width: '30px', + width: '0', opacity: '0' })), state('expanded', style({ diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.html b/src/app/shared/auth-nav-menu/auth-nav-menu.component.html index 05f502afa1b..bbc4fa3ca70 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.html +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.html @@ -2,7 +2,7 @@ diff --git a/src/app/shared/impersonate-navbar/impersonate-navbar.component.html b/src/app/shared/impersonate-navbar/impersonate-navbar.component.html index 9f2b66694b7..9581ba8ea87 100644 --- a/src/app/shared/impersonate-navbar/impersonate-navbar.component.html +++ b/src/app/shared/impersonate-navbar/impersonate-navbar.component.html @@ -1,4 +1,4 @@ -
- + From 58d31dd73f9762a341e774df261d909d97c4b3e2 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Tue, 26 Sep 2023 22:16:25 +0200 Subject: [PATCH 080/196] Applied same gap between header icons in the dspace theme and made the search field non-focusable when collapsed --- src/app/header/header.component.scss | 3 ++- src/app/search-navbar/search-navbar.component.html | 5 ++++- src/themes/dspace/app/header/header.component.html | 2 +- src/themes/dspace/app/header/header.component.scss | 6 ++++++ src/themes/dspace/app/navbar/navbar.component.html | 12 +++++++----- src/themes/dspace/app/navbar/navbar.component.scss | 6 ++++++ 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/app/header/header.component.scss b/src/app/header/header.component.scss index 8a11a651956..871adf289c6 100644 --- a/src/app/header/header.component.scss +++ b/src/app/header/header.component.scss @@ -22,5 +22,6 @@ .navbar { display: flex; - gap: 0.25rem; + gap: calc(var(--bs-spacer) / 3); + align-items: center; } diff --git a/src/app/search-navbar/search-navbar.component.html b/src/app/search-navbar/search-navbar.component.html index 8a98d4c44c4..02a98905021 100644 --- a/src/app/search-navbar/search-navbar.component.html +++ b/src/app/search-navbar/search-navbar.component.html @@ -3,7 +3,10 @@ + class="bg-transparent position-absolute form-control dropdown-menu-right pl-1 pr-4" + [class.display]="searchExpanded ? 'inline-block' : 'none'" + [tabIndex]="searchExpanded ? 0 : -1" + [attr.data-test]="'header-search-box' | dsBrowserOnly"> diff --git a/src/themes/dspace/app/header/header.component.html b/src/themes/dspace/app/header/header.component.html index 87a26ca326a..4b0046bc834 100644 --- a/src/themes/dspace/app/header/header.component.html +++ b/src/themes/dspace/app/header/header.component.html @@ -5,7 +5,7 @@ -
+ - - - - - +
diff --git a/src/themes/dspace/app/navbar/navbar.component.scss b/src/themes/dspace/app/navbar/navbar.component.scss index d3aea9f0780..2e1b4a04f92 100644 --- a/src/themes/dspace/app/navbar/navbar.component.scss +++ b/src/themes/dspace/app/navbar/navbar.component.scss @@ -54,3 +54,9 @@ a.navbar-brand img { color: var(--ds-navbar-link-color-hover); } } + +.navbar-buttons { + display: flex; + gap: calc(var(--bs-spacer) / 3); + align-items: center; +} From fa56d5dfb719c14d99080ef8fe208b5ee129c72f Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Thu, 28 Sep 2023 11:50:24 +0200 Subject: [PATCH 081/196] Fixed invalid html structure the ExpandableNavbarSectionComponent had an ul tag containing non-li tags --- .../admin-sidebar-section/admin-sidebar-section.component.ts | 3 +-- src/app/admin/admin-sidebar/admin-sidebar.component.html | 4 ++-- .../expandable-admin-sidebar-section.component.ts | 3 +-- .../expandable-navbar-section.component.html | 4 ++-- .../expandable-navbar-section.component.ts | 2 -- .../themed-expandable-navbar-section.component.ts | 3 +-- src/app/navbar/navbar-section/navbar-section.component.ts | 3 +-- src/app/navbar/navbar.component.html | 4 ++-- .../dso-edit-menu-expandable-section.component.ts | 1 - .../dso-edit-menu-section/dso-edit-menu-section.component.ts | 1 - src/themes/dspace/app/navbar/navbar.component.html | 4 ++-- 11 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts index d6cd803622b..b195526d1c0 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component.ts @@ -12,8 +12,7 @@ import { Router } from '@angular/router'; * Represents a non-expandable section in the admin sidebar */ @Component({ - /* eslint-disable @angular-eslint/component-selector */ - selector: 'li[ds-admin-sidebar-section]', + selector: 'ds-admin-sidebar-section', templateUrl: './admin-sidebar-section.component.html', styleUrls: ['./admin-sidebar-section.component.scss'], diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.html b/src/app/admin/admin-sidebar/admin-sidebar.component.html index ef220b834ba..fe7e5595ab0 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.html +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.html @@ -26,10 +26,10 @@

{{ 'menu.header.admin' | translate }}

- +
  • - +
  • diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts index 5bc69bcbb4e..d32fa46a327 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts @@ -4,7 +4,6 @@ import { MenuService } from '../../shared/menu/menu.service'; import { slide } from '../../shared/animations/slide'; import { first } from 'rxjs/operators'; import { HostWindowService } from '../../shared/host-window.service'; -import { rendersSectionForMenu } from '../../shared/menu/menu-section.decorator'; import { MenuID } from '../../shared/menu/menu-id.model'; /** @@ -16,7 +15,6 @@ import { MenuID } from '../../shared/menu/menu-id.model'; styleUrls: ['./expandable-navbar-section.component.scss'], animations: [slide] }) -@rendersSectionForMenu(MenuID.PUBLIC, true) export class ExpandableNavbarSectionComponent extends NavbarSectionComponent implements OnInit { /** * This section resides in the Public Navbar diff --git a/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts index e33dca41049..8f474e99490 100644 --- a/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts +++ b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts @@ -8,8 +8,7 @@ import { MenuID } from '../../shared/menu/menu-id.model'; * Themed wrapper for ExpandableNavbarSectionComponent */ @Component({ - /* eslint-disable @angular-eslint/component-selector */ - selector: 'li[ds-themed-expandable-navbar-section]', + selector: 'ds-themed-expandable-navbar-section', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', }) diff --git a/src/app/navbar/navbar-section/navbar-section.component.ts b/src/app/navbar/navbar-section/navbar-section.component.ts index 9f75a96f6e7..9b86aa10f2b 100644 --- a/src/app/navbar/navbar-section/navbar-section.component.ts +++ b/src/app/navbar/navbar-section/navbar-section.component.ts @@ -8,8 +8,7 @@ import { MenuID } from '../../shared/menu/menu-id.model'; * Represents a non-expandable section in the navbar */ @Component({ - /* eslint-disable @angular-eslint/component-selector */ - selector: 'li[ds-navbar-section]', + selector: 'ds-navbar-section', templateUrl: './navbar-section.component.html', styleUrls: ['./navbar-section.component.scss'] }) diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index bc1e04f5130..edfc4bb8ee0 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -8,9 +8,9 @@
  • - +
  • - +
  • diff --git a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts index 8e4a7008afe..1925099418a 100644 --- a/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts +++ b/src/app/shared/dso-page/dso-edit-menu/dso-edit-expandable-menu-section/dso-edit-menu-expandable-section.component.ts @@ -13,7 +13,6 @@ import { hasValue } from '../../../empty.util'; * Represents an expandable section in the dso edit menus */ @Component({ - /* tslint:disable:component-selector */ selector: 'ds-dso-edit-menu-expandable-section', templateUrl: './dso-edit-menu-expandable-section.component.html', styleUrls: ['./dso-edit-menu-expandable-section.component.scss'], diff --git a/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.ts b/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.ts index af3381ef716..060049ef5fc 100644 --- a/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.ts +++ b/src/app/shared/dso-page/dso-edit-menu/dso-edit-menu-section/dso-edit-menu-section.component.ts @@ -10,7 +10,6 @@ import { MenuSection } from '../../../menu/menu-section.model'; * Represents a non-expandable section in the dso edit menus */ @Component({ - /* tslint:disable:component-selector */ selector: 'ds-dso-edit-menu-section', templateUrl: './dso-edit-menu-section.component.html', styleUrls: ['./dso-edit-menu-section.component.scss'] diff --git a/src/themes/dspace/app/navbar/navbar.component.html b/src/themes/dspace/app/navbar/navbar.component.html index d9631aad182..c14671cf683 100644 --- a/src/themes/dspace/app/navbar/navbar.component.html +++ b/src/themes/dspace/app/navbar/navbar.component.html @@ -10,9 +10,9 @@
  • - +
  • - +
  • diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts index b3e686c0123..704a92d0f9f 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts @@ -7,10 +7,9 @@ import { of as observableOf, Subscription, BehaviorSubject, - combineLatest as observableCombineLatest, - ObservedValueOf, + combineLatest as observableCombineLatest } from 'rxjs'; -import { defaultIfEmpty, map, mergeMap, switchMap, take } from 'rxjs/operators'; +import { defaultIfEmpty, map, switchMap, take } from 'rxjs/operators'; import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { EPersonDataService } from '../../../../core/eperson/eperson-data.service'; @@ -18,10 +17,8 @@ import { GroupDataService } from '../../../../core/eperson/group-data.service'; import { EPerson } from '../../../../core/eperson/models/eperson.model'; import { Group } from '../../../../core/eperson/models/group.model'; import { - getFirstSucceededRemoteData, getFirstCompletedRemoteData, - getAllCompletedRemoteData, - getRemoteDataPayload + getAllCompletedRemoteData } from '../../../../core/shared/operators'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model'; @@ -191,14 +188,9 @@ export class MembersListComponent implements OnInit, OnDestroy { }), switchMap((epersonListRD: RemoteData>) => { const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => { - const dto$: Observable = observableCombineLatest( - this.isMemberOfGroup(member), (isMember: ObservedValueOf>) => { - const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); - epersonDtoModel.eperson = member; - epersonDtoModel.memberOfGroup = isMember; - return epersonDtoModel; - }); - return dto$; + const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); + epersonDtoModel.eperson = member; + return observableOf(epersonDtoModel); })]); return dtos$.pipe(defaultIfEmpty([]), map((dtos: EpersonDtoModel[]) => { return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); @@ -209,29 +201,6 @@ export class MembersListComponent implements OnInit, OnDestroy { })); } - /** - * Whether the given ePerson is a member of the group currently being edited - * @param possibleMember EPerson that is a possible member (being tested) of the group currently being edited - */ - isMemberOfGroup(possibleMember: EPerson): Observable { - return this.groupDataService.getActiveGroup().pipe(take(1), - mergeMap((group: Group) => { - if (group != null) { - return this.ePersonDataService.findListByHref(group._links.epersons.href, { - currentPage: 1, - elementsPerPage: 9999 - }) - .pipe( - getFirstSucceededRemoteData(), - getRemoteDataPayload(), - map((listEPeopleInGroup: PaginatedList) => listEPeopleInGroup.page.filter((ePersonInList: EPerson) => ePersonInList.id === possibleMember.id)), - map((epeople: EPerson[]) => epeople.length > 0)); - } else { - return observableOf(false); - } - })); - } - /** * Unsubscribe from a subscription if it's still subscribed, and remove it from the map of * active subscriptions @@ -251,7 +220,6 @@ export class MembersListComponent implements OnInit, OnDestroy { * @param ePerson EPerson we want to delete as member from group that is currently being edited */ deleteMemberFromGroup(ePerson: EpersonDtoModel) { - ePerson.memberOfGroup = false; this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => { if (activeGroup != null) { const response = this.groupDataService.deleteMemberFromGroup(activeGroup, ePerson.eperson); @@ -267,7 +235,6 @@ export class MembersListComponent implements OnInit, OnDestroy { * @param ePerson EPerson we want to add as member to group that is currently being edited */ addMemberToGroup(ePerson: EpersonDtoModel) { - ePerson.memberOfGroup = true; this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => { if (activeGroup != null) { const response = this.groupDataService.addMemberToGroup(activeGroup, ePerson.eperson); @@ -321,14 +288,9 @@ export class MembersListComponent implements OnInit, OnDestroy { }), switchMap((epersonListRD: RemoteData>) => { const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => { - const dto$: Observable = observableCombineLatest( - this.isMemberOfGroup(member), (isMember: ObservedValueOf>) => { - const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); - epersonDtoModel.eperson = member; - epersonDtoModel.memberOfGroup = isMember; - return epersonDtoModel; - }); - return dto$; + const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); + epersonDtoModel.eperson = member; + return observableOf(epersonDtoModel); })]); return dtos$.pipe(defaultIfEmpty([]), map((dtos: EpersonDtoModel[]) => { return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); From bffae54b10ea7a4c883cb25512f9c9ac4949f97a Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 25 Sep 2023 16:34:04 -0500 Subject: [PATCH 127/196] Remove unnecessary EpersonDtoModel. Rework code and tests to use EPerson instead. --- .../members-list/members-list.component.html | 48 +++--- .../members-list.component.spec.ts | 156 ++++++++---------- .../members-list/members-list.component.ts | 62 +++---- 3 files changed, 116 insertions(+), 150 deletions(-) diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html index b90a3e405b1..0f5010e08eb 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html @@ -37,10 +37,10 @@ - - + + - - + + diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 7392b3da7ac..f6630d594db 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3242,6 +3242,8 @@ "process.overview.delete": "Delete {{count}} processes", + "process.overview.delete-process": "Delete process", + "process.overview.delete.clear": "Clear delete selection", "process.overview.delete.processing": "{{count}} process(es) are being deleted. Please wait for the deletion to fully complete. Note that this can take a while.", From 52c0977489063689dba99caf004e4120a85e9fc9 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Tue, 28 Nov 2023 00:20:35 +0100 Subject: [PATCH 169/196] Fix Create a new process page accessibility issues - Added missing aria-label to delete buttons - Moved hardcoded translation to translation files - Fix color contrast issues on buttons - Fix minor alignment issues - Added missing aria labels to input and select elements --- .../process-page/form/process-form.component.html | 6 +++--- .../parameter-select/parameter-select.component.html | 12 ++++++++---- .../parameter-select.component.spec.ts | 7 +++++-- .../boolean-value-input.component.html | 2 +- .../boolean-value-input.component.spec.ts | 5 ++++- .../date-value-input/date-value-input.component.html | 4 ++-- .../date-value-input/date-value-input.component.scss | 5 +++++ .../file-value-input/file-value-input.component.html | 2 +- .../string-value-input.component.html | 4 ++-- .../string-value-input.component.scss | 5 +++++ src/assets/i18n/en.json5 | 8 ++++++++ 11 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/app/process-page/form/process-form.component.html b/src/app/process-page/form/process-form.component.html index ce6d62efec3..c55592f3e77 100644 --- a/src/app/process-page/form/process-form.component.html +++ b/src/app/process-page/form/process-form.component.html @@ -3,12 +3,12 @@

    {{headerKey | translate}}

    -
    +
    - - + {{ 'process.new.cancel' | translate }} +
    diff --git a/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.html b/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.html index 4bf06bbadec..1f1559b50bd 100644 --- a/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.html +++ b/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.html @@ -1,16 +1,20 @@ -
    +
    - - + +
    diff --git a/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.spec.ts b/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.spec.ts index 56fece56b40..818a292e338 100644 --- a/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.spec.ts +++ b/src/app/process-page/form/process-parameters/parameter-select/parameter-select.component.spec.ts @@ -1,5 +1,5 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; - +import { TranslateModule } from '@ngx-translate/core'; import { ParameterSelectComponent } from './parameter-select.component'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { FormsModule } from '@angular/forms'; @@ -33,7 +33,10 @@ describe('ParameterSelectComponent', () => { beforeEach(waitForAsync(() => { init(); TestBed.configureTestingModule({ - imports: [FormsModule], + imports: [ + FormsModule, + TranslateModule.forRoot(), + ], declarations: [ParameterSelectComponent], schemas: [NO_ERRORS_SCHEMA] }) diff --git a/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.html b/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.html index 914b331413b..68171a23b29 100644 --- a/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.html +++ b/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.html @@ -1 +1 @@ - + diff --git a/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts b/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts index 38f119ad5bb..76b01b87096 100644 --- a/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts +++ b/src/app/process-page/form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - +import { TranslateModule } from '@ngx-translate/core'; import { BooleanValueInputComponent } from './boolean-value-input.component'; describe('BooleanValueInputComponent', () => { @@ -8,6 +8,9 @@ describe('BooleanValueInputComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot(), + ], declarations: [BooleanValueInputComponent] }) .compileComponents(); diff --git a/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html b/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html index f367d3779f2..4e77f4ed1b9 100644 --- a/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html +++ b/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html @@ -1,6 +1,6 @@ - +
    + class="alert alert-danger validation-error mb-0">
    {{'process.new.parameter.string.required' | translate}}
    diff --git a/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.scss b/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.scss index e69de29bb2d..8c6325f95a1 100644 --- a/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.scss +++ b/src/app/process-page/form/process-parameters/parameter-value-input/date-value-input/date-value-input.component.scss @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: column; + gap: calc(var(--bs-spacer) / 2); +} diff --git a/src/app/process-page/form/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html b/src/app/process-page/form/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html index cac3fbd82d5..a741eacc867 100644 --- a/src/app/process-page/form/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html +++ b/src/app/process-page/form/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html @@ -1,5 +1,5 @@
    -
    \ No newline at end of file +
    diff --git a/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.component.html b/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.component.html index 0a2e9f0f926..45d8ed5d11c 100644 --- a/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.component.html +++ b/src/app/admin/admin-registries/bitstream-formats/bitstream-formats.component.html @@ -2,7 +2,7 @@
    - +

    {{'admin.registries.bitstream-formats.description' | translate}}

    {{'admin.registries.bitstream-formats.create.new' | translate}}

    @@ -19,7 +19,7 @@
    {{'quality-assurance.event.table.trust' | translate}}{{'quality-assurance.event.table.publication' | translate}}{{'quality-assurance.event.table.details' | translate}}{{'quality-assurance.event.table.project-details' | translate}}{{'quality-assurance.event.table.actions' | translate}}{{'quality-assurance.event.table.trust' | translate}}{{'quality-assurance.event.table.publication' | translate}} + {{'quality-assurance.event.table.details' | translate}} + + {{'quality-assurance.event.table.project-details' | translate}} + {{'quality-assurance.event.table.actions' | translate}}
    -

    {{'quality-assurance.event.table.pidtype' | translate}} {{eventElement.event.message.type}}

    +

    {{'quality-assurance.event.table.pidtype' | translate}} {{eventElement.event.message.type}}

    {{'quality-assurance.event.table.pidvalue' | translate}}
    {{eventElement.event.message.value}} @@ -82,18 +87,19 @@

    {{eventElement.event.message.title}}

    - {{'quality-assurance.event.table.acronym' | translate}} {{eventElement.event.message.acronym}}
    - {{'quality-assurance.event.table.code' | translate}} {{eventElement.event.message.code}}
    - {{'quality-assurance.event.table.funder' | translate}} {{eventElement.event.message.funder}}
    - {{'quality-assurance.event.table.fundingProgram' | translate}} {{eventElement.event.message.fundingProgram}}
    - {{'quality-assurance.event.table.jurisdiction' | translate}} {{eventElement.event.message.jurisdiction}} + {{'quality-assurance.event.table.acronym' | translate}} {{eventElement.event.message.acronym}}
    + {{'quality-assurance.event.table.code' | translate}} {{eventElement.event.message.code}}
    + {{'quality-assurance.event.table.funder' | translate}} {{eventElement.event.message.funder}}
    + {{'quality-assurance.event.table.fundingProgram' | translate}} {{eventElement.event.message.fundingProgram}}
    + {{'quality-assurance.event.table.jurisdiction' | translate}} {{eventElement.event.message.jurisdiction}}


    {{(eventElement.hasProject ? 'quality-assurance.event.project.found' : 'quality-assurance.event.project.notFound') | translate}} {{eventElement.handle}}
    -
    -
    +
    diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss index b38da70f376..29c16328c35 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss @@ -1,5 +1,12 @@ -.button-rows { - min-width: 200px; +.button-col, .trust-col { + width: 15%; +} + +.title-col { + width: 30%; +} +.content-col { + width: 40%; } .button-width { diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts index 41358b20a52..f0109f5f662 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts @@ -5,16 +5,18 @@ import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/t import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { of as observableOf } from 'rxjs'; -import { QualityAssuranceEventRestService } from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-rest.service'; +import { + QualityAssuranceEventRestService +} from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-rest.service'; import { QualityAssuranceEventsComponent } from './quality-assurance-events.component'; import { getMockQualityAssuranceEventRestService, ItemMockPid10, ItemMockPid8, ItemMockPid9, + NotificationsMockDspaceObject, qualityAssuranceEventObjectMissingProjectFound, - qualityAssuranceEventObjectMissingProjectNotFound, - NotificationsMockDspaceObject + qualityAssuranceEventObjectMissingProjectNotFound } from '../../../shared/mocks/notifications.mock'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; @@ -22,10 +24,12 @@ import { getMockTranslateService } from '../../../shared/mocks/translate.service import { createTestComponent } from '../../../shared/testing/utils.test'; import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { QualityAssuranceEventObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; +import { + QualityAssuranceEventObject +} from '../../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; import { QualityAssuranceEventData } from '../project-entry-import-modal/project-entry-import-modal.component'; import { TestScheduler } from 'rxjs/testing'; -import { getTestScheduler } from 'jasmine-marbles'; +import { cold, getTestScheduler } from 'jasmine-marbles'; import { followLink } from '../../../shared/utils/follow-link-config.model'; import { PageInfo } from '../../../core/shared/page-info.model'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; @@ -37,7 +41,7 @@ import { import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; -import {FindListOptions} from '../../../core/data/find-list-options.model'; +import { FindListOptions } from '../../../core/data/find-list-options.model'; describe('QualityAssuranceEventsComponent test suite', () => { let fixture: ComponentFixture; @@ -156,18 +160,16 @@ describe('QualityAssuranceEventsComponent test suite', () => { compAsAny = null; }); - describe('setEventUpdated', () => { - it('should update events', () => { - const expected = [ - getQualityAssuranceEventData1(), - getQualityAssuranceEventData2() - ]; - scheduler.schedule(() => { - compAsAny.setEventUpdated(events); + describe('fetchEvents', () => { + it('should fetch events', () => { + const result = compAsAny.fetchEvents(events); + const expected = cold('(a|)', { + a: [ + getQualityAssuranceEventData1(), + getQualityAssuranceEventData2() + ] }); - scheduler.flush(); - - expect(comp.eventsUpdated$.value).toEqual(expected); + expect(result).toBeObservable(expected); }); }); @@ -229,7 +231,10 @@ describe('QualityAssuranceEventsComponent test suite', () => { describe('executeAction', () => { it('should call getQualityAssuranceEvents on 200 response from REST', () => { const action = 'ACCEPTED'; - spyOn(compAsAny, 'getQualityAssuranceEvents'); + spyOn(compAsAny, 'getQualityAssuranceEvents').and.returnValue(observableOf([ + getQualityAssuranceEventData1(), + getQualityAssuranceEventData2() + ])); qualityAssuranceEventRestServiceStub.patchEvent.and.returnValue(createSuccessfulRemoteDataObject$({})); scheduler.schedule(() => { @@ -279,7 +284,7 @@ describe('QualityAssuranceEventsComponent test suite', () => { }); describe('getQualityAssuranceEvents', () => { - it('should call the "qualityAssuranceEventRestService.getEventsByTopic" to take data and "setEventUpdated" to populate eventData', () => { + it('should call the "qualityAssuranceEventRestService.getEventsByTopic" to take data and "fetchEvents" to populate eventData', () => { comp.paginationConfig = new PaginationComponentOptions(); comp.paginationConfig.currentPage = 1; comp.paginationConfig.pageSize = 20; @@ -292,7 +297,7 @@ describe('QualityAssuranceEventsComponent test suite', () => { const pageInfo = new PageInfo({ elementsPerPage: comp.paginationConfig.pageSize, - totalElements: 0, + totalElements: 2, totalPages: 1, currentPage: comp.paginationConfig.currentPage }); @@ -303,10 +308,13 @@ describe('QualityAssuranceEventsComponent test suite', () => { const paginatedList = buildPaginatedList(pageInfo, array); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); qualityAssuranceEventRestServiceStub.getEventsByTopic.and.returnValue(observableOf(paginatedListRD)); - spyOn(compAsAny, 'setEventUpdated'); + spyOn(compAsAny, 'fetchEvents').and.returnValue(observableOf([ + getQualityAssuranceEventData1(), + getQualityAssuranceEventData2() + ])); scheduler.schedule(() => { - compAsAny.getQualityAssuranceEvents(); + compAsAny.getQualityAssuranceEvents().subscribe(); }); scheduler.flush(); @@ -315,7 +323,7 @@ describe('QualityAssuranceEventsComponent test suite', () => { options, followLink('target'),followLink('related') ); - expect(compAsAny.setEventUpdated).toHaveBeenCalled(); + expect(compAsAny.fetchEvents).toHaveBeenCalled(); }); }); diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts index 9f33a022251..f78798ac250 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts @@ -3,8 +3,8 @@ import { ActivatedRoute } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, from, Observable, of as observableOf, Subscription } from 'rxjs'; -import { distinctUntilChanged, map, mergeMap, scan, switchMap, take } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest, from, Observable, of, Subscription } from 'rxjs'; +import { distinctUntilChanged, last, map, mergeMap, scan, switchMap, take, tap } from 'rxjs/operators'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; @@ -19,7 +19,7 @@ import { import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { Metadata } from '../../../core/shared/metadata.utils'; import { followLink } from '../../../shared/utils/follow-link-config.model'; -import { hasValue, isEmpty } from '../../../shared/empty.util'; +import { hasValue } from '../../../shared/empty.util'; import { ItemSearchResult } from '../../../shared/object-collection/shared/item-search-result.model'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { @@ -28,7 +28,6 @@ import { } from '../project-entry-import-modal/project-entry-import-modal.component'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { PaginationService } from '../../../core/pagination/pagination.service'; -import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { Item } from '../../../core/shared/item.model'; import { FindListOptions } from '../../../core/data/find-list-options.model'; @@ -65,7 +64,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * The total number of Quality Assurance events. * @type {Observable} */ - public totalElements$: Observable; + public totalElements$: BehaviorSubject = new BehaviorSubject(null); /** * The topic of the Quality Assurance events; suitable for displaying. * @type {string} @@ -86,11 +85,6 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * @type {Observable} */ public isEventPageLoading: BehaviorSubject = new BehaviorSubject(false); - /** - * Contains the information about the loading status of the events inside the pagination component. - * @type {Observable} - */ - public isEventLoading: BehaviorSubject = new BehaviorSubject(false); /** * The modal reference. * @type {any} @@ -104,7 +98,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { /** * The FindListOptions object */ - protected defaultConfig: FindListOptions = Object.assign(new FindListOptions(), {sort: this.paginationSortConfig}); + protected defaultConfig: FindListOptions = Object.assign(new FindListOptions(), { sort: this.paginationSortConfig }); /** * Array to track all the component subscriptions. Useful to unsubscribe them with 'onDestroy'. * @type {Array} @@ -138,13 +132,17 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { this.activatedRoute.paramMap.pipe( map((params) => params.get('topicId')), - take(1) - ).subscribe((id: string) => { - const regEx = /!/g; - this.showTopic = id.replace(regEx, '/'); - this.topic = id; + take(1), + switchMap((id: string) => { + const regEx = /!/g; + this.showTopic = id.replace(regEx, '/'); + this.topic = id; + return this.getQualityAssuranceEvents(); + }) + ).subscribe((events: QualityAssuranceEventData[]) => { + console.log(events); + this.eventsUpdated$.next(events); this.isEventPageLoading.next(false); - this.getQualityAssuranceEvents(); }); } @@ -240,20 +238,25 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { public executeAction(action: string, eventData: QualityAssuranceEventData): void { eventData.isRunning = true; this.subs.push( - this.qualityAssuranceEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) - .subscribe((rd: RemoteData) => { - if (rd.isSuccess && rd.statusCode === 200) { + this.qualityAssuranceEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe( + getFirstCompletedRemoteData(), + switchMap((rd: RemoteData) => { + if (rd.hasSucceeded) { this.notificationsService.success( this.translateService.instant('quality-assurance.event.action.saved') ); - this.getQualityAssuranceEvents(); + return this.getQualityAssuranceEvents(); } else { this.notificationsService.error( this.translateService.instant('quality-assurance.event.action.error') ); + return of(this.eventsUpdated$.value); } - eventData.isRunning = false; }) + ).subscribe((events: QualityAssuranceEventData[]) => { + this.eventsUpdated$.next(events); + eventData.isRunning = false; + }) ); } @@ -274,7 +277,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { this.subs.push( this.qualityAssuranceEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) .subscribe((rd: RemoteData) => { - if (rd.isSuccess) { + if (rd.hasSucceeded) { this.notificationsService.success( this.translateService.instant('quality-assurance.event.project.bounded') ); @@ -303,7 +306,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { this.subs.push( this.qualityAssuranceEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) .subscribe((rd: RemoteData) => { - if (rd.isSuccess) { + if (rd.hasSucceeded) { this.notificationsService.success( this.translateService.instant('quality-assurance.event.project.removed') ); @@ -337,12 +340,11 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { return event.pidHref; } - /** * Dispatch the Quality Assurance events retrival. */ - public getQualityAssuranceEvents(): void { - this.paginationService.getFindListOptions(this.paginationConfig.id, this.defaultConfig).pipe( + public getQualityAssuranceEvents(): Observable { + return this.paginationService.getFindListOptions(this.paginationConfig.id, this.defaultConfig).pipe( distinctUntilChanged(), switchMap((options: FindListOptions) => this.qualityAssuranceEventRestService.getEventsByTopic( this.topic, @@ -350,16 +352,24 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { followLink('target'), followLink('related') )), getFirstCompletedRemoteData(), - ).subscribe((rd: RemoteData>) => { - if (rd.hasSucceeded) { - this.isEventLoading.next(false); - this.totalElements$ = observableOf(rd.payload.totalElements); - this.setEventUpdated(rd.payload.page); - } else { - throw new Error('Can\'t retrieve Quality Assurance events from the Broker events REST service'); - } - this.qualityAssuranceEventRestService.clearFindByTopicRequests(); - }); + switchMap((rd: RemoteData>) => { + if (rd.hasSucceeded) { + this.totalElements$.next(rd.payload.totalElements); + if (rd.payload.totalElements > 0) { + console.log(rd.payload.page); + return this.fetchEvents(rd.payload.page); + } else { + return of([]); + } + } else { + throw new Error('Can\'t retrieve Quality Assurance events from the Broker events REST service'); + } + }), + take(1), + tap(() => { + this.qualityAssuranceEventRestService.clearFindByTopicRequests(); + }) + ); } /** @@ -372,55 +382,47 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { } /** - * Set the project status for the Quality Assurance events. + * Fetch Quality Assurance events in order to build proper QualityAssuranceEventData object. * * @param {QualityAssuranceEventObject[]} events * the Quality Assurance event item + * @return array of QualityAssuranceEventData */ - protected setEventUpdated(events: QualityAssuranceEventObject[]): void { - if (isEmpty(events)) { - this.eventsUpdated$.next([]); - } else { - this.subs.push( - from(events).pipe( - mergeMap((event: QualityAssuranceEventObject) => { - const related$ = event.related.pipe( - getFirstCompletedRemoteData(), - ); - const target$ = event.target.pipe( - getFirstCompletedRemoteData() - ); - return combineLatest([related$, target$]).pipe( - map(([relatedItemRD, targetItemRD]: [RemoteData, RemoteData]) => { - const data: QualityAssuranceEventData = { - event: event, - id: event.id, - title: event.title, - hasProject: false, - projectTitle: null, - projectId: null, - handle: null, - reason: null, - isRunning: false, - target: (targetItemRD?.hasSucceeded) ? targetItemRD.payload : null, - }; - if (relatedItemRD?.hasSucceeded && relatedItemRD?.payload?.id) { - data.hasProject = true; - data.projectTitle = event.message.title; - data.projectId = relatedItemRD?.payload?.id; - data.handle = relatedItemRD?.payload?.handle; - } - return data; - }) - ); - }), - scan((acc: any, value: any) => [...acc, value], []), - take(events.length) - ).subscribe((eventsReduced) => { - this.eventsUpdated$.next(eventsReduced); - } - ) - ); - } + protected fetchEvents(events: QualityAssuranceEventObject[]): Observable { + return from(events).pipe( + mergeMap((event: QualityAssuranceEventObject) => { + const related$ = event.related.pipe( + getFirstCompletedRemoteData(), + ); + const target$ = event.target.pipe( + getFirstCompletedRemoteData() + ); + return combineLatest([related$, target$]).pipe( + map(([relatedItemRD, targetItemRD]: [RemoteData, RemoteData]) => { + const data: QualityAssuranceEventData = { + event: event, + id: event.id, + title: event.title, + hasProject: false, + projectTitle: null, + projectId: null, + handle: null, + reason: null, + isRunning: false, + target: (targetItemRD?.hasSucceeded) ? targetItemRD.payload : null, + }; + if (relatedItemRD?.hasSucceeded && relatedItemRD?.payload?.id) { + data.hasProject = true; + data.projectTitle = event.message.title; + data.projectId = relatedItemRD?.payload?.id; + data.handle = relatedItemRD?.payload?.handle; + } + return data; + }) + ); + }), + scan((acc: any, value: any) => [...acc, value], []), + last() + ); } } diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html index 20f4d4394a5..0f6cf184024 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html @@ -2,12 +2,12 @@

    {{'quality-assurance.title'| translate}}

    -

    {{'quality-assurance.source.description'| translate}}

    +
    -

    {{'quality-assurance.source'| translate}}

    +

    {{'quality-assurance.source'| translate}}

    >) => !rd.isResponsePending), + getFirstCompletedRemoteData(), map((rd: RemoteData>) => { if (rd.hasSucceeded) { return rd.payload; diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html index fdc7d554a23..db8586f264d 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html @@ -2,12 +2,12 @@

    {{'quality-assurance.title'| translate}}

    -

    {{'quality-assurance.topics.description'| translate:{source: sourceId} }}

    + {{'quality-assurance.topics.description'| translate:{source: sourceId} }}
    -

    {{'quality-assurance.topics'| translate}}

    +

    {{'quality-assurance.topics'| translate}}

    >) => !rd.isResponsePending), + getFirstCompletedRemoteData(), map((rd: RemoteData>) => { if (rd.hasSucceeded) { return rd.payload; diff --git a/src/app/suggestion-notifications/suggestion-notifications.module.ts b/src/app/suggestion-notifications/suggestion-notifications.module.ts index 90e73eb0bef..e7e2272fffd 100644 --- a/src/app/suggestion-notifications/suggestion-notifications.module.ts +++ b/src/app/suggestion-notifications/suggestion-notifications.module.ts @@ -30,6 +30,7 @@ import { const MODULES = [ CommonModule, SharedModule, + SearchModule, CoreModule.forRoot(), StoreModule.forFeature('suggestionNotifications', suggestionNotificationsReducers, storeModuleConfig as StoreConfig), EffectsModule.forFeature(suggestionNotificationsEffects), @@ -59,8 +60,7 @@ const PROVIDERS = [ @NgModule({ imports: [ - ...MODULES, - SearchModule + ...MODULES ], declarations: [ ...COMPONENTS, From 9fd4a1feee5a13fbe1c2909445c8cc61548f9b3e Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 11 Nov 2022 13:07:21 +0100 Subject: [PATCH 022/196] [CST-5537] Add flag to hide the export button from search results when needed --- .../search-results.component.html | 2 +- .../search-results.component.ts | 5 +++++ .../themed-search-results.component.ts | 4 +++- src/app/shared/search/search.component.html | 21 ++++++++++--------- src/app/shared/search/search.component.ts | 5 +++++ .../shared/search/themed-search.component.ts | 4 +++- 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index 44498c3cab8..dcb3465be4b 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,6 +1,6 @@

    {{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}

    - +
    { - protected inAndOutputNames: (keyof SearchResultsComponent & keyof this)[] = ['linkType', 'searchResults', 'searchConfig', 'sortConfig', 'viewMode', 'configuration', 'disableHeader', 'selectable', 'context', 'hidePaginationDetail', 'selectionConfig', 'contentChange', 'deselectObject', 'selectObject']; + protected inAndOutputNames: (keyof SearchResultsComponent & keyof this)[] = ['linkType', 'searchResults', 'searchConfig', 'showExport', 'sortConfig', 'viewMode', 'configuration', 'disableHeader', 'selectable', 'context', 'hidePaginationDetail', 'selectionConfig', 'contentChange', 'deselectObject', 'selectObject']; @Input() linkType: CollectionElementLinkType; @@ -29,6 +29,8 @@ export class ThemedSearchResultsComponent extends ThemedComponent
    + [searchConfig]="searchOptions$ | async" + [configuration]="(currentConfiguration$ | async)" + [disableHeader]="!searchEnabled" + [linkType]="linkType" + [context]="(currentContext$ | async)" + [selectable]="selectable" + [selectionConfig]="selectionConfig" + [showExport]="showExport" + (contentChange)="onContentChange($event)" + (deselectObject)="deselectObject.emit($event)" + (selectObject)="selectObject.emit($event)">
    diff --git a/src/app/shared/search/search.component.ts b/src/app/shared/search/search.component.ts index c094e37ef23..b08b9a4b2a5 100644 --- a/src/app/shared/search/search.component.ts +++ b/src/app/shared/search/search.component.ts @@ -117,6 +117,11 @@ export class SearchComponent implements OnInit { */ @Input() selectionConfig: SelectionConfig; + /** + * A boolean representing if show export button + */ + @Input() showExport = true; + /** * A boolean representing if show search sidebar button */ diff --git a/src/app/shared/search/themed-search.component.ts b/src/app/shared/search/themed-search.component.ts index 64a2befeb2d..095357d74b5 100644 --- a/src/app/shared/search/themed-search.component.ts +++ b/src/app/shared/search/themed-search.component.ts @@ -19,7 +19,7 @@ import { ListableObject } from '../object-collection/shared/listable-object.mode templateUrl: '../theme-support/themed.component.html', }) export class ThemedSearchComponent extends ThemedComponent { - protected inAndOutputNames: (keyof SearchComponent & keyof this)[] = ['configurationList', 'context', 'configuration', 'fixedFilterQuery', 'useCachedVersionIfAvailable', 'inPlaceSearch', 'linkType', 'paginationId', 'searchEnabled', 'sideBarWidth', 'searchFormPlaceholder', 'selectable', 'selectionConfig', 'showSidebar', 'showViewModes', 'useUniquePageId', 'viewModeList', 'showScopeSelector', 'resultFound', 'deselectObject', 'selectObject', 'trackStatistics']; + protected inAndOutputNames: (keyof SearchComponent & keyof this)[] = ['configurationList', 'context', 'configuration', 'fixedFilterQuery', 'useCachedVersionIfAvailable', 'inPlaceSearch', 'linkType', 'paginationId', 'searchEnabled', 'sideBarWidth', 'searchFormPlaceholder', 'selectable', 'selectionConfig', 'showExport', 'showSidebar', 'showViewModes', 'useUniquePageId', 'viewModeList', 'showScopeSelector', 'resultFound', 'deselectObject', 'selectObject', 'trackStatistics']; @Input() configurationList: SearchConfigurationOption[] = []; @@ -47,6 +47,8 @@ export class ThemedSearchComponent extends ThemedComponent { @Input() selectionConfig: SelectionConfig; + @Input() showExport = true; + @Input() showSidebar = true; @Input() showViewModes = true; From 79cd69fb9421d818b9e33731fc8eb2e47f49f3c7 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 11 Nov 2022 13:07:52 +0100 Subject: [PATCH 023/196] [CST-5537] hide the export button from project search --- .../project-entry-import-modal.component.html | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html index 1090fd22fcf..35b4b396a7b 100644 --- a/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html +++ b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html @@ -38,19 +38,20 @@

    {{ (labelPrefix + label + '.select' | translate) }}

    - - + +
    From b8880091e6da2f5168255b8de8a55723cbcb0f94 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 11 Nov 2022 14:41:50 +0100 Subject: [PATCH 024/196] [CST-5537] Fix lint --- .../admin-quality-assurance-source-page.component.ts | 2 +- src/app/shared/selector.util.ts | 2 +- .../project-entry-import-modal.component.ts | 3 +-- .../qa/source/quality-assurance-source.service.spec.ts | 7 ++++--- .../qa/topics/quality-assurance-topics.component.spec.ts | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts index 20d0356d5f0..447e5a2e553 100644 --- a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; /** * Component for the page that show the QA sources. diff --git a/src/app/shared/selector.util.ts b/src/app/shared/selector.util.ts index 97ddb9af7dc..7ea73347b7c 100644 --- a/src/app/shared/selector.util.ts +++ b/src/app/shared/selector.util.ts @@ -1,4 +1,4 @@ -import { createSelector, MemoizedSelector, Selector } from '@ngrx/store'; +import { createSelector, MemoizedSelector } from '@ngrx/store'; import { hasValue } from './empty.util'; /** diff --git a/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts index bde97f364ce..1a43f59a1fc 100644 --- a/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts +++ b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts @@ -13,9 +13,8 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio import { SearchService } from '../../../core/shared/search/search.service'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { - QualityAssuranceEventObject, - QualityAssuranceEventMessageObject, OpenaireQualityAssuranceEventMessageObject, + QualityAssuranceEventObject, } from '../../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; import { Item } from '../../../core/shared/item.model'; diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts index 208e45e387f..355de6e6169 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts @@ -11,9 +11,10 @@ import { import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; import { cold } from 'jasmine-marbles'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; -import { QualityAssuranceSourceRestService } from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; -import { RequestParam } from '../../../core/cache/models/request-param.model'; -import {FindListOptions} from '../../../core/data/find-list-options.model'; +import { + QualityAssuranceSourceRestService +} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; +import { FindListOptions } from '../../../core/data/find-list-options.model'; describe('QualityAssuranceSourceService', () => { let service: QualityAssuranceSourceService; diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts index 6e933a0e803..c80d2bce20b 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts @@ -1,9 +1,9 @@ /* eslint-disable no-empty, @typescript-eslint/no-empty-function */ import { CommonModule } from '@angular/common'; import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; -import { of as observableOf, of } from 'rxjs'; +import { of as observableOf } from 'rxjs'; import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing'; import { createTestComponent } from '../../../shared/testing/utils.test'; import { From 625409cbb016c16d894826a915ee337ccdeabb29 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 17 Nov 2022 11:45:59 +0100 Subject: [PATCH 025/196] [CST-5537] Rename rest services to data services --- ...lity-assurance-event-data.service.spec.ts} | 8 ++-- ...> quality-assurance-event-data.service.ts} | 2 +- ...ity-assurance-source-data.service.spec.ts} | 20 ++++---- ... quality-assurance-source-data.service.ts} | 48 +++++++++---------- ...lity-assurance-topic-data.service.spec.ts} | 16 +++---- ...> quality-assurance-topic-data.service.ts} | 44 +++++++++-------- src/app/shared/mocks/notifications.mock.ts | 40 ++++++++++------ ...quality-assurance-events.component.spec.ts | 6 +-- .../quality-assurance-events.component.ts | 8 ++-- .../quality-assurance-source.effects.ts | 8 ++-- .../quality-assurance-source.service.spec.ts | 10 ++-- .../quality-assurance-source.service.ts | 8 ++-- .../quality-assurance-topics.effects.ts | 8 ++-- .../quality-assurance-topics.service.spec.ts | 12 +++-- .../quality-assurance-topics.service.ts | 8 ++-- .../suggestion-notifications.module.ts | 18 +++---- 16 files changed, 139 insertions(+), 125 deletions(-) rename src/app/core/suggestion-notifications/qa/events/{quality-assurance-event-rest.service.spec.ts => quality-assurance-event-data.service.spec.ts} (97%) rename src/app/core/suggestion-notifications/qa/events/{quality-assurance-event-rest.service.ts => quality-assurance-event-data.service.ts} (99%) rename src/app/core/suggestion-notifications/qa/source/{quality-assurance-source-rest.service.spec.ts => quality-assurance-source-data.service.spec.ts} (84%) rename src/app/core/suggestion-notifications/qa/source/{quality-assurance-source-rest.service.ts => quality-assurance-source-data.service.ts} (52%) rename src/app/core/suggestion-notifications/qa/topics/{quality-assurance-topic-rest.service.spec.ts => quality-assurance-topic-data.service.spec.ts} (86%) rename src/app/core/suggestion-notifications/qa/topics/{quality-assurance-topic-rest.service.ts => quality-assurance-topic-data.service.ts} (53%) diff --git a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.spec.ts b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.spec.ts similarity index 97% rename from src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.spec.ts rename to src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.spec.ts index 731c70d6243..50d0e43a99c 100644 --- a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.spec.ts +++ b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.spec.ts @@ -13,7 +13,7 @@ import { PageInfo } from '../../../shared/page-info.model'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; -import { QualityAssuranceEventRestService } from './quality-assurance-event-rest.service'; +import { QualityAssuranceEventDataService } from './quality-assurance-event-data.service'; import { qualityAssuranceEventObjectMissingPid, qualityAssuranceEventObjectMissingPid2, @@ -23,9 +23,9 @@ import { ReplaceOperation } from 'fast-json-patch'; import { RequestEntry } from '../../../data/request-entry.model'; import { FindListOptions } from '../../../data/find-list-options.model'; -describe('QualityAssuranceEventRestService', () => { +describe('QualityAssuranceEventDataService', () => { let scheduler: TestScheduler; - let service: QualityAssuranceEventRestService; + let service: QualityAssuranceEventDataService; let serviceASAny: any; let responseCacheEntry: RequestEntry; let responseCacheEntryB: RequestEntry; @@ -100,7 +100,7 @@ describe('QualityAssuranceEventRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new QualityAssuranceEventRestService( + service = new QualityAssuranceEventDataService( requestService, rdbService, objectCache, diff --git a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.ts b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts similarity index 99% rename from src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.ts rename to src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts index e83c9a8b439..7f7e68afaab 100644 --- a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.ts +++ b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts @@ -31,7 +31,7 @@ import { DeleteByIDRequest, PostRequest } from '../../../data/request.models'; */ @Injectable() @dataService(QUALITY_ASSURANCE_EVENT_OBJECT) -export class QualityAssuranceEventRestService extends IdentifiableDataService { +export class QualityAssuranceEventDataService extends IdentifiableDataService { private createData: CreateData; private searchData: SearchData; diff --git a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.spec.ts b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.spec.ts similarity index 84% rename from src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.spec.ts rename to src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.spec.ts index f4a2d81b367..50d9251bb88 100644 --- a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.spec.ts +++ b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.spec.ts @@ -18,11 +18,11 @@ import { qualityAssuranceSourceObjectMorePid } from '../../../../shared/mocks/notifications.mock'; import { RequestEntry } from '../../../data/request-entry.model'; -import { QualityAssuranceSourceRestService } from './quality-assurance-source-rest.service'; +import { QualityAssuranceSourceDataService } from './quality-assurance-source-data.service'; -describe('QualityAssuranceSourceRestService', () => { +describe('QualityAssuranceSourceDataService', () => { let scheduler: TestScheduler; - let service: QualityAssuranceSourceRestService; + let service: QualityAssuranceSourceDataService; let responseCacheEntry: RequestEntry; let requestService: RequestService; let rdbService: RemoteDataBuildService; @@ -72,7 +72,7 @@ describe('QualityAssuranceSourceRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new QualityAssuranceSourceRestService( + service = new QualityAssuranceSourceDataService( requestService, rdbService, objectCache, @@ -80,15 +80,15 @@ describe('QualityAssuranceSourceRestService', () => { notificationsService ); - spyOn((service as any), 'findListByHref').and.callThrough(); - spyOn((service as any), 'findByHref').and.callThrough(); + spyOn((service as any).findAllData, 'findAll').and.callThrough(); + spyOn((service as any), 'findById').and.callThrough(); }); describe('getSources', () => { - it('should call findListByHref', (done) => { + it('should call findAll', (done) => { service.getSources().subscribe( (res) => { - expect((service as any).findListByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); + expect((service as any).findAllData.findAll).toHaveBeenCalledWith({}, true, true); } ); done(); @@ -104,10 +104,10 @@ describe('QualityAssuranceSourceRestService', () => { }); describe('getSource', () => { - it('should call findByHref', (done) => { + it('should call findById', (done) => { service.getSource(qualityAssuranceSourceObjectMorePid.id).subscribe( (res) => { - expect((service as any).findByHref).toHaveBeenCalledWith(endpointURL + '/' + qualityAssuranceSourceObjectMorePid.id, true, true); + expect((service as any).findById).toHaveBeenCalledWith(qualityAssuranceSourceObjectMorePid.id, true, true); } ); done(); diff --git a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.ts b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts similarity index 52% rename from src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.ts rename to src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts index 8f16347b252..03a5da2e8c4 100644 --- a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.ts +++ b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts @@ -1,8 +1,6 @@ -/* eslint-disable max-classes-per-file */ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { mergeMap, take } from 'rxjs/operators'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; @@ -17,13 +15,16 @@ import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.mo import { PaginatedList } from '../../../data/paginated-list.model'; import { FindListOptions } from '../../../data/find-list-options.model'; import { IdentifiableDataService } from '../../../data/base/identifiable-data.service'; +import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data'; /** * The service handling all Quality Assurance source REST requests. */ @Injectable() @dataService(QUALITY_ASSURANCE_SOURCE_OBJECT) -export class QualityAssuranceSourceRestService extends IdentifiableDataService { +export class QualityAssuranceSourceDataService extends IdentifiableDataService { + + private findAllData: FindAllData; /** * Initialize service variables @@ -41,23 +42,24 @@ export class QualityAssuranceSourceRestService extends IdentifiableDataService>> * The list of Quality Assurance source. */ - public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { - return this.getBrowseEndpoint(options).pipe( - take(1), - mergeMap((href: string) => this.findListByHref(href, options, true, true, ...linksToFollow)), - ); + public getSources(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable>> { + return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } /** @@ -70,18 +72,16 @@ export class QualityAssuranceSourceRestService extends IdentifiableDataService> - * The Quality Assurance source. + * @param id The Quality Assurance source id + * @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + * @param reRequestOnStale Whether or not the request should automatically be re- + * requested after the response becomes stale + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. + * + * @return Observable> The Quality Assurance source. */ - public getSource(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { - const options = {}; - return this.getBrowseEndpoint(options, 'qualityassurancesources').pipe( - take(1), - mergeMap((href: string) => this.findByHref(href + '/' + id, true, true, ...linksToFollow)) - ); + public getSource(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable> { + return this.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } } diff --git a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.spec.ts similarity index 86% rename from src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts rename to src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.spec.ts index d16ccbdb005..638ee3fa62e 100644 --- a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts +++ b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.spec.ts @@ -13,16 +13,16 @@ import { PageInfo } from '../../../shared/page-info.model'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { createSuccessfulRemoteDataObject } from '../../../../shared/remote-data.utils'; -import { QualityAssuranceTopicRestService } from './quality-assurance-topic-rest.service'; +import { QualityAssuranceTopicDataService } from './quality-assurance-topic-data.service'; import { qualityAssuranceTopicObjectMoreAbstract, qualityAssuranceTopicObjectMorePid } from '../../../../shared/mocks/notifications.mock'; import { RequestEntry } from '../../../data/request-entry.model'; -describe('QualityAssuranceTopicRestService', () => { +describe('QualityAssuranceTopicDataService', () => { let scheduler: TestScheduler; - let service: QualityAssuranceTopicRestService; + let service: QualityAssuranceTopicDataService; let responseCacheEntry: RequestEntry; let requestService: RequestService; let rdbService: RemoteDataBuildService; @@ -72,7 +72,7 @@ describe('QualityAssuranceTopicRestService', () => { http = {} as HttpClient; comparator = {} as any; - service = new QualityAssuranceTopicRestService( + service = new QualityAssuranceTopicDataService( requestService, rdbService, objectCache, @@ -80,15 +80,15 @@ describe('QualityAssuranceTopicRestService', () => { notificationsService ); - spyOn((service as any), 'findListByHref').and.callThrough(); - spyOn((service as any), 'findByHref').and.callThrough(); + spyOn((service as any).findAllData, 'findAll').and.callThrough(); + spyOn((service as any), 'findById').and.callThrough(); }); describe('getTopics', () => { it('should call findListByHref', (done) => { service.getTopics().subscribe( (res) => { - expect((service as any).findListByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); + expect((service as any).findAllData.findAll).toHaveBeenCalledWith({}, true, true); } ); done(); @@ -107,7 +107,7 @@ describe('QualityAssuranceTopicRestService', () => { it('should call findByHref', (done) => { service.getTopic(qualityAssuranceTopicObjectMorePid.id).subscribe( (res) => { - expect((service as any).findByHref).toHaveBeenCalledWith(endpointURL + '/' + qualityAssuranceTopicObjectMorePid.id, true, true); + expect((service as any).findById).toHaveBeenCalledWith(qualityAssuranceTopicObjectMorePid.id, true, true); } ); done(); diff --git a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.ts b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts similarity index 53% rename from src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.ts rename to src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts index 2ab715bbbec..2bf5195bf1e 100644 --- a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.ts +++ b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { mergeMap, take } from 'rxjs/operators'; import { HALEndpointService } from '../../../shared/hal-endpoint.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; @@ -16,13 +15,16 @@ import { FindListOptions } from '../../../data/find-list-options.model'; import { IdentifiableDataService } from '../../../data/base/identifiable-data.service'; import { dataService } from '../../../data/base/data-service.decorator'; import { QUALITY_ASSURANCE_TOPIC_OBJECT } from '../models/quality-assurance-topic-object.resource-type'; +import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data'; /** * The service handling all Quality Assurance topic REST requests. */ @Injectable() @dataService(QUALITY_ASSURANCE_TOPIC_OBJECT) -export class QualityAssuranceTopicRestService extends IdentifiableDataService { +export class QualityAssuranceTopicDataService extends IdentifiableDataService { + + private findAllData: FindAllData; /** * Initialize service variables @@ -40,23 +42,24 @@ export class QualityAssuranceTopicRestService extends IdentifiableDataService>> * The list of Quality Assurance topics. */ - public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig[]): Observable>> { - return this.getBrowseEndpoint(options).pipe( - take(1), - mergeMap((href: string) => this.findListByHref(href, options, true, true, ...linksToFollow)), - ); + public getTopics(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable>> { + return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } /** @@ -69,18 +72,17 @@ export class QualityAssuranceTopicRestService extends IdentifiableDataService> * The Quality Assurance topic. */ - public getTopic(id: string, ...linksToFollow: FollowLinkConfig[]): Observable> { - const options = {}; - return this.getBrowseEndpoint(options).pipe( - take(1), - mergeMap((href: string) => this.findByHref(href + '/' + id, true, true, ...linksToFollow)) - ); + public getTopic(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable> { + return this.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } } diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index bbdf60c083f..dc1c98c7b95 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -1,9 +1,17 @@ import { of as observableOf } from 'rxjs'; import { ResourceType } from '../../core/shared/resource-type'; -import { QualityAssuranceTopicObject } from '../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; -import { QualityAssuranceEventObject } from '../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; -import { QualityAssuranceTopicRestService } from '../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; -import { QualityAssuranceEventRestService } from '../../core/suggestion-notifications/qa/events/quality-assurance-event-rest.service'; +import { + QualityAssuranceTopicObject +} from '../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { + QualityAssuranceEventObject +} from '../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; +import { + QualityAssuranceTopicDataService +} from '../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; +import { + QualityAssuranceEventDataService +} from '../../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { Item } from '../../core/shared/item.model'; import { @@ -12,7 +20,9 @@ import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { SearchResult } from '../search/models/search-result.model'; -import { QualityAssuranceSourceObject } from '../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { + QualityAssuranceSourceObject +} from '../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; // REST Mock --------------------------------------------------------------------- // ------------------------------------------------------------------------------- @@ -1814,30 +1824,30 @@ export function getMockNotificationsStateService(): any { } /** - * Mock for [[QualityAssuranceSourceRestService]] + * Mock for [[QualityAssuranceSourceDataService]] */ - export function getMockQualityAssuranceSourceRestService(): QualityAssuranceTopicRestService { - return jasmine.createSpyObj('QualityAssuranceSourceRestService', { + export function getMockQualityAssuranceSourceRestService(): QualityAssuranceTopicDataService { + return jasmine.createSpyObj('QualityAssuranceSourceDataService', { getSources: jasmine.createSpy('getSources'), getSource: jasmine.createSpy('getSource'), }); } /** - * Mock for [[QualityAssuranceTopicRestService]] + * Mock for [[QualityAssuranceTopicDataService]] */ -export function getMockQualityAssuranceTopicRestService(): QualityAssuranceTopicRestService { - return jasmine.createSpyObj('QualityAssuranceTopicRestService', { +export function getMockQualityAssuranceTopicRestService(): QualityAssuranceTopicDataService { + return jasmine.createSpyObj('QualityAssuranceTopicDataService', { getTopics: jasmine.createSpy('getTopics'), getTopic: jasmine.createSpy('getTopic'), }); } /** - * Mock for [[QualityAssuranceEventRestService]] + * Mock for [[QualityAssuranceEventDataService]] */ -export function getMockQualityAssuranceEventRestService(): QualityAssuranceEventRestService { - return jasmine.createSpyObj('QualityAssuranceEventRestService', { +export function getMockQualityAssuranceEventRestService(): QualityAssuranceEventDataService { + return jasmine.createSpyObj('QualityAssuranceEventDataService', { getEventsByTopic: jasmine.createSpy('getEventsByTopic'), getEvent: jasmine.createSpy('getEvent'), patchEvent: jasmine.createSpy('patchEvent'), @@ -1848,7 +1858,7 @@ export function getMockQualityAssuranceEventRestService(): QualityAssuranceEvent } /** - * Mock for [[QualityAssuranceEventRestService]] + * Mock for [[QualityAssuranceEventDataService]] */ export function getMockSuggestionsService(): any { return jasmine.createSpyObj('SuggestionsService', { diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts index f0109f5f662..04ece87fbb3 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts @@ -6,8 +6,8 @@ import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { of as observableOf } from 'rxjs'; import { - QualityAssuranceEventRestService -} from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-rest.service'; + QualityAssuranceEventDataService +} from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; import { QualityAssuranceEventsComponent } from './quality-assurance-events.component'; import { getMockQualityAssuranceEventRestService, @@ -113,7 +113,7 @@ describe('QualityAssuranceEventsComponent test suite', () => { ], providers: [ { provide: ActivatedRoute, useValue: new ActivatedRouteStub(activatedRouteParamsMap, activatedRouteParams) }, - { provide: QualityAssuranceEventRestService, useValue: qualityAssuranceEventRestServiceStub }, + { provide: QualityAssuranceEventDataService, useValue: qualityAssuranceEventRestServiceStub }, { provide: NgbModal, useValue: modalStub }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: TranslateService, useValue: getMockTranslateService() }, diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts index f78798ac250..e34c121f359 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts @@ -14,8 +14,8 @@ import { QualityAssuranceEventObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; import { - QualityAssuranceEventRestService -} from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-rest.service'; + QualityAssuranceEventDataService +} from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { Metadata } from '../../../core/shared/metadata.utils'; import { followLink } from '../../../shared/utils/follow-link-config.model'; @@ -110,7 +110,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * @param {ActivatedRoute} activatedRoute * @param {NgbModal} modalService * @param {NotificationsService} notificationsService - * @param {QualityAssuranceEventRestService} qualityAssuranceEventRestService + * @param {QualityAssuranceEventDataService} qualityAssuranceEventRestService * @param {PaginationService} paginationService * @param {TranslateService} translateService */ @@ -118,7 +118,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { private activatedRoute: ActivatedRoute, private modalService: NgbModal, private notificationsService: NotificationsService, - private qualityAssuranceEventRestService: QualityAssuranceEventRestService, + private qualityAssuranceEventRestService: QualityAssuranceEventDataService, private paginationService: PaginationService, private translateService: TranslateService ) { diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts index b1514171aaf..fd78911ab4d 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts @@ -19,8 +19,8 @@ import { PaginatedList } from '../../../core/data/paginated-list.model'; import { QualityAssuranceSourceService } from './quality-assurance-source.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { - QualityAssuranceSourceRestService -} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; + QualityAssuranceSourceDataService +} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; /** * Provides effect methods for the Quality Assurance source actions. @@ -79,7 +79,7 @@ export class QualityAssuranceSourceEffects { * @param {TranslateService} translate * @param {NotificationsService} notificationsService * @param {QualityAssuranceSourceService} qualityAssuranceSourceService - * @param {QualityAssuranceSourceRestService} qualityAssuranceSourceDataService + * @param {QualityAssuranceSourceDataService} qualityAssuranceSourceDataService */ constructor( private actions$: Actions, @@ -87,7 +87,7 @@ export class QualityAssuranceSourceEffects { private translate: TranslateService, private notificationsService: NotificationsService, private qualityAssuranceSourceService: QualityAssuranceSourceService, - private qualityAssuranceSourceDataService: QualityAssuranceSourceRestService + private qualityAssuranceSourceDataService: QualityAssuranceSourceDataService ) { } } diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts index 355de6e6169..745a2baef78 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts @@ -12,13 +12,13 @@ import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.ut import { cold } from 'jasmine-marbles'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; import { - QualityAssuranceSourceRestService -} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; + QualityAssuranceSourceDataService +} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; import { FindListOptions } from '../../../core/data/find-list-options.model'; describe('QualityAssuranceSourceService', () => { let service: QualityAssuranceSourceService; - let restService: QualityAssuranceSourceRestService; + let restService: QualityAssuranceSourceDataService; let serviceAsAny: any; let restServiceAsAny: any; @@ -32,14 +32,14 @@ describe('QualityAssuranceSourceService', () => { beforeEach(async () => { TestBed.configureTestingModule({ providers: [ - { provide: QualityAssuranceSourceRestService, useClass: getMockQualityAssuranceSourceRestService }, + { provide: QualityAssuranceSourceDataService, useClass: getMockQualityAssuranceSourceRestService }, { provide: QualityAssuranceSourceService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { - restService = TestBed.get(QualityAssuranceSourceRestService); + restService = TestBed.inject(QualityAssuranceSourceDataService); restServiceAsAny = restService; restServiceAsAny.getSources.and.returnValue(observableOf(paginatedListRD)); service = new QualityAssuranceSourceService(restService); diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts index a0556ece8cc..5c16fb1a03d 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts @@ -4,8 +4,8 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { - QualityAssuranceSourceRestService -} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; + QualityAssuranceSourceDataService +} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list.model'; @@ -23,10 +23,10 @@ export class QualityAssuranceSourceService { /** * Initialize the service variables. - * @param {QualityAssuranceSourceRestService} qualityAssuranceSourceRestService + * @param {QualityAssuranceSourceDataService} qualityAssuranceSourceRestService */ constructor( - private qualityAssuranceSourceRestService: QualityAssuranceSourceRestService + private qualityAssuranceSourceRestService: QualityAssuranceSourceDataService ) { } diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts index 11d7e115553..13e36700001 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts @@ -19,8 +19,8 @@ import { PaginatedList } from '../../../core/data/paginated-list.model'; import { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { - QualityAssuranceTopicRestService -} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; + QualityAssuranceTopicDataService +} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; /** * Provides effect methods for the Quality Assurance topics actions. @@ -79,7 +79,7 @@ export class QualityAssuranceTopicsEffects { * @param {TranslateService} translate * @param {NotificationsService} notificationsService * @param {QualityAssuranceTopicsService} qualityAssuranceTopicService - * @param {QualityAssuranceTopicRestService} qualityAssuranceTopicDataService + * @param {QualityAssuranceTopicDataService} qualityAssuranceTopicDataService */ constructor( private actions$: Actions, @@ -87,6 +87,6 @@ export class QualityAssuranceTopicsEffects { private translate: TranslateService, private notificationsService: NotificationsService, private qualityAssuranceTopicService: QualityAssuranceTopicsService, - private qualityAssuranceTopicDataService: QualityAssuranceTopicRestService + private qualityAssuranceTopicDataService: QualityAssuranceTopicDataService ) { } } diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts index ba1399fcd43..1e4e3fcffd9 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts @@ -2,7 +2,9 @@ import { TestBed } from '@angular/core/testing'; import { of as observableOf } from 'rxjs'; import { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; -import { QualityAssuranceTopicRestService } from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; +import { + QualityAssuranceTopicDataService +} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; import { PageInfo } from '../../../core/shared/page-info.model'; import { getMockQualityAssuranceTopicRestService, @@ -13,11 +15,11 @@ import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.ut import { cold } from 'jasmine-marbles'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; import { RequestParam } from '../../../core/cache/models/request-param.model'; -import {FindListOptions} from '../../../core/data/find-list-options.model'; +import { FindListOptions } from '../../../core/data/find-list-options.model'; describe('QualityAssuranceTopicsService', () => { let service: QualityAssuranceTopicsService; - let restService: QualityAssuranceTopicRestService; + let restService: QualityAssuranceTopicDataService; let serviceAsAny: any; let restServiceAsAny: any; @@ -31,14 +33,14 @@ describe('QualityAssuranceTopicsService', () => { beforeEach(async () => { TestBed.configureTestingModule({ providers: [ - { provide: QualityAssuranceTopicRestService, useClass: getMockQualityAssuranceTopicRestService }, + { provide: QualityAssuranceTopicDataService, useClass: getMockQualityAssuranceTopicRestService }, { provide: QualityAssuranceTopicsService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { - restService = TestBed.get(QualityAssuranceTopicRestService); + restService = TestBed.inject(QualityAssuranceTopicDataService); restServiceAsAny = restService; restServiceAsAny.getTopics.and.returnValue(observableOf(paginatedListRD)); service = new QualityAssuranceTopicsService(restService); diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts index 968e21fb957..6820791dffd 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { - QualityAssuranceTopicRestService -} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; + QualityAssuranceTopicDataService +} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list.model'; @@ -22,10 +22,10 @@ export class QualityAssuranceTopicsService { /** * Initialize the service variables. - * @param {QualityAssuranceTopicRestService} qualityAssuranceTopicRestService + * @param {QualityAssuranceTopicDataService} qualityAssuranceTopicRestService */ constructor( - private qualityAssuranceTopicRestService: QualityAssuranceTopicRestService + private qualityAssuranceTopicRestService: QualityAssuranceTopicDataService ) { } /** diff --git a/src/app/suggestion-notifications/suggestion-notifications.module.ts b/src/app/suggestion-notifications/suggestion-notifications.module.ts index e7e2272fffd..eac527d6726 100644 --- a/src/app/suggestion-notifications/suggestion-notifications.module.ts +++ b/src/app/suggestion-notifications/suggestion-notifications.module.ts @@ -13,19 +13,19 @@ import { suggestionNotificationsReducers, SuggestionNotificationsState } from '. import { suggestionNotificationsEffects } from './suggestion-notifications-effects'; import { QualityAssuranceTopicsService } from './qa/topics/quality-assurance-topics.service'; import { - QualityAssuranceTopicRestService -} from '../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; + QualityAssuranceTopicDataService +} from '../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; import { - QualityAssuranceEventRestService -} from '../core/suggestion-notifications/qa/events/quality-assurance-event-rest.service'; + QualityAssuranceEventDataService +} from '../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; import { ProjectEntryImportModalComponent } from './qa/project-entry-import-modal/project-entry-import-modal.component'; import { TranslateModule } from '@ngx-translate/core'; import { SearchModule } from '../shared/search/search.module'; import { QualityAssuranceSourceComponent } from './qa/source/quality-assurance-source.component'; import { QualityAssuranceSourceService } from './qa/source/quality-assurance-source.service'; import { - QualityAssuranceSourceRestService -} from '../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; + QualityAssuranceSourceDataService +} from '../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; const MODULES = [ CommonModule, @@ -53,9 +53,9 @@ const PROVIDERS = [ SuggestionNotificationsStateService, QualityAssuranceTopicsService, QualityAssuranceSourceService, - QualityAssuranceTopicRestService, - QualityAssuranceSourceRestService, - QualityAssuranceEventRestService + QualityAssuranceTopicDataService, + QualityAssuranceSourceDataService, + QualityAssuranceEventDataService ]; @NgModule({ From ae6b183faec9cda0d2932143a52e14ef94bd945c Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 14 Jun 2023 18:51:42 +0200 Subject: [PATCH 026/196] 103236: fix issue where setStaleByHrefSubtring wouldn't emit after all requests were stale --- src/app/core/data/request.service.ts | 36 +++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index 2d5acb2cb3d..3b7ee80ffb0 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@angular/core'; import { HttpHeaders } from '@angular/common/http'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; -import { filter, map, take, tap } from 'rxjs/operators'; +import { Observable, from as observableFrom } from 'rxjs'; +import { filter, find, map, mergeMap, switchMap, take, tap, toArray } from 'rxjs/operators'; import { cloneDeep } from 'lodash'; import { hasValue, isEmpty, isNotEmpty, hasNoValue } from '../../shared/empty.util'; import { ObjectCacheEntry } from '../cache/object-cache.reducer'; @@ -292,22 +292,42 @@ export class RequestService { * Set all requests that match (part of) the href to stale * * @param href A substring of the request(s) href - * @return Returns an observable emitting whether or not the cache is removed + * @return Returns an observable emitting when those requests are all stale */ setStaleByHrefSubstring(href: string): Observable { - this.store.pipe( + const requestUUIDs$ = this.store.pipe( select(uuidsFromHrefSubstringSelector(requestIndexSelector, href)), take(1) - ).subscribe((uuids: string[]) => { + ); + requestUUIDs$.subscribe((uuids: string[]) => { for (const uuid of uuids) { this.store.dispatch(new RequestStaleAction(uuid)); } }); this.requestsOnTheirWayToTheStore = this.requestsOnTheirWayToTheStore.filter((reqHref: string) => reqHref.indexOf(href) < 0); - return this.store.pipe( - select(uuidsFromHrefSubstringSelector(requestIndexSelector, href)), - map((uuids) => isEmpty(uuids)) + // emit true after all requests are stale + return requestUUIDs$.pipe( + switchMap((uuids: string[]) => { + if (isEmpty(uuids)) { + // if there were no matching requests, emit true immediately + return [true]; + } else { + // otherwise emit all request uuids in order + return observableFrom(uuids).pipe( + // retrieve the RequestEntry for each uuid + mergeMap((uuid: string) => this.getByUUID(uuid)), + // check whether it is undefined or stale + map((request: RequestEntry) => hasNoValue(request) || isStale(request.state)), + // if it is, complete + find((stale: boolean) => stale === true), + // after all observables above are completed, emit them as a single array + toArray(), + // when the array comes in, emit true + map(() => true) + ); + } + }) ); } From 02a20c8862ca4d93919ca07e900d70a722ebbb5d Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 30 Jun 2023 16:56:37 +0200 Subject: [PATCH 027/196] 103236: Added tests for setStaleByHrefSubstring --- src/app/core/data/request.service.spec.ts | 46 ++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index fe35d840d7d..4493c61a69c 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -1,6 +1,6 @@ import { Store, StoreModule } from '@ngrx/store'; import { cold, getTestScheduler } from 'jasmine-marbles'; -import { EMPTY, of as observableOf } from 'rxjs'; +import { EMPTY, Observable, of as observableOf } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { getMockObjectCacheService } from '../../shared/mocks/object-cache.service.mock'; @@ -625,4 +625,48 @@ describe('RequestService', () => { expect(done$).toBeObservable(cold('-----(t|)', { t: true })); })); }); + + describe('setStaleByHrefSubstring', () => { + let dispatchSpy: jasmine.Spy; + let getByUUIDSpy: jasmine.Spy; + + beforeEach(() => { + dispatchSpy = spyOn(store, 'dispatch'); + getByUUIDSpy = spyOn(service, 'getByUUID').and.callThrough(); + }); + + describe('with an empty/no matching requests in the state', () => { + it('should return true', () => { + const done$: Observable = service.setStaleByHrefSubstring('https://rest.api/endpoint/selfLink'); + expect(done$).toBeObservable(cold('(a|)', { a: true })); + }); + }); + + describe('with a matching request in the state', () => { + beforeEach(() => { + const state = Object.assign({}, initialState, { + core: Object.assign({}, initialState.core, { + 'index': { + 'get-request/href-to-uuid': { + 'https://rest.api/endpoint/selfLink': '5f2a0d2a-effa-4d54-bd54-5663b960f9eb' + } + } + }) + }); + mockStore.setState(state); + }); + + it('should return an Observable that emits true as soon as the request is stale', () => { + dispatchSpy.and.callFake(() => { /* empty */ }); // don't actually set as stale + getByUUIDSpy.and.returnValue(cold('a-b--c--d-', { // but fake the state in the cache + a: { state: RequestEntryState.ResponsePending }, + b: { state: RequestEntryState.Success }, + c: { state: RequestEntryState.SuccessStale }, + d: { state: RequestEntryState.Error }, + })); + const done$: Observable = service.setStaleByHrefSubstring('https://rest.api/endpoint/selfLink'); + expect(done$).toBeObservable(cold('-----(a|)', { a: true })); + }); + }); + }); }); From 23aefb7385a987c5cb3f3eb169b37037f032a126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:29:14 +0200 Subject: [PATCH 028/196] Added themed-user-menu component. --- .../user-menu/themed-user-menu.component.ts | 33 +++++++++++++++++++ src/app/shared/shared.module.ts | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts diff --git a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts new file mode 100644 index 00000000000..09f02eb761c --- /dev/null +++ b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts @@ -0,0 +1,33 @@ +import {Component, Input} from '@angular/core' +import {ThemedComponent} from '../../theme-support/themed.component'; +import {UserMenuComponent} from './user-menu.component'; + +/** + * This component represents the user nav menu. + */ +@Component({ + selector: 'ds-themed-user-menu', + templateUrl: './../../theme-support/themed.component.html', + styleUrls: [] +}) +export class ThemedUserMenuComponent extends ThemedComponent{ + + /** + * The input flag to show user details in navbar expandable menu + */ + @Input() inExpandableNavbar = false; + + protected inAndOutputNames: (keyof UserMenuComponent & keyof this)[] = ['inExpandableNavbar']; + + protected getComponentName(): string { + return 'UserMenuComponent'; + } + + protected importThemedComponent(themeName: string): Promise { + return import((`../../../../themes/${themeName}/app/shared/auth-nav-menu/user-menu/user-menu.component`)); + } + + protected importUnthemedComponent(): Promise { + return import('./user-menu.component'); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 0f7871f7f9b..91175736baf 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -284,6 +284,7 @@ import { } from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component'; import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component'; import { NgxPaginationModule } from 'ngx-pagination'; +import {ThemedUserMenuComponent} from './auth-nav-menu/user-menu/themed-user-menu.component'; const MODULES = [ CommonModule, @@ -332,6 +333,7 @@ const COMPONENTS = [ AuthNavMenuComponent, ThemedAuthNavMenuComponent, UserMenuComponent, + ThemedUserMenuComponent, DsSelectComponent, ErrorComponent, LangSwitchComponent, From 63582cfa0d40497b73f39088aaf949f41571e5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:34:25 +0200 Subject: [PATCH 029/196] Corrected missing semicolon. --- .../auth-nav-menu/user-menu/themed-user-menu.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts index 09f02eb761c..cecafc9d5cd 100644 --- a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts +++ b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core' +import {Component, Input} from '@angular/core'; import {ThemedComponent} from '../../theme-support/themed.component'; import {UserMenuComponent} from './user-menu.component'; From ed84f4513225d3fdef45edcafd2d434271b5f4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:38:32 +0200 Subject: [PATCH 030/196] Replaced tags for ds-user-menu. --- src/app/navbar/navbar.component.html | 2 +- src/app/shared/auth-nav-menu/auth-nav-menu.component.html | 2 +- src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index bc1e04f5130..8608ee7b02d 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -6,7 +6,7 @@ diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts index 58a1edfabde..0b9ea6ef4b4 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts @@ -248,7 +248,7 @@ describe('AuthNavMenuComponent', () => { component = null; }); it('should render UserMenuComponent component', () => { - const logoutDropdownMenu = deNavMenuItem.query(By.css('ds-user-menu')); + const logoutDropdownMenu = deNavMenuItem.query(By.css('ds-themed-user-menu')); expect(logoutDropdownMenu.nativeElement).toBeDefined(); }); }); From e3f57dae44de6f58e1ba2bf91d0de092b9416f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= Date: Mon, 10 Jul 2023 15:54:09 +0200 Subject: [PATCH 031/196] Included user-menu component in custom theme. --- .../user-menu/user-menu.component.html | 0 .../user-menu/user-menu.component.scss | 0 .../user-menu/user-menu.component.ts | 15 +++++++++++++++ src/themes/custom/lazy-theme.module.ts | 2 ++ 4 files changed, 17 insertions(+) create mode 100644 src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.html create mode 100644 src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.scss create mode 100644 src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts diff --git a/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.html b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.scss b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts new file mode 100644 index 00000000000..f9f1db65ee6 --- /dev/null +++ b/src/themes/custom/app/shared/auth-nav-menu/user-menu/user-menu.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { UserMenuComponent as BaseComponent } from '../../../../../../app/shared/auth-nav-menu/user-menu/user-menu.component'; + +/** + * Component representing the {@link UserMenuComponent} of a page + */ +@Component({ + selector: 'ds-user-menu', + // templateUrl: 'user-menu.component.html', + templateUrl: '../../../../../../app/shared/auth-nav-menu/user-menu/user-menu.component.html', + // styleUrls: ['user-menu.component.scss'], + styleUrls: ['../../../../../../app/shared/auth-nav-menu/user-menu/user-menu.component.scss'], +}) +export class UserMenuComponent extends BaseComponent { +} diff --git a/src/themes/custom/lazy-theme.module.ts b/src/themes/custom/lazy-theme.module.ts index edb3f5478c9..937e174b7f8 100644 --- a/src/themes/custom/lazy-theme.module.ts +++ b/src/themes/custom/lazy-theme.module.ts @@ -156,6 +156,7 @@ import { ItemStatusComponent } from './app/item-page/edit-item-page/item-status/ import { EditBitstreamPageComponent } from './app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component'; import { FormModule } from '../../app/shared/form/form.module'; import { RequestCopyModule } from 'src/app/request-copy/request-copy.module'; +import {UserMenuComponent} from './app/shared/auth-nav-menu/user-menu/user-menu.component'; const DECLARATIONS = [ FileSectionComponent, @@ -239,6 +240,7 @@ const DECLARATIONS = [ SubmissionSectionUploadFileComponent, ItemStatusComponent, EditBitstreamPageComponent, + UserMenuComponent, ]; @NgModule({ From 648925f3e1c0a51fc3eb61b7257e7a44ea57fee6 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Wed, 19 Jul 2023 14:01:41 +0200 Subject: [PATCH 032/196] 104312: DsDynamicLookupRelationExternalSourceTabComponent should have the form value already filled in the search input --- .../dynamic-lookup-relation-modal.component.html | 1 + ...ookup-relation-external-source-tab.component.ts | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html index f95cd98c656..4c635b931f0 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.html @@ -42,6 +42,7 @@
    diff --git a/src/app/community-page/community-page.component.html b/src/app/community-page/community-page.component.html index 6d5262d9338..671bf28fd1c 100644 --- a/src/app/community-page/community-page.component.html +++ b/src/app/community-page/community-page.component.html @@ -21,9 +21,6 @@ -
    - -
    diff --git a/src/app/shared/dso-page/dso-edit-menu.resolver.ts b/src/app/shared/dso-page/dso-edit-menu.resolver.ts index 80a69c2830d..1ade4578405 100644 --- a/src/app/shared/dso-page/dso-edit-menu.resolver.ts +++ b/src/app/shared/dso-page/dso-edit-menu.resolver.ts @@ -21,6 +21,9 @@ import { getDSORoute } from '../../app-routing-paths'; import { ResearcherProfileDataService } from '../../core/profile/researcher-profile-data.service'; import { NotificationsService } from '../notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; +import { SubscriptionModalComponent } from '../subscriptions/subscription-modal/subscription-modal.component'; +import { Community } from '../../core/shared/community.model'; +import { Collection } from '../../core/shared/collection.model'; /** * Creates the menus for the dspace object pages @@ -84,6 +87,7 @@ export class DSOEditMenuResolver implements Resolve<{ [key: string]: MenuSection getDsoMenus(dso, route, state): Observable[] { return [ this.getItemMenu(dso), + this.getComColMenu(dso), this.getCommonMenu(dso, state) ]; } @@ -178,6 +182,39 @@ export class DSOEditMenuResolver implements Resolve<{ [key: string]: MenuSection } } + /** + * Get Community/Collection-specific menus + */ + protected getComColMenu(dso): Observable { + if (dso instanceof Community || dso instanceof Collection) { + return combineLatest([ + this.authorizationService.isAuthorized(FeatureID.CanSubscribe, dso.self), + ]).pipe( + map(([canSubscribe]) => { + return [ + { + id: 'subscribe', + active: false, + visible: canSubscribe, + model: { + type: MenuItemType.ONCLICK, + text: 'subscriptions.tooltip', + function: () => { + const modalRef = this.modalService.open(SubscriptionModalComponent); + modalRef.componentInstance.dso = dso; + } + } as OnClickMenuItemModel, + icon: 'bell', + index: 4 + }, + ]; + }) + ); + } else { + return observableOf([]); + } + } + /** * Claim a researcher by creating a profile * Shows notifications and/or hides the menu section on success/error diff --git a/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.html b/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.html deleted file mode 100644 index 15135009fcd..00000000000 --- a/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.html +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.scss b/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.scss deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.spec.ts b/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.spec.ts deleted file mode 100644 index 726854778dc..00000000000 --- a/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DsoPageSubscriptionButtonComponent } from './dso-page-subscription-button.component'; -import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; -import { of as observableOf } from 'rxjs'; -import { NgbModalModule } from '@ng-bootstrap/ng-bootstrap'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; -import { Item } from '../../../core/shared/item.model'; -import { ITEM } from '../../../core/shared/item.resource-type'; -import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { TranslateLoaderMock } from '../../mocks/translate-loader.mock'; - -describe('DsoPageSubscriptionButtonComponent', () => { - let component: DsoPageSubscriptionButtonComponent; - let fixture: ComponentFixture; - let de: DebugElement; - - const authorizationService = jasmine.createSpyObj('authorizationService', { - isAuthorized: jasmine.createSpy('isAuthorized') // observableOf(true) - }); - - const mockItem = Object.assign(new Item(), { - id: 'fake-id', - uuid: 'fake-id', - handle: 'fake/handle', - lastModified: '2018', - type: ITEM, - _links: { - self: { - href: 'https://localhost:8000/items/fake-id' - } - } - }); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - NgbModalModule, - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useClass: TranslateLoaderMock - } - }) - ], - declarations: [ DsoPageSubscriptionButtonComponent ], - providers: [ - { provide: AuthorizationDataService, useValue: authorizationService }, - ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DsoPageSubscriptionButtonComponent); - component = fixture.componentInstance; - de = fixture.debugElement; - component.dso = mockItem; - }); - - describe('when is authorized', () => { - beforeEach(() => { - authorizationService.isAuthorized.and.returnValue(observableOf(true)); - fixture.detectChanges(); - }); - - it('should display subscription button', () => { - expect(de.query(By.css(' [data-test="subscription-button"]'))).toBeTruthy(); - }); - }); - - describe('when is not authorized', () => { - beforeEach(() => { - authorizationService.isAuthorized.and.returnValue(observableOf(false)); - fixture.detectChanges(); - }); - - it('should not display subscription button', () => { - expect(de.query(By.css(' [data-test="subscription-button"]'))).toBeNull(); - }); - }); -}); diff --git a/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.ts b/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.ts deleted file mode 100644 index 54cd9e6bb0d..00000000000 --- a/src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; - -import { Observable, of } from 'rxjs'; -import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; - -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; -import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; -import { SubscriptionModalComponent } from '../../subscriptions/subscription-modal/subscription-modal.component'; -import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; - -@Component({ - selector: 'ds-dso-page-subscription-button', - templateUrl: './dso-page-subscription-button.component.html', - styleUrls: ['./dso-page-subscription-button.component.scss'] -}) -/** - * Display a button that opens the modal to manage subscriptions - */ -export class DsoPageSubscriptionButtonComponent implements OnInit { - - /** - * Whether the current user is authorized to edit the DSpaceObject - */ - isAuthorized$: Observable = of(false); - - /** - * Reference to NgbModal - */ - public modalRef: NgbModalRef; - - /** - * DSpaceObject that is being viewed - */ - @Input() dso: DSpaceObject; - - constructor( - protected authorizationService: AuthorizationDataService, - private modalService: NgbModal, - ) { - } - - /** - * check if the current DSpaceObject can be subscribed by the user - */ - ngOnInit(): void { - this.isAuthorized$ = this.authorizationService.isAuthorized(FeatureID.CanSubscribe, this.dso.self); - } - - /** - * Open the modal to subscribe to the related DSpaceObject - */ - public openSubscriptionModal() { - this.modalRef = this.modalService.open(SubscriptionModalComponent); - this.modalRef.componentInstance.dso = this.dso; - } - -} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 0f7871f7f9b..c6e2ddc3f37 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -273,9 +273,6 @@ import { AdvancedClaimedTaskActionRatingComponent } from './mydspace-actions/claimed-task/rating/advanced-claimed-task-action-rating.component'; import { ClaimedTaskActionsDeclineTaskComponent } from './mydspace-actions/claimed-task/decline-task/claimed-task-actions-decline-task.component'; -import { - DsoPageSubscriptionButtonComponent -} from './dso-page/dso-page-subscription-button/dso-page-subscription-button.component'; import { EpersonGroupListComponent } from './eperson-group-list/eperson-group-list.component'; import { EpersonSearchBoxComponent } from './eperson-group-list/eperson-search-box/eperson-search-box.component'; import { GroupSearchBoxComponent } from './eperson-group-list/group-search-box/group-search-box.component'; @@ -395,7 +392,6 @@ const COMPONENTS = [ ItemPageTitleFieldComponent, ThemedSearchNavbarComponent, ListableNotificationObjectComponent, - DsoPageSubscriptionButtonComponent, MetadataFieldWrapperComponent, ContextHelpWrapperComponent, EpersonGroupListComponent, From 2a35180a1b2c81ca84e3fe7d9c4a84567f567a6a Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 21 Jul 2023 15:03:46 +0200 Subject: [PATCH 034/196] Created separate pages for edit & create EPersons --- .../access-control-routing-paths.ts | 10 ++ .../access-control-routing.module.ts | 25 ++- .../epeople-registry.component.html | 141 ++++++++------- .../epeople-registry.component.spec.ts | 30 ---- .../epeople-registry.component.ts | 64 +------ .../eperson-form/eperson-form.component.html | 161 +++++++++--------- .../eperson-form.component.spec.ts | 89 +++++----- .../eperson-form/eperson-form.component.ts | 23 +-- .../eperson-resolver.service.ts | 53 ++++++ src/assets/i18n/en.json5 | 8 + 10 files changed, 307 insertions(+), 297 deletions(-) create mode 100644 src/app/access-control/epeople-registry/eperson-resolver.service.ts diff --git a/src/app/access-control/access-control-routing-paths.ts b/src/app/access-control/access-control-routing-paths.ts index 259aa311e74..c3c42b3155d 100644 --- a/src/app/access-control/access-control-routing-paths.ts +++ b/src/app/access-control/access-control-routing-paths.ts @@ -1,6 +1,16 @@ import { URLCombiner } from '../core/url-combiner/url-combiner'; import { getAccessControlModuleRoute } from '../app-routing-paths'; +export const EPERSON_PATH = 'epeople'; + +export function getEPersonsRoute(): string { + return new URLCombiner(getAccessControlModuleRoute(), EPERSON_PATH).toString(); +} + +export function getEPersonEditRoute(id: string): string { + return new URLCombiner(getEPersonsRoute(), id).toString(); +} + export const GROUP_EDIT_PATH = 'groups'; export function getGroupsRoute() { diff --git a/src/app/access-control/access-control-routing.module.ts b/src/app/access-control/access-control-routing.module.ts index 6f6de6cb263..a4082d19e2f 100644 --- a/src/app/access-control/access-control-routing.module.ts +++ b/src/app/access-control/access-control-routing.module.ts @@ -3,7 +3,7 @@ import { RouterModule } from '@angular/router'; import { EPeopleRegistryComponent } from './epeople-registry/epeople-registry.component'; import { GroupFormComponent } from './group-registry/group-form/group-form.component'; import { GroupsRegistryComponent } from './group-registry/groups-registry.component'; -import { GROUP_EDIT_PATH } from './access-control-routing-paths'; +import { EPERSON_PATH, GROUP_EDIT_PATH } from './access-control-routing-paths'; import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver'; import { GroupPageGuard } from './group-registry/group-page.guard'; import { @@ -13,12 +13,14 @@ import { SiteAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard'; import { BulkAccessComponent } from './bulk-access/bulk-access.component'; +import { EPersonFormComponent } from './epeople-registry/eperson-form/eperson-form.component'; +import { EPersonResolver } from './epeople-registry/eperson-resolver.service'; @NgModule({ imports: [ RouterModule.forChild([ { - path: 'epeople', + path: EPERSON_PATH, component: EPeopleRegistryComponent, resolve: { breadcrumb: I18nBreadcrumbResolver @@ -26,6 +28,25 @@ import { BulkAccessComponent } from './bulk-access/bulk-access.component'; data: { title: 'admin.access-control.epeople.title', breadcrumbKey: 'admin.access-control.epeople' }, canActivate: [SiteAdministratorGuard] }, + { + path: `${EPERSON_PATH}/create`, + component: EPersonFormComponent, + resolve: { + breadcrumb: I18nBreadcrumbResolver, + }, + data: { title: 'admin.access-control.epeople.add.title', breadcrumbKey: 'admin.access-control.epeople.add' }, + canActivate: [SiteAdministratorGuard], + }, + { + path: `${EPERSON_PATH}/:id`, + component: EPersonFormComponent, + resolve: { + breadcrumb: I18nBreadcrumbResolver, + ePerson: EPersonResolver, + }, + data: { title: 'admin.access-control.epeople.edit.title', breadcrumbKey: 'admin.access-control.epeople.edit' }, + canActivate: [SiteAdministratorGuard], + }, { path: GROUP_EDIT_PATH, component: GroupsRegistryComponent, diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.html b/src/app/access-control/epeople-registry/epeople-registry.component.html index e3a8e2c590f..f3ddd63ae80 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.html +++ b/src/app/access-control/epeople-registry/epeople-registry.component.html @@ -4,96 +4,91 @@
    -
    +
    - + + +
    + +
    +
    +
    + + -
    -
    - -
    - +
    +
    + +
    + - - + + -
    - - - - - - - - - - - - - - - - - -
    {{labelPrefix + 'table.id' | translate}}{{labelPrefix + 'table.name' | translate}}{{labelPrefix + 'table.email' | translate}}{{labelPrefix + 'table.edit' | translate}}
    {{epersonDto.eperson.id}}{{ dsoNameService.getName(epersonDto.eperson) }}{{epersonDto.eperson.email}} -
    - - -
    -
    -
    +
    + + + + + + + + + + + + + + + + + +
    {{labelPrefix + 'table.id' | translate}}{{labelPrefix + 'table.name' | translate}}{{labelPrefix + 'table.email' | translate}}{{labelPrefix + 'table.edit' | translate}}
    {{epersonDto.eperson.id}}{{ dsoNameService.getName(epersonDto.eperson) }}{{epersonDto.eperson.email}} +
    + + +
    +
    +
    -
    +
    - +
    diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts b/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts index 4a09913862f..e2cee5e9356 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts +++ b/src/app/access-control/epeople-registry/epeople-registry.component.spec.ts @@ -203,36 +203,6 @@ describe('EPeopleRegistryComponent', () => { }); }); - describe('toggleEditEPerson', () => { - describe('when you click on first edit eperson button', () => { - beforeEach(fakeAsync(() => { - const editButtons = fixture.debugElement.queryAll(By.css('.access-control-editEPersonButton')); - editButtons[0].triggerEventHandler('click', { - preventDefault: () => {/**/ - } - }); - tick(); - fixture.detectChanges(); - })); - - it('editEPerson form is toggled', () => { - const ePeopleIds = fixture.debugElement.queryAll(By.css('#epeople tr td:first-child')); - ePersonDataServiceStub.getActiveEPerson().subscribe((activeEPerson: EPerson) => { - if (ePeopleIds[0] && activeEPerson === ePeopleIds[0].nativeElement.textContent) { - expect(component.isEPersonFormShown).toEqual(false); - } else { - expect(component.isEPersonFormShown).toEqual(true); - } - - }); - }); - - it('EPerson search section is hidden', () => { - expect(fixture.debugElement.query(By.css('#search'))).toBeNull(); - }); - }); - }); - describe('deleteEPerson', () => { describe('when you click on first delete eperson button', () => { let ePeopleIdsFoundBeforeDelete; diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.ts b/src/app/access-control/epeople-registry/epeople-registry.component.ts index fb045ebb883..221fa9fd71a 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.ts +++ b/src/app/access-control/epeople-registry/epeople-registry.component.ts @@ -22,6 +22,7 @@ import { PageInfo } from '../../core/shared/page-info.model'; import { NoContent } from '../../core/shared/NoContent.model'; import { PaginationService } from '../../core/pagination/pagination.service'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { getEPersonEditRoute, getEPersonsRoute } from '../access-control-routing-paths'; @Component({ selector: 'ds-epeople-registry', @@ -64,11 +65,6 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { currentPage: 1 }); - /** - * Whether or not to show the EPerson form - */ - isEPersonFormShown: boolean; - // The search form searchForm; @@ -114,17 +110,11 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { */ initialisePage() { this.searching$.next(true); - this.isEPersonFormShown = false; this.search({scope: this.currentSearchScope, query: this.currentSearchQuery}); - this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => { - if (eperson != null && eperson.id) { - this.isEPersonFormShown = true; - } - })); this.subs.push(this.ePeople$.pipe( switchMap((epeople: PaginatedList) => { if (epeople.pageInfo.totalElements > 0) { - return combineLatest([...epeople.page.map((eperson: EPerson) => { + return combineLatest(epeople.page.map((eperson: EPerson) => { return this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined).pipe( map((authorized) => { const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); @@ -133,7 +123,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { return epersonDtoModel; }) ); - })]).pipe(map((dtos: EpersonDtoModel[]) => { + })).pipe(map((dtos: EpersonDtoModel[]) => { return buildPaginatedList(epeople.pageInfo, dtos); })); } else { @@ -160,14 +150,14 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { const query: string = data.query; const scope: string = data.scope; if (query != null && this.currentSearchQuery !== query) { - this.router.navigate([this.epersonService.getEPeoplePageRouterLink()], { + void this.router.navigate([getEPersonsRoute()], { queryParamsHandling: 'merge' }); this.currentSearchQuery = query; this.paginationService.resetPage(this.config.id); } if (scope != null && this.currentSearchScope !== scope) { - this.router.navigate([this.epersonService.getEPeoplePageRouterLink()], { + void this.router.navigate([getEPersonsRoute()], { queryParamsHandling: 'merge' }); this.currentSearchScope = scope; @@ -205,23 +195,6 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { return this.epersonService.getActiveEPerson(); } - /** - * Start editing the selected EPerson - * @param ePerson - */ - toggleEditEPerson(ePerson: EPerson) { - this.getActiveEPerson().pipe(take(1)).subscribe((activeEPerson: EPerson) => { - if (ePerson === activeEPerson) { - this.epersonService.cancelEditEPerson(); - this.isEPersonFormShown = false; - } else { - this.epersonService.editEPerson(ePerson); - this.isEPersonFormShown = true; - } - }); - this.scrollToTop(); - } - /** * Deletes EPerson, show notification on success/failure & updates EPeople list */ @@ -264,16 +237,6 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe()); } - scrollToTop() { - (function smoothscroll() { - const currentScroll = document.documentElement.scrollTop || document.body.scrollTop; - if (currentScroll > 0) { - window.requestAnimationFrame(smoothscroll); - window.scrollTo(0, currentScroll - (currentScroll / 8)); - } - })(); - } - /** * Reset all input-fields to be empty and search all search */ @@ -284,20 +247,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { this.search({query: ''}); } - /** - * This method will set everything to stale, which will cause the lists on this page to update. - */ - reset(): void { - this.epersonService.getBrowseEndpoint().pipe( - take(1), - switchMap((href: string) => { - return this.requestService.setStaleByHrefSubstring(href).pipe( - take(1), - ); - }) - ).subscribe(()=>{ - this.epersonService.cancelEditEPerson(); - this.isEPersonFormShown = false; - }); + getEditEPeoplePage(id: string): string { + return getEPersonEditRoute(id); } } diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html index 228449a8a57..493209f0a27 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html @@ -1,89 +1,98 @@ -
    +
    +
    +
    - -

    {{messagePrefix + '.create' | translate}}

    -
    +
    - -

    {{messagePrefix + '.edit' | translate}}

    -
    + +

    {{messagePrefix + '.create' | translate}}

    +
    - -
    - -
    -
    - -
    -
    - - -
    - -
    + +

    {{messagePrefix + '.edit' | translate}}

    +
    - + +
    + +
    +
    + +
    +
    + + +
    + +
    -
    -
    {{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}
    + - +
    +
    {{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}
    - + -
    - - - - - - - - - - - - - - - -
    {{messagePrefix + '.table.id' | translate}}{{messagePrefix + '.table.name' | translate}}{{messagePrefix + '.table.collectionOrCommunity' | translate}}
    {{group.id}} - - {{ dsoNameService.getName(group) }} - - {{ dsoNameService.getName(undefined) }}
    -
    + + +
    + + + + + + + + + + + + + + + +
    {{messagePrefix + '.table.id' | translate}}{{messagePrefix + '.table.name' | translate}}{{messagePrefix + '.table.collectionOrCommunity' | translate}}
    {{group.id}} + + {{ dsoNameService.getName(group) }} + + {{ dsoNameService.getName(undefined) }}
    +
    -
    +
    -
    diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts index fb911e709c4..1402f79ae3e 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts @@ -31,6 +31,10 @@ import { PaginationServiceStub } from '../../../shared/testing/pagination-servic import { FindListOptions } from '../../../core/data/find-list-options.model'; import { ValidateEmailNotTaken } from './validators/email-taken.validator'; import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service'; +import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RouterStub } from '../../../shared/testing/router.stub'; +import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub'; describe('EPersonFormComponent', () => { let component: EPersonFormComponent; @@ -43,6 +47,8 @@ describe('EPersonFormComponent', () => { let authorizationService: AuthorizationDataService; let groupsDataService: GroupDataService; let epersonRegistrationService: EpersonRegistrationService; + let route: ActivatedRouteStub; + let router: RouterStub; let paginationService; @@ -106,6 +112,9 @@ describe('EPersonFormComponent', () => { }, getEPersonByEmail(email): Observable> { return createSuccessfulRemoteDataObject$(null); + }, + findById(_id: string, _useCachedVersionIfAvailable = true, _reRequestOnStale = true, ..._linksToFollow: FollowLinkConfig[]): Observable> { + return createSuccessfulRemoteDataObject$(null); } }; builderService = Object.assign(getMockFormBuilderService(),{ @@ -182,6 +191,8 @@ describe('EPersonFormComponent', () => { }); paginationService = new PaginationServiceStub(); + route = new ActivatedRouteStub(); + router = new RouterStub(); TestBed.configureTestingModule({ imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule, TranslateModule.forRoot({ @@ -202,6 +213,8 @@ describe('EPersonFormComponent', () => { { provide: PaginationService, useValue: paginationService }, { provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring'])}, { provide: EpersonRegistrationService, useValue: epersonRegistrationService }, + { provide: ActivatedRoute, useValue: route }, + { provide: Router, useValue: router }, EPeopleRegistryComponent ], schemas: [NO_ERRORS_SCHEMA] @@ -263,24 +276,18 @@ describe('EPersonFormComponent', () => { fixture.detectChanges(); }); describe('firstName, lastName and email should be required', () => { - it('form should be invalid because the firstName is required', waitForAsync(() => { - fixture.whenStable().then(() => { - expect(component.formGroup.controls.firstName.valid).toBeFalse(); - expect(component.formGroup.controls.firstName.errors.required).toBeTrue(); - }); - })); - it('form should be invalid because the lastName is required', waitForAsync(() => { - fixture.whenStable().then(() => { - expect(component.formGroup.controls.lastName.valid).toBeFalse(); - expect(component.formGroup.controls.lastName.errors.required).toBeTrue(); - }); - })); - it('form should be invalid because the email is required', waitForAsync(() => { - fixture.whenStable().then(() => { - expect(component.formGroup.controls.email.valid).toBeFalse(); - expect(component.formGroup.controls.email.errors.required).toBeTrue(); - }); - })); + it('form should be invalid because the firstName is required', () => { + expect(component.formGroup.controls.firstName.valid).toBeFalse(); + expect(component.formGroup.controls.firstName.errors.required).toBeTrue(); + }); + it('form should be invalid because the lastName is required', () => { + expect(component.formGroup.controls.lastName.valid).toBeFalse(); + expect(component.formGroup.controls.lastName.errors.required).toBeTrue(); + }); + it('form should be invalid because the email is required', () => { + expect(component.formGroup.controls.email.valid).toBeFalse(); + expect(component.formGroup.controls.email.errors.required).toBeTrue(); + }); }); describe('after inserting information firstName,lastName and email not required', () => { @@ -290,24 +297,18 @@ describe('EPersonFormComponent', () => { component.formGroup.controls.email.setValue('test@test.com'); fixture.detectChanges(); }); - it('firstName should be valid because the firstName is set', waitForAsync(() => { - fixture.whenStable().then(() => { + it('firstName should be valid because the firstName is set', () => { expect(component.formGroup.controls.firstName.valid).toBeTrue(); expect(component.formGroup.controls.firstName.errors).toBeNull(); - }); - })); - it('lastName should be valid because the lastName is set', waitForAsync(() => { - fixture.whenStable().then(() => { + }); + it('lastName should be valid because the lastName is set', () => { expect(component.formGroup.controls.lastName.valid).toBeTrue(); expect(component.formGroup.controls.lastName.errors).toBeNull(); - }); - })); - it('email should be valid because the email is set', waitForAsync(() => { - fixture.whenStable().then(() => { + }); + it('email should be valid because the email is set', () => { expect(component.formGroup.controls.email.valid).toBeTrue(); expect(component.formGroup.controls.email.errors).toBeNull(); - }); - })); + }); }); @@ -316,12 +317,10 @@ describe('EPersonFormComponent', () => { component.formGroup.controls.email.setValue('test@test'); fixture.detectChanges(); }); - it('email should not be valid because the email pattern', waitForAsync(() => { - fixture.whenStable().then(() => { + it('email should not be valid because the email pattern', () => { expect(component.formGroup.controls.email.valid).toBeFalse(); expect(component.formGroup.controls.email.errors.pattern).toBeTruthy(); - }); - })); + }); }); describe('after already utilized email', () => { @@ -336,12 +335,10 @@ describe('EPersonFormComponent', () => { fixture.detectChanges(); }); - it('email should not be valid because email is already taken', waitForAsync(() => { - fixture.whenStable().then(() => { + it('email should not be valid because email is already taken', () => { expect(component.formGroup.controls.email.valid).toBeFalse(); expect(component.formGroup.controls.email.errors.emailTaken).toBeTruthy(); - }); - })); + }); }); @@ -393,11 +390,9 @@ describe('EPersonFormComponent', () => { fixture.detectChanges(); }); - it('should emit a new eperson using the correct values', waitForAsync(() => { - fixture.whenStable().then(() => { - expect(component.submitForm.emit).toHaveBeenCalledWith(expected); - }); - })); + it('should emit a new eperson using the correct values', () => { + expect(component.submitForm.emit).toHaveBeenCalledWith(expected); + }); }); describe('with an active eperson', () => { @@ -428,11 +423,9 @@ describe('EPersonFormComponent', () => { fixture.detectChanges(); }); - it('should emit the existing eperson using the correct values', waitForAsync(() => { - fixture.whenStable().then(() => { - expect(component.submitForm.emit).toHaveBeenCalledWith(expectedWithId); - }); - })); + it('should emit the existing eperson using the correct values', () => { + expect(component.submitForm.emit).toHaveBeenCalledWith(expectedWithId); + }); }); }); diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts index d009d560589..d7d5a0b49c7 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.ts @@ -38,6 +38,8 @@ import { Registration } from '../../../core/shared/registration.model'; import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service'; import { TYPE_REQUEST_FORGOT } from '../../../register-email-form/register-email-form.component'; import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { getEPersonsRoute } from '../../access-control-routing-paths'; @Component({ selector: 'ds-eperson-form', @@ -194,6 +196,8 @@ export class EPersonFormComponent implements OnInit, OnDestroy { public requestService: RequestService, private epersonRegistrationService: EpersonRegistrationService, public dsoNameService: DSONameService, + protected route: ActivatedRoute, + protected router: Router, ) { this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => { this.epersonInitial = eperson; @@ -213,7 +217,9 @@ export class EPersonFormComponent implements OnInit, OnDestroy { * This method will initialise the page */ initialisePage() { - + this.subs.push(this.epersonService.findById(this.route.snapshot.params.id).subscribe((ePersonRD: RemoteData) => { + this.epersonService.editEPerson(ePersonRD.payload); + })); observableCombineLatest([ this.translateService.get(`${this.messagePrefix}.firstName`), this.translateService.get(`${this.messagePrefix}.lastName`), @@ -339,6 +345,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy { onCancel() { this.epersonService.cancelEditEPerson(); this.cancelForm.emit(); + void this.router.navigate([getEPersonsRoute()]); } /** @@ -390,6 +397,8 @@ export class EPersonFormComponent implements OnInit, OnDestroy { if (rd.hasSucceeded) { this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.created.success', { name: this.dsoNameService.getName(ePersonToCreate) })); this.submitForm.emit(ePersonToCreate); + this.epersonService.clearEPersonRequests(); + void this.router.navigateByUrl(getEPersonsRoute()); } else { this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.created.failure', { name: this.dsoNameService.getName(ePersonToCreate) })); this.cancelForm.emit(); @@ -429,6 +438,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy { if (rd.hasSucceeded) { this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.edited.success', { name: this.dsoNameService.getName(editedEperson) })); this.submitForm.emit(editedEperson); + void this.router.navigateByUrl(getEPersonsRoute()); } else { this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.edited.failure', { name: this.dsoNameService.getName(editedEperson) })); this.cancelForm.emit(); @@ -495,6 +505,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy { ).subscribe(({ restResponse, eperson }: { restResponse: RemoteData | null, eperson: EPerson }) => { if (restResponse?.hasSucceeded) { this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: this.dsoNameService.getName(eperson) })); + void this.router.navigate([getEPersonsRoute()]); } else { this.notificationsService.error(`Error occurred when trying to delete EPerson with id: ${eperson?.id} with code: ${restResponse?.statusCode} and message: ${restResponse?.errorMessage}`); } @@ -541,16 +552,6 @@ export class EPersonFormComponent implements OnInit, OnDestroy { } } - /** - * This method will ensure that the page gets reset and that the cache is cleared - */ - reset() { - this.epersonService.getActiveEPerson().pipe(take(1)).subscribe((eperson: EPerson) => { - this.requestService.removeByHrefSubstring(eperson.self); - }); - this.initialisePage(); - } - /** * Checks for the given ePerson if there is already an ePerson in the system with that email * and shows notification if this is the case diff --git a/src/app/access-control/epeople-registry/eperson-resolver.service.ts b/src/app/access-control/epeople-registry/eperson-resolver.service.ts new file mode 100644 index 00000000000..1db8e70d899 --- /dev/null +++ b/src/app/access-control/epeople-registry/eperson-resolver.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; +import { EPerson } from '../../core/eperson/models/eperson.model'; +import { RemoteData } from '../../core/data/remote-data'; +import { getFirstCompletedRemoteData } from '../../core/shared/operators'; +import { ResolvedAction } from '../../core/resolving/resolver.actions'; +import { EPersonDataService } from '../../core/eperson/eperson-data.service'; +import { Store } from '@ngrx/store'; +import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; + +export const EPERSON_EDIT_FOLLOW_LINKS: FollowLinkConfig[] = [ + followLink('groups'), +]; + +/** + * This class represents a resolver that requests a specific {@link EPerson} before the route is activated + */ +@Injectable({ + providedIn: 'root', +}) +export class EPersonResolver implements Resolve> { + + constructor( + protected ePersonService: EPersonDataService, + protected store: Store, + ) { + } + + /** + * Method for resolving a {@link EPerson} based on the parameters in the current route + * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot + * @param {RouterStateSnapshot} state The current RouterStateSnapshot + * @returns `Observable<>` Emits the found {@link EPerson} based on the parameters in the current + * route, or an error if something went wrong + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable> { + const ePersonRD$: Observable> = this.ePersonService.findById(route.params.id, + true, + false, + ...EPERSON_EDIT_FOLLOW_LINKS, + ).pipe( + getFirstCompletedRemoteData(), + ); + + ePersonRD$.subscribe((ePersonRD: RemoteData) => { + this.store.dispatch(new ResolvedAction(state.url, ePersonRD.payload)); + }); + + return ePersonRD$; + } + +} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..2a552296163 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -248,6 +248,14 @@ "admin.access-control.epeople.title": "EPeople", + "admin.access-control.epeople.edit.breadcrumbs": "New EPerson", + + "admin.access-control.epeople.edit.title": "New EPerson", + + "admin.access-control.epeople.add.breadcrumbs": "Add EPerson", + + "admin.access-control.epeople.add.title": "Add EPerson", + "admin.access-control.epeople.head": "EPeople", "admin.access-control.epeople.search.head": "Search", From 9ac19d40fc26275d53a50deed3a8151e07955113 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 21 Jul 2023 15:11:01 +0200 Subject: [PATCH 035/196] Cleanup access-control components - Use the same methods to retrieve the access-control urls - Fix EPersonDataService.startEditingNewEPerson returning the incorrect link --- .../access-control-routing-paths.ts | 6 ++--- .../access-control-routing.module.ts | 8 +++---- .../epeople-registry.component.ts | 2 +- .../group-form/group-form.component.html | 4 ++-- .../group-form/group-form.component.ts | 24 +++++++++---------- .../groups-registry.component.html | 2 +- src/app/core/eperson/eperson-data.service.ts | 6 ++--- src/app/core/eperson/group-data.service.ts | 7 +++--- .../entry/resource-policy-entry.component.ts | 5 ++-- 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/app/access-control/access-control-routing-paths.ts b/src/app/access-control/access-control-routing-paths.ts index c3c42b3155d..c8b9e01793f 100644 --- a/src/app/access-control/access-control-routing-paths.ts +++ b/src/app/access-control/access-control-routing-paths.ts @@ -11,12 +11,12 @@ export function getEPersonEditRoute(id: string): string { return new URLCombiner(getEPersonsRoute(), id).toString(); } -export const GROUP_EDIT_PATH = 'groups'; +export const GROUP_PATH = 'groups'; export function getGroupsRoute() { - return new URLCombiner(getAccessControlModuleRoute(), GROUP_EDIT_PATH).toString(); + return new URLCombiner(getAccessControlModuleRoute(), GROUP_PATH).toString(); } export function getGroupEditRoute(id: string) { - return new URLCombiner(getAccessControlModuleRoute(), GROUP_EDIT_PATH, id).toString(); + return new URLCombiner(getGroupsRoute(), id).toString(); } diff --git a/src/app/access-control/access-control-routing.module.ts b/src/app/access-control/access-control-routing.module.ts index a4082d19e2f..4ef97cb5eab 100644 --- a/src/app/access-control/access-control-routing.module.ts +++ b/src/app/access-control/access-control-routing.module.ts @@ -3,7 +3,7 @@ import { RouterModule } from '@angular/router'; import { EPeopleRegistryComponent } from './epeople-registry/epeople-registry.component'; import { GroupFormComponent } from './group-registry/group-form/group-form.component'; import { GroupsRegistryComponent } from './group-registry/groups-registry.component'; -import { EPERSON_PATH, GROUP_EDIT_PATH } from './access-control-routing-paths'; +import { EPERSON_PATH, GROUP_PATH } from './access-control-routing-paths'; import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver'; import { GroupPageGuard } from './group-registry/group-page.guard'; import { @@ -48,7 +48,7 @@ import { EPersonResolver } from './epeople-registry/eperson-resolver.service'; canActivate: [SiteAdministratorGuard], }, { - path: GROUP_EDIT_PATH, + path: GROUP_PATH, component: GroupsRegistryComponent, resolve: { breadcrumb: I18nBreadcrumbResolver @@ -57,7 +57,7 @@ import { EPersonResolver } from './epeople-registry/eperson-resolver.service'; canActivate: [GroupAdministratorGuard] }, { - path: `${GROUP_EDIT_PATH}/newGroup`, + path: `${GROUP_PATH}/create`, component: GroupFormComponent, resolve: { breadcrumb: I18nBreadcrumbResolver @@ -66,7 +66,7 @@ import { EPersonResolver } from './epeople-registry/eperson-resolver.service'; canActivate: [GroupAdministratorGuard] }, { - path: `${GROUP_EDIT_PATH}/:groupId`, + path: `${GROUP_PATH}/:groupId`, component: GroupFormComponent, resolve: { breadcrumb: I18nBreadcrumbResolver diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.ts b/src/app/access-control/epeople-registry/epeople-registry.component.ts index 221fa9fd71a..d2837a5317e 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.ts +++ b/src/app/access-control/epeople-registry/epeople-registry.component.ts @@ -215,7 +215,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { if (restResponse.hasSucceeded) { this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', {name: this.dsoNameService.getName(ePerson)})); } else { - this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + ePerson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.errorMessage); + this.notificationsService.error(`Error occurred when trying to delete EPerson with id: ${ePerson.id} with code: ${restResponse.statusCode} and message: ${restResponse.errorMessage}`); } }); } diff --git a/src/app/access-control/group-registry/group-form/group-form.component.html b/src/app/access-control/group-registry/group-form/group-form.component.html index 77a81a8daa0..0515b071ae6 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.html +++ b/src/app/access-control/group-registry/group-form/group-form.component.html @@ -2,13 +2,13 @@
    -
    +

    {{messagePrefix + '.head.create' | translate}}

    - +

    {{messagePrefix + 'head' | translate}}

    diff --git a/src/app/core/eperson/eperson-data.service.ts b/src/app/core/eperson/eperson-data.service.ts index d30030365ca..00620655de4 100644 --- a/src/app/core/eperson/eperson-data.service.ts +++ b/src/app/core/eperson/eperson-data.service.ts @@ -34,6 +34,7 @@ import { PatchData, PatchDataImpl } from '../data/base/patch-data'; import { DeleteData, DeleteDataImpl } from '../data/base/delete-data'; import { RestRequestMethod } from '../data/rest-request-method'; import { dataService } from '../data/base/data-service.decorator'; +import { getEPersonEditRoute, getEPersonsRoute } from '../../access-control/access-control-routing-paths'; const ePeopleRegistryStateSelector = (state: AppState) => state.epeopleRegistry; const editEPersonSelector = createSelector(ePeopleRegistryStateSelector, (ePeopleRegistryState: EPeopleRegistryState) => ePeopleRegistryState.editEPerson); @@ -281,15 +282,14 @@ export class EPersonDataService extends IdentifiableDataService impleme this.editEPerson(ePerson); } }); - return '/access-control/epeople'; + return getEPersonEditRoute(ePerson.id); } /** * Get EPeople admin page - * @param ePerson New EPerson to edit */ public getEPeoplePageRouterLink(): string { - return '/access-control/epeople'; + return getEPersonsRoute(); } /** diff --git a/src/app/core/eperson/group-data.service.ts b/src/app/core/eperson/group-data.service.ts index bb38e467588..7b3a14c70b2 100644 --- a/src/app/core/eperson/group-data.service.ts +++ b/src/app/core/eperson/group-data.service.ts @@ -40,6 +40,7 @@ import { DeleteData, DeleteDataImpl } from '../data/base/delete-data'; import { Operation } from 'fast-json-patch'; import { RestRequestMethod } from '../data/rest-request-method'; import { dataService } from '../data/base/data-service.decorator'; +import { getGroupEditRoute } from '../../access-control/access-control-routing-paths'; const groupRegistryStateSelector = (state: AppState) => state.groupRegistry; const editGroupSelector = createSelector(groupRegistryStateSelector, (groupRegistryState: GroupRegistryState) => groupRegistryState.editGroup); @@ -264,15 +265,15 @@ export class GroupDataService extends IdentifiableDataService implements * @param group Group we want edit page for */ public getGroupEditPageRouterLink(group: Group): string { - return this.getGroupEditPageRouterLinkWithID(group.id); + return getGroupEditRoute(group.id); } /** * Get Edit page of group * @param groupID Group ID we want edit page for */ - public getGroupEditPageRouterLinkWithID(groupId: string): string { - return '/access-control/groups/' + groupId; + public getGroupEditPageRouterLinkWithID(groupID: string): string { + return getGroupEditRoute(groupID); } /** diff --git a/src/app/shared/resource-policies/entry/resource-policy-entry.component.ts b/src/app/shared/resource-policies/entry/resource-policy-entry.component.ts index 904a79cbe61..83733c7011c 100644 --- a/src/app/shared/resource-policies/entry/resource-policy-entry.component.ts +++ b/src/app/shared/resource-policies/entry/resource-policy-entry.component.ts @@ -17,8 +17,7 @@ import { RemoteData } from '../../../core/data/remote-data'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { ActivatedRoute, Router } from '@angular/router'; import { Group } from '../../../core/eperson/models/group.model'; -import { ACCESS_CONTROL_MODULE_PATH } from '../../../app-routing-paths'; -import { GROUP_EDIT_PATH } from '../../../access-control/access-control-routing-paths'; +import { getGroupEditRoute } from '../../../access-control/access-control-routing-paths'; import { GroupDataService } from '../../../core/eperson/group-data.service'; export interface ResourcePolicyCheckboxEntry { @@ -97,7 +96,7 @@ export class ResourcePolicyEntryComponent implements OnInit { getFirstSucceededRemoteDataPayload(), map((group: Group) => group.id), ).subscribe((groupUUID) => { - this.router.navigate([ACCESS_CONTROL_MODULE_PATH, GROUP_EDIT_PATH, groupUUID]); + void this.router.navigate([getGroupEditRoute(groupUUID)]); }); } } From 998e1fac8de2707a62c729250a82f439b173b33c Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 21 Jul 2023 17:48:27 +0200 Subject: [PATCH 036/196] Fix spacing issues for EPerson form buttons --- .../eperson-form/eperson-form.component.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html index 493209f0a27..88c4f99870d 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.html @@ -29,9 +29,8 @@

    {{messagePrefix + '.edit' | translate}}

    {{'admin.access-control.epeople.actions.reset' | translate}}
    -
    - -
    - diff --git a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts index 1402f79ae3e..b9aeeb0af26 100644 --- a/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts +++ b/src/app/access-control/epeople-registry/eperson-form/eperson-form.component.spec.ts @@ -484,16 +484,16 @@ describe('EPersonFormComponent', () => { }); - it('the delete button should be active if the eperson can be deleted', () => { + it('the delete button should be visible if the ePerson can be deleted', () => { const deleteButton = fixture.debugElement.query(By.css('.delete-button')); - expect(deleteButton.nativeElement.disabled).toBe(false); + expect(deleteButton).not.toBeNull(); }); - it('the delete button should be disabled if the eperson cannot be deleted', () => { + it('the delete button should be hidden if the ePerson cannot be deleted', () => { component.canDelete$ = observableOf(false); fixture.detectChanges(); const deleteButton = fixture.debugElement.query(By.css('.delete-button')); - expect(deleteButton.nativeElement.disabled).toBe(true); + expect(deleteButton).toBeNull(); }); it('should call the epersonFormComponent delete when clicked on the button', () => { diff --git a/src/app/access-control/group-registry/group-form/group-form.component.html b/src/app/access-control/group-registry/group-form/group-form.component.html index 0515b071ae6..d5003911aec 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.html +++ b/src/app/access-control/group-registry/group-form/group-form.component.html @@ -39,7 +39,7 @@

    -
    +
    \ No newline at end of file + diff --git a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.spec.ts b/src/app/shared/log-in/methods/oidc/log-in-oidc.component.spec.ts index 078a58dd5a7..93559689e80 100644 --- a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.spec.ts +++ b/src/app/shared/log-in/methods/oidc/log-in-oidc.component.spec.ts @@ -3,11 +3,8 @@ import { ActivatedRoute, Router } from '@angular/router'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { provideMockStore } from '@ngrx/store/testing'; -import { Store, StoreModule } from '@ngrx/store'; +import { StoreModule } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; - -import { EPerson } from '../../../../core/eperson/models/eperson.model'; -import { EPersonMock } from '../../../testing/eperson.mock'; import { authReducer } from '../../../../core/auth/auth.reducer'; import { AuthService } from '../../../../core/auth/auth.service'; import { AuthServiceStub } from '../../../testing/auth-service.stub'; @@ -20,23 +17,22 @@ import { RouterStub } from '../../../testing/router.stub'; import { ActivatedRouteStub } from '../../../testing/active-router.stub'; import { NativeWindowMockFactory } from '../../../mocks/mock-native-window-ref'; import { HardRedirectService } from '../../../../core/services/hard-redirect.service'; +import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service'; +import { AuthorizationDataServiceStub } from '../../../testing/authorization-service.stub'; describe('LogInOidcComponent', () => { let component: LogInOidcComponent; let fixture: ComponentFixture; - let page: Page; - let user: EPerson; let componentAsAny: any; let setHrefSpy; - let oidcBaseUrl; - let location; + let oidcBaseUrl: string; + let location: string; let initialState: any; let hardRedirectService: HardRedirectService; beforeEach(() => { - user = EPersonMock; oidcBaseUrl = 'dspace-rest.test/oidc?redirectUrl='; location = oidcBaseUrl + 'http://dspace-angular.test/home'; @@ -60,7 +56,7 @@ describe('LogInOidcComponent', () => { beforeEach(waitForAsync(() => { // refine the test module by declaring the test component - TestBed.configureTestingModule({ + void TestBed.configureTestingModule({ imports: [ StoreModule.forRoot({ auth: authReducer }, storeModuleConfig), TranslateModule.forRoot() @@ -70,7 +66,8 @@ describe('LogInOidcComponent', () => { ], providers: [ { provide: AuthService, useClass: AuthServiceStub }, - { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Oidc, location) }, + { provide: AuthorizationDataService, useClass: AuthorizationDataServiceStub }, + { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Oidc, 0, location) }, { provide: 'isStandalonePage', useValue: true }, { provide: NativeWindowService, useFactory: NativeWindowMockFactory }, { provide: Router, useValue: new RouterStub() }, @@ -95,7 +92,6 @@ describe('LogInOidcComponent', () => { componentAsAny = component; // create page - page = new Page(component, fixture); setHrefSpy = spyOnProperty(componentAsAny._window.nativeWindow.location, 'href', 'set').and.callThrough(); }); @@ -131,25 +127,3 @@ describe('LogInOidcComponent', () => { }); }); - -/** - * I represent the DOM elements and attach spies. - * - * @class Page - */ -class Page { - - public emailInput: HTMLInputElement; - public navigateSpy: jasmine.Spy; - public passwordInput: HTMLInputElement; - - constructor(private component: LogInOidcComponent, private fixture: ComponentFixture) { - // use injector to get services - const injector = fixture.debugElement.injector; - const store = injector.get(Store); - - // add spies - this.navigateSpy = spyOn(store, 'dispatch'); - } - -} diff --git a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.html b/src/app/shared/log-in/methods/orcid/log-in-orcid.component.html index 6f5453fd60c..2260197ab4a 100644 --- a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.html +++ b/src/app/shared/log-in/methods/orcid/log-in-orcid.component.html @@ -1,3 +1,3 @@ - \ No newline at end of file + diff --git a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.spec.ts b/src/app/shared/log-in/methods/orcid/log-in-orcid.component.spec.ts index 001f0a4959d..0782f15720c 100644 --- a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.spec.ts +++ b/src/app/shared/log-in/methods/orcid/log-in-orcid.component.spec.ts @@ -3,11 +3,8 @@ import { ActivatedRoute, Router } from '@angular/router'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { provideMockStore } from '@ngrx/store/testing'; -import { Store, StoreModule } from '@ngrx/store'; +import { StoreModule } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; - -import { EPerson } from '../../../../core/eperson/models/eperson.model'; -import { EPersonMock } from '../../../testing/eperson.mock'; import { authReducer } from '../../../../core/auth/auth.reducer'; import { AuthService } from '../../../../core/auth/auth.service'; import { AuthServiceStub } from '../../../testing/auth-service.stub'; @@ -26,17 +23,14 @@ describe('LogInOrcidComponent', () => { let component: LogInOrcidComponent; let fixture: ComponentFixture; - let page: Page; - let user: EPerson; let componentAsAny: any; let setHrefSpy; - let orcidBaseUrl; - let location; + let orcidBaseUrl: string; + let location: string; let initialState: any; let hardRedirectService: HardRedirectService; beforeEach(() => { - user = EPersonMock; orcidBaseUrl = 'dspace-rest.test/orcid?redirectUrl='; location = orcidBaseUrl + 'http://dspace-angular.test/home'; @@ -60,7 +54,7 @@ describe('LogInOrcidComponent', () => { beforeEach(waitForAsync(() => { // refine the test module by declaring the test component - TestBed.configureTestingModule({ + void TestBed.configureTestingModule({ imports: [ StoreModule.forRoot({ auth: authReducer }, storeModuleConfig), TranslateModule.forRoot() @@ -70,7 +64,7 @@ describe('LogInOrcidComponent', () => { ], providers: [ { provide: AuthService, useClass: AuthServiceStub }, - { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Orcid, location) }, + { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Orcid, 0, location) }, { provide: 'isStandalonePage', useValue: true }, { provide: NativeWindowService, useFactory: NativeWindowMockFactory }, { provide: Router, useValue: new RouterStub() }, @@ -95,7 +89,6 @@ describe('LogInOrcidComponent', () => { componentAsAny = component; // create page - page = new Page(component, fixture); setHrefSpy = spyOnProperty(componentAsAny._window.nativeWindow.location, 'href', 'set').and.callThrough(); }); @@ -131,25 +124,3 @@ describe('LogInOrcidComponent', () => { }); }); - -/** - * I represent the DOM elements and attach spies. - * - * @class Page - */ -class Page { - - public emailInput: HTMLInputElement; - public navigateSpy: jasmine.Spy; - public passwordInput: HTMLInputElement; - - constructor(private component: LogInOrcidComponent, private fixture: ComponentFixture) { - // use injector to get services - const injector = fixture.debugElement.injector; - const store = injector.get(Store); - - // add spies - this.navigateSpy = spyOn(store, 'dispatch'); - } - -} diff --git a/src/app/shared/log-in/methods/password/log-in-password.component.html b/src/app/shared/log-in/methods/password/log-in-password.component.html index c1f1016cb8e..60477d141de 100644 --- a/src/app/shared/log-in/methods/password/log-in-password.component.html +++ b/src/app/shared/log-in/methods/password/log-in-password.component.html @@ -28,3 +28,12 @@ + + diff --git a/src/app/shared/log-in/methods/password/log-in-password.component.scss b/src/app/shared/log-in/methods/password/log-in-password.component.scss index 0eda382c0a6..955252b51e9 100644 --- a/src/app/shared/log-in/methods/password/log-in-password.component.scss +++ b/src/app/shared/log-in/methods/password/log-in-password.component.scss @@ -11,3 +11,7 @@ border-top-right-radius: 0; } +.dropdown-item { + white-space: normal; + padding: .25rem .75rem; +} diff --git a/src/app/shared/log-in/methods/password/log-in-password.component.spec.ts b/src/app/shared/log-in/methods/password/log-in-password.component.spec.ts index 5238482770d..94d18fe768c 100644 --- a/src/app/shared/log-in/methods/password/log-in-password.component.spec.ts +++ b/src/app/shared/log-in/methods/password/log-in-password.component.spec.ts @@ -8,8 +8,6 @@ import { Store, StoreModule } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; import { LogInPasswordComponent } from './log-in-password.component'; -import { EPerson } from '../../../../core/eperson/models/eperson.model'; -import { EPersonMock } from '../../../testing/eperson.mock'; import { authReducer } from '../../../../core/auth/auth.reducer'; import { AuthService } from '../../../../core/auth/auth.service'; import { AuthServiceStub } from '../../../testing/auth-service.stub'; @@ -18,19 +16,18 @@ import { AuthMethod } from '../../../../core/auth/models/auth.method'; import { AuthMethodType } from '../../../../core/auth/models/auth.method-type'; import { HardRedirectService } from '../../../../core/services/hard-redirect.service'; import { BrowserOnlyMockPipe } from '../../../testing/browser-only-mock.pipe'; +import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service'; +import { AuthorizationDataServiceStub } from '../../../testing/authorization-service.stub'; describe('LogInPasswordComponent', () => { let component: LogInPasswordComponent; let fixture: ComponentFixture; let page: Page; - let user: EPerson; let initialState: any; let hardRedirectService: HardRedirectService; beforeEach(() => { - user = EPersonMock; - hardRedirectService = jasmine.createSpyObj('hardRedirectService', { getCurrentRoute: {} }); @@ -50,7 +47,7 @@ describe('LogInPasswordComponent', () => { beforeEach(waitForAsync(() => { // refine the test module by declaring the test component - TestBed.configureTestingModule({ + void TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, @@ -63,7 +60,8 @@ describe('LogInPasswordComponent', () => { ], providers: [ { provide: AuthService, useClass: AuthServiceStub }, - { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Password) }, + { provide: AuthorizationDataService, useClass: AuthorizationDataServiceStub }, + { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Password, 0) }, { provide: 'isStandalonePage', useValue: true }, { provide: HardRedirectService, useValue: hardRedirectService }, provideMockStore({ initialState }), @@ -76,7 +74,7 @@ describe('LogInPasswordComponent', () => { })); - beforeEach(() => { + beforeEach(async () => { // create component and test fixture fixture = TestBed.createComponent(LogInPasswordComponent); @@ -87,10 +85,8 @@ describe('LogInPasswordComponent', () => { page = new Page(component, fixture); // verify the fixture is stable (no pending tasks) - fixture.whenStable().then(() => { - page.addPageElements(); - }); - + await fixture.whenStable(); + page.addPageElements(); }); it('should create a FormGroup comprised of FormControls', () => { diff --git a/src/app/shared/log-in/methods/password/log-in-password.component.ts b/src/app/shared/log-in/methods/password/log-in-password.component.ts index e4a92ded296..e2fe92fafba 100644 --- a/src/app/shared/log-in/methods/password/log-in-password.component.ts +++ b/src/app/shared/log-in/methods/password/log-in-password.component.ts @@ -15,6 +15,9 @@ import { AuthMethod } from '../../../../core/auth/models/auth.method'; import { AuthService } from '../../../../core/auth/auth.service'; import { HardRedirectService } from '../../../../core/services/hard-redirect.service'; import { CoreState } from '../../../../core/core-state.model'; +import { getForgotPasswordRoute, getRegisterRoute } from '../../../../app-routing-paths'; +import { FeatureID } from '../../../../core/data/feature-authorization/feature-id'; +import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service'; /** * /users/sign-in @@ -66,21 +69,18 @@ export class LogInPasswordComponent implements OnInit { public form: FormGroup; /** - * @constructor - * @param {AuthMethod} injectedAuthMethodModel - * @param {boolean} isStandalonePage - * @param {AuthService} authService - * @param {HardRedirectService} hardRedirectService - * @param {FormBuilder} formBuilder - * @param {Store} store + * Whether the current user (or anonymous) is authorized to register an account */ + public canRegister$: Observable; + constructor( @Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod, @Inject('isStandalonePage') public isStandalonePage: boolean, private authService: AuthService, private hardRedirectService: HardRedirectService, private formBuilder: FormBuilder, - private store: Store + protected store: Store, + protected authorizationService: AuthorizationDataService, ) { this.authMethod = injectedAuthMethodModel; } @@ -115,6 +115,15 @@ export class LogInPasswordComponent implements OnInit { }) ); + this.canRegister$ = this.authorizationService.isAuthorized(FeatureID.EPersonRegistration); + } + + getRegisterRoute() { + return getRegisterRoute(); + } + + getForgotRoute() { + return getForgotPasswordRoute(); } /** diff --git a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.html b/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.html index 3a3b935cfa3..fca514b83d3 100644 --- a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.html +++ b/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.html @@ -1,3 +1,3 @@ - diff --git a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.spec.ts b/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.spec.ts index 075d33d98ef..afb0f2092ac 100644 --- a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.spec.ts +++ b/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.spec.ts @@ -3,11 +3,8 @@ import { ActivatedRoute, Router } from '@angular/router'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { provideMockStore } from '@ngrx/store/testing'; -import { Store, StoreModule } from '@ngrx/store'; +import { StoreModule } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; - -import { EPerson } from '../../../../core/eperson/models/eperson.model'; -import { EPersonMock } from '../../../testing/eperson.mock'; import { authReducer } from '../../../../core/auth/auth.reducer'; import { AuthService } from '../../../../core/auth/auth.service'; import { AuthServiceStub } from '../../../testing/auth-service.stub'; @@ -26,17 +23,14 @@ describe('LogInShibbolethComponent', () => { let component: LogInShibbolethComponent; let fixture: ComponentFixture; - let page: Page; - let user: EPerson; let componentAsAny: any; let setHrefSpy; - let shibbolethBaseUrl; - let location; + let shibbolethBaseUrl: string; + let location: string; let initialState: any; let hardRedirectService: HardRedirectService; beforeEach(() => { - user = EPersonMock; shibbolethBaseUrl = 'dspace-rest.test/shibboleth?redirectUrl='; location = shibbolethBaseUrl + 'http://dspace-angular.test/home'; @@ -60,7 +54,7 @@ describe('LogInShibbolethComponent', () => { beforeEach(waitForAsync(() => { // refine the test module by declaring the test component - TestBed.configureTestingModule({ + void TestBed.configureTestingModule({ imports: [ StoreModule.forRoot({ auth: authReducer }, storeModuleConfig), TranslateModule.forRoot() @@ -70,7 +64,7 @@ describe('LogInShibbolethComponent', () => { ], providers: [ { provide: AuthService, useClass: AuthServiceStub }, - { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Shibboleth, location) }, + { provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Shibboleth, 0, location) }, { provide: 'isStandalonePage', useValue: true }, { provide: NativeWindowService, useFactory: NativeWindowMockFactory }, { provide: Router, useValue: new RouterStub() }, @@ -95,7 +89,6 @@ describe('LogInShibbolethComponent', () => { componentAsAny = component; // create page - page = new Page(component, fixture); setHrefSpy = spyOnProperty(componentAsAny._window.nativeWindow.location, 'href', 'set').and.callThrough(); }); @@ -131,25 +124,3 @@ describe('LogInShibbolethComponent', () => { }); }); - -/** - * I represent the DOM elements and attach spies. - * - * @class Page - */ -class Page { - - public emailInput: HTMLInputElement; - public navigateSpy: jasmine.Spy; - public passwordInput: HTMLInputElement; - - constructor(private component: LogInShibbolethComponent, private fixture: ComponentFixture) { - // use injector to get services - const injector = fixture.debugElement.injector; - const store = injector.get(Store); - - // add spies - this.navigateSpy = spyOn(store, 'dispatch'); - } - -} diff --git a/src/app/shared/testing/auth-service.stub.ts b/src/app/shared/testing/auth-service.stub.ts index b8d822252d7..e974c5ca9ea 100644 --- a/src/app/shared/testing/auth-service.stub.ts +++ b/src/app/shared/testing/auth-service.stub.ts @@ -6,10 +6,11 @@ import { EPerson } from '../../core/eperson/models/eperson.model'; import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { AuthMethod } from '../../core/auth/models/auth.method'; import { hasValue } from '../empty.util'; +import { AuthMethodType } from '../../core/auth/models/auth.method-type'; -export const authMethodsMock = [ - new AuthMethod('password'), - new AuthMethod('shibboleth', 'dspace.test/shibboleth') +export const authMethodsMock: AuthMethod[] = [ + new AuthMethod(AuthMethodType.Password, 0), + new AuthMethod(AuthMethodType.Shibboleth, 1, 'dspace.test/shibboleth'), ]; export class AuthServiceStub { diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 597f226cc75..4e875d61f22 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2560,8 +2560,6 @@ "login.form.new-user": "New user? Click here to register.", - "login.form.or-divider": "or", - "login.form.oidc": "Log in with OIDC", "login.form.orcid": "Log in with ORCID", From e53abcb69ea3d26461c24bd67894b7de1104a8cb Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Wed, 2 Aug 2023 18:00:03 +0200 Subject: [PATCH 041/196] remove redundant cache default values from server.ts --- server.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/server.ts b/server.ts index 23327c2058e..4feda5209a7 100644 --- a/server.ts +++ b/server.ts @@ -320,22 +320,23 @@ function initCache() { if (botCacheEnabled()) { // Initialize a new "least-recently-used" item cache (where least recently used pages are removed first) // See https://www.npmjs.com/package/lru-cache - // When enabled, each page defaults to expiring after 1 day + // When enabled, each page defaults to expiring after 1 day (defined in default-app-config.ts) botCache = new LRU( { max: environment.cache.serverSide.botCache.max, - ttl: environment.cache.serverSide.botCache.timeToLive || 24 * 60 * 60 * 1000, // 1 day - allowStale: environment.cache.serverSide.botCache.allowStale ?? true // if object is stale, return stale value before deleting + ttl: environment.cache.serverSide.botCache.timeToLive, + allowStale: environment.cache.serverSide.botCache.allowStale }); } if (anonymousCacheEnabled()) { // NOTE: While caches may share SSR pages, this cache must be kept separately because the timeToLive // may expire pages more frequently. - // When enabled, each page defaults to expiring after 10 seconds (to minimize anonymous users seeing out-of-date content) + // When enabled, each page defaults to expiring after 10 seconds (defined in default-app-config.ts) + // to minimize anonymous users seeing out-of-date content anonymousCache = new LRU( { max: environment.cache.serverSide.anonymousCache.max, - ttl: environment.cache.serverSide.anonymousCache.timeToLive || 10 * 1000, // 10 seconds - allowStale: environment.cache.serverSide.anonymousCache.allowStale ?? true // if object is stale, return stale value before deleting + ttl: environment.cache.serverSide.anonymousCache.timeToLive, + allowStale: environment.cache.serverSide.anonymousCache.allowStale }); } } From 3dc73f90214bc9fd288aaf0e0a06bc5912aadfbb Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Wed, 2 Aug 2023 21:25:58 +0200 Subject: [PATCH 042/196] Properly handle AuthMethod subscription in LogInComponent --- src/app/shared/log-in/log-in.component.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/app/shared/log-in/log-in.component.ts b/src/app/shared/log-in/log-in.component.ts index f47ea2d77e3..4bfae183326 100644 --- a/src/app/shared/log-in/log-in.component.ts +++ b/src/app/shared/log-in/log-in.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; +import { map, Observable } from 'rxjs'; import { select, Store } from '@ngrx/store'; import { AuthMethod } from '../../core/auth/models/auth.method'; import { @@ -35,7 +35,7 @@ export class LogInComponent implements OnInit { * The list of authentication methods available * @type {AuthMethod[]} */ - public authMethods: AuthMethod[]; + public authMethods: Observable; /** * Whether user is authenticated. @@ -55,13 +55,11 @@ export class LogInComponent implements OnInit { } ngOnInit(): void { - - this.store.pipe( + this.authMethods = this.store.pipe( select(getAuthenticationMethods), - ).subscribe(methods => { // ignore the ip authentication method when it's returned by the backend - this.authMethods = methods.filter(a => a.authMethodType !== AuthMethodType.Ip); - }); + map((methods: AuthMethod[]) => methods.filter((authMethod: AuthMethod) => authMethod.authMethodType !== AuthMethodType.Ip)), + ); // set loading this.loading = this.store.pipe(select(isAuthenticationLoading)); From 4c8ec8a4f22fcc4930b898581de098e317e08b5d Mon Sep 17 00:00:00 2001 From: Hugo Dominguez Date: Fri, 4 Aug 2023 12:44:13 -0600 Subject: [PATCH 043/196] =?UTF-8?q?=F0=9F=9A=B8remove=20thumbnail=20from?= =?UTF-8?q?=20file-upload=20section=20and=20show=20bitstream=20format=20an?= =?UTF-8?q?d=20checksum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...workspaceitem-section-upload-file.model.ts | 16 ++++++++++++-- .../file/section-upload-file.component.html | 15 +++++++------ .../section-upload-file-view.component.html | 12 +++++++++-- .../section-upload-file-view.component.ts | 21 ++++++++++++++----- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/app/core/submission/models/workspaceitem-section-upload-file.model.ts b/src/app/core/submission/models/workspaceitem-section-upload-file.model.ts index 177473b7d58..59a8faf6342 100644 --- a/src/app/core/submission/models/workspaceitem-section-upload-file.model.ts +++ b/src/app/core/submission/models/workspaceitem-section-upload-file.model.ts @@ -1,5 +1,5 @@ -import { SubmissionUploadFileAccessConditionObject } from './submission-upload-file-access-condition.model'; -import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model'; +import {SubmissionUploadFileAccessConditionObject} from './submission-upload-file-access-condition.model'; +import {WorkspaceitemSectionFormObject} from './workspaceitem-section-form.model'; /** * An interface to represent submission's upload section file entry. @@ -29,6 +29,18 @@ export class WorkspaceitemSectionUploadFileObject { value: string; }; + /** + * The file check sum + */ + format: { + shortDescription: string, + description: string, + mimetype: string, + supportLevel: string, + internal: boolean, + type: string + }; + /** * The file url */ diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.html b/src/app/submission/sections/upload/file/section-upload-file.component.html index 8999853d722..cd0ee512fde 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.html +++ b/src/app/submission/sections/upload/file/section-upload-file.component.html @@ -1,16 +1,13 @@
    -
    - - -
    -
    +

    {{fileName}} ({{fileData?.sizeBytes | dsFileSize}})

    - +
    diff --git a/src/app/submission/sections/upload/file/view/section-upload-file-view.component.html b/src/app/submission/sections/upload/file/view/section-upload-file-view.component.html index b84ef6f6a8c..cc12b5dea63 100644 --- a/src/app/submission/sections/upload/file/view/section-upload-file-view.component.html +++ b/src/app/submission/sections/upload/file/view/section-upload-file-view.component.html @@ -15,15 +15,23 @@
    - {{entry.value | dsTruncate:['150']}} + {{entry.value | dsTruncate:['150']}} - {{'submission.sections.upload.no-entry' | translate}} {{fileDescrKey}} + {{'submission.sections.upload.no-entry' | translate}} {{fileDescrKey}} + +
    + {{'admin.registries.bitstream-formats.edit.head' | translate:{format: fileFormat} }} +
    +
    + Checksum {{fileCheckSum.checkSumAlgorithm}}: {{fileCheckSum.value}} +
    diff --git a/src/app/submission/sections/upload/file/view/section-upload-file-view.component.ts b/src/app/submission/sections/upload/file/view/section-upload-file-view.component.ts index bb2fea20f83..b0ea2487e10 100644 --- a/src/app/submission/sections/upload/file/view/section-upload-file-view.component.ts +++ b/src/app/submission/sections/upload/file/view/section-upload-file-view.component.ts @@ -1,9 +1,11 @@ -import { Component, Input, OnInit } from '@angular/core'; +import {Component, Input, OnInit} from '@angular/core'; -import { WorkspaceitemSectionUploadFileObject } from '../../../../../core/submission/models/workspaceitem-section-upload-file.model'; -import { isNotEmpty } from '../../../../../shared/empty.util'; -import { Metadata } from '../../../../../core/shared/metadata.utils'; -import { MetadataMap, MetadataValue } from '../../../../../core/shared/metadata.models'; +import { + WorkspaceitemSectionUploadFileObject +} from '../../../../../core/submission/models/workspaceitem-section-upload-file.model'; +import {isNotEmpty} from '../../../../../shared/empty.util'; +import {Metadata} from '../../../../../core/shared/metadata.utils'; +import {MetadataMap, MetadataValue} from '../../../../../core/shared/metadata.models'; /** * This component allow to show bitstream's metadata @@ -38,6 +40,13 @@ export class SubmissionSectionUploadFileViewComponent implements OnInit { */ public fileDescrKey = 'Description'; + public fileFormat!: string; + + public fileCheckSum!: { + checkSumAlgorithm: string; + value: string; + }; + /** * Initialize instance variables */ @@ -46,6 +55,8 @@ export class SubmissionSectionUploadFileViewComponent implements OnInit { this.metadata[this.fileTitleKey] = Metadata.all(this.fileData.metadata, 'dc.title'); this.metadata[this.fileDescrKey] = Metadata.all(this.fileData.metadata, 'dc.description'); } + this.fileCheckSum = this.fileData.checkSum; + this.fileFormat = this.fileData.format.shortDescription; } /** From ec821392565737f768b0cd95917eade7e5ae6589 Mon Sep 17 00:00:00 2001 From: Francesco Bacchelli Date: Mon, 7 Aug 2023 14:26:42 +0200 Subject: [PATCH 044/196] CST-11298 COAR: Update the first community PRs for DSpace target 8.0-SNAPSHOT --- .../project-entry-import-modal.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html index 35b4b396a7b..42eb7e4b16a 100644 --- a/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html +++ b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html @@ -46,7 +46,7 @@

    {{ (labelPrefix + label + '.select' | translate) }}

    [disableHeader]="true" [hidePaginationDetail]="false" [selectionConfig]="{ repeatable: false, listId: entityListId }" - [showExport]="false" + [showCsvExport]="false" [linkType]="linkTypes.ExternalLink" [context]="context" (deselectObject)="deselectEntity()" From 95abcc9ce828d7fff8d8a3786f78930ac9dd9f5c Mon Sep 17 00:00:00 2001 From: Koen Pauwels Date: Fri, 4 Aug 2023 12:25:20 +0200 Subject: [PATCH 045/196] 103818 Add warning tooltip to "Inherit policies" checkbox on item move page --- .../edit-item-page/item-move/item-move.component.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/item-page/edit-item-page/item-move/item-move.component.html b/src/app/item-page/edit-item-page/item-move/item-move.component.html index 589aac655f5..475d36fb6fe 100644 --- a/src/app/item-page/edit-item-page/item-move/item-move.component.html +++ b/src/app/item-page/edit-item-page/item-move/item-move.component.html @@ -21,7 +21,11 @@

    {{'item.edit.move.head' | translate: {id: (itemRD$ | async)?.payload?.handle

    From 6791f6e311ab9ac2900f35c742c09cda9f9cd20e Mon Sep 17 00:00:00 2001 From: Koen Pauwels Date: Fri, 4 Aug 2023 17:10:06 +0200 Subject: [PATCH 046/196] 103818 Adjusted "Inherit policies" tooltip --- .../item-page/edit-item-page/item-move/item-move.component.html | 2 +- src/assets/i18n/en.json5 | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/item-page/edit-item-page/item-move/item-move.component.html b/src/app/item-page/edit-item-page/item-move/item-move.component.html index 475d36fb6fe..c1a4a5b9a94 100644 --- a/src/app/item-page/edit-item-page/item-move/item-move.component.html +++ b/src/app/item-page/edit-item-page/item-move/item-move.component.html @@ -22,7 +22,7 @@

    {{'item.edit.move.head' | translate: {id: (itemRD$ | async)?.payload?.handle

    {{field.id}}{{schema?.prefix}}.{{field.element}}{{field.qualifier}}{{schema?.prefix}}.{{field.element}}{{field.qualifier ? '.' + field.qualifier : ''}} {{field.scopeNote}}
    {{ dsoNameService.getName((group.object | async)?.payload) }}
    - - {{ messagePrefix + '.table.edit.currentGroup' | translate }} -
    - - -
    - -
    {{ePerson.eperson.id}}
    {{eperson.id}} - - {{ dsoNameService.getName(ePerson.eperson) }} + {{ dsoNameService.getName(eperson) }} - {{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}
    - {{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }} + {{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}
    + {{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }}
    -
    @@ -84,7 +84,7 @@
    {{ePerson.eperson.id}}
    {{eperson.id}} - - {{ dsoNameService.getName(ePerson.eperson) }} + {{ dsoNameService.getName(eperson) }} - {{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}
    - {{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }} + {{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}
    + {{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }}
    -
    @@ -139,7 +139,7 @@

    {{messagePrefix + '.headMembers' | translate}}

    - diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts index 7c8db399bcd..76e38067bc8 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts @@ -17,7 +17,7 @@ import { Group } from '../../../../core/eperson/models/group.model'; import { PageInfo } from '../../../../core/shared/page-info.model'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; -import { GroupMock, GroupMock2 } from '../../../../shared/testing/group-mock'; +import { GroupMock } from '../../../../shared/testing/group-mock'; import { MembersListComponent } from './members-list.component'; import { EPersonMock, EPersonMock2 } from '../../../../shared/testing/eperson.mock'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils'; @@ -39,28 +39,26 @@ describe('MembersListComponent', () => { let ePersonDataServiceStub: any; let groupsDataServiceStub: any; let activeGroup; - let allEPersons: EPerson[]; - let allGroups: Group[]; let epersonMembers: EPerson[]; - let subgroupMembers: Group[]; + let epersonNonMembers: EPerson[]; let paginationService; beforeEach(waitForAsync(() => { activeGroup = GroupMock; epersonMembers = [EPersonMock2]; - subgroupMembers = [GroupMock2]; - allEPersons = [EPersonMock, EPersonMock2]; - allGroups = [GroupMock, GroupMock2]; + epersonNonMembers = [EPersonMock]; ePersonDataServiceStub = { activeGroup: activeGroup, epersonMembers: epersonMembers, - subgroupMembers: subgroupMembers, + epersonNonMembers: epersonNonMembers, + // This method is used to get all the current members findListByHref(_href: string): Observable>> { return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupsDataServiceStub.getEPersonMembers())); }, + // This method is used to search across *non-members* searchByScope(scope: string, query: string): Observable>> { if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), allEPersons)); + return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), epersonNonMembers)); } return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); }, @@ -77,22 +75,22 @@ describe('MembersListComponent', () => { groupsDataServiceStub = { activeGroup: activeGroup, epersonMembers: epersonMembers, - subgroupMembers: subgroupMembers, - allGroups: allGroups, + epersonNonMembers: epersonNonMembers, getActiveGroup(): Observable { return observableOf(activeGroup); }, getEPersonMembers() { return this.epersonMembers; }, - searchGroups(query: string): Observable>> { - if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), this.allGroups)); - } - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); - }, - addMemberToGroup(parentGroup, eperson: EPerson): Observable { - this.epersonMembers = [...this.epersonMembers, eperson]; + addMemberToGroup(parentGroup, epersonToAdd: EPerson): Observable { + // Add eperson to list of members + this.epersonMembers = [...this.epersonMembers, epersonToAdd]; + // Remove eperson from list of non-members + this.epersonNonMembers.forEach( (eperson: EPerson, index: number) => { + if (eperson.id === epersonToAdd.id) { + this.epersonNonMembers.splice(index, 1); + } + }); return observableOf(new RestResponse(true, 200, 'Success')); }, clearGroupsRequests() { @@ -105,14 +103,14 @@ describe('MembersListComponent', () => { return '/access-control/groups/' + group.id; }, deleteMemberFromGroup(parentGroup, epersonToDelete: EPerson): Observable { - this.epersonMembers = this.epersonMembers.find((eperson: EPerson) => { - if (eperson.id !== epersonToDelete.id) { - return eperson; + // Remove eperson from list of members + this.epersonMembers.forEach( (eperson: EPerson, index: number) => { + if (eperson.id === epersonToDelete.id) { + this.epersonMembers.splice(index, 1); } }); - if (this.epersonMembers === undefined) { - this.epersonMembers = []; - } + // Add eperson to list of non-members + this.epersonNonMembers = [...this.epersonNonMembers, epersonToDelete]; return observableOf(new RestResponse(true, 200, 'Success')); } }; @@ -160,13 +158,37 @@ describe('MembersListComponent', () => { expect(comp).toBeDefined(); })); - it('should show list of eperson members of current active group', () => { - const epersonIdsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tr td:first-child')); - expect(epersonIdsFound.length).toEqual(1); - epersonMembers.map((eperson: EPerson) => { - expect(epersonIdsFound.find((foundEl) => { - return (foundEl.nativeElement.textContent.trim() === eperson.uuid); - })).toBeTruthy(); + describe('current members list', () => { + it('should show list of eperson members of current active group', () => { + const epersonIdsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tr td:first-child')); + expect(epersonIdsFound.length).toEqual(1); + epersonMembers.map((eperson: EPerson) => { + expect(epersonIdsFound.find((foundEl) => { + return (foundEl.nativeElement.textContent.trim() === eperson.uuid); + })).toBeTruthy(); + }); + }); + + it('should show a delete button next to each member', () => { + const epersonsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tbody tr')); + epersonsFound.map((foundEPersonRowElement: DebugElement) => { + const addButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-plus')); + const deleteButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-trash-alt')); + expect(addButton).toBeNull(); + expect(deleteButton).not.toBeNull(); + }); + }); + + describe('if first delete button is pressed', () => { + beforeEach(() => { + const deleteButton: DebugElement = fixture.debugElement.query(By.css('#ePeopleMembersOfGroup tbody .fa-trash-alt')); + deleteButton.nativeElement.click(); + fixture.detectChanges(); + }); + it('then no ePerson remains as a member of the active group.', () => { + const epersonsFound = fixture.debugElement.queryAll(By.css('#ePeopleMembersOfGroup tbody tr')); + expect(epersonsFound.length).toEqual(0); + }); }); }); @@ -174,76 +196,40 @@ describe('MembersListComponent', () => { describe('when searching without query', () => { let epersonsFound: DebugElement[]; beforeEach(fakeAsync(() => { - spyOn(component, 'isMemberOfGroup').and.callFake((ePerson: EPerson) => { - return observableOf(activeGroup.epersons.includes(ePerson)); - }); component.search({ scope: 'metadata', query: '' }); tick(); fixture.detectChanges(); epersonsFound = fixture.debugElement.queryAll(By.css('#epersonsSearch tbody tr')); - // Stop using the fake spy function (because otherwise the clicking on the buttons will not change anything - // because they don't change the value of activeGroup.epersons) - jasmine.getEnv().allowRespy(true); - spyOn(component, 'isMemberOfGroup').and.callThrough(); })); - it('should display all epersons', () => { - expect(epersonsFound.length).toEqual(2); + it('should display only non-members of the group', () => { + const epersonIdsFound = fixture.debugElement.queryAll(By.css('#epersonsSearch tbody tr td:first-child')); + expect(epersonIdsFound.length).toEqual(1); + epersonNonMembers.map((eperson: EPerson) => { + expect(epersonIdsFound.find((foundEl) => { + return (foundEl.nativeElement.textContent.trim() === eperson.uuid); + })).toBeTruthy(); + }); }); - describe('if eperson is already a eperson', () => { - it('should have delete button, else it should have add button', () => { - const memberIds: string[] = activeGroup.epersons.map((ePerson: EPerson) => ePerson.id); - epersonsFound.map((foundEPersonRowElement: DebugElement) => { - const epersonId: DebugElement = foundEPersonRowElement.query(By.css('td:first-child')); - const addButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-plus')); - const deleteButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-trash-alt')); - if (memberIds.includes(epersonId.nativeElement.textContent)) { - expect(addButton).toBeNull(); - expect(deleteButton).not.toBeNull(); - } else { - expect(deleteButton).toBeNull(); - expect(addButton).not.toBeNull(); - } - }); + it('should display an add button next to non-members, not a delete button', () => { + epersonsFound.map((foundEPersonRowElement: DebugElement) => { + const addButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-plus')); + const deleteButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-trash-alt')); + expect(addButton).not.toBeNull(); + expect(deleteButton).toBeNull(); }); }); describe('if first add button is pressed', () => { - beforeEach(fakeAsync(() => { + beforeEach(() => { const addButton: DebugElement = fixture.debugElement.query(By.css('#epersonsSearch tbody .fa-plus')); addButton.nativeElement.click(); - tick(); fixture.detectChanges(); - })); - it('then all the ePersons are member of the active group', () => { - epersonsFound = fixture.debugElement.queryAll(By.css('#epersonsSearch tbody tr')); - expect(epersonsFound.length).toEqual(2); - epersonsFound.map((foundEPersonRowElement: DebugElement) => { - const addButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-plus')); - const deleteButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-trash-alt')); - expect(addButton).toBeNull(); - expect(deleteButton).not.toBeNull(); - }); }); - }); - - describe('if first delete button is pressed', () => { - beforeEach(fakeAsync(() => { - const deleteButton: DebugElement = fixture.debugElement.query(By.css('#epersonsSearch tbody .fa-trash-alt')); - deleteButton.nativeElement.click(); - tick(); - fixture.detectChanges(); - })); - it('then no ePerson is member of the active group', () => { + it('then all (two) ePersons are member of the active group. No non-members left', () => { epersonsFound = fixture.debugElement.queryAll(By.css('#epersonsSearch tbody tr')); - expect(epersonsFound.length).toEqual(2); - epersonsFound.map((foundEPersonRowElement: DebugElement) => { - const addButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-plus')); - const deleteButton: DebugElement = foundEPersonRowElement.query(By.css('td:last-child .fa-trash-alt')); - expect(deleteButton).toBeNull(); - expect(addButton).not.toBeNull(); - }); + expect(epersonsFound.length).toEqual(0); }); }); }); diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts index 704a92d0f9f..f49690f6746 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts @@ -4,13 +4,11 @@ import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Observable, - of as observableOf, Subscription, - BehaviorSubject, - combineLatest as observableCombineLatest + BehaviorSubject } from 'rxjs'; -import { defaultIfEmpty, map, switchMap, take } from 'rxjs/operators'; -import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model'; +import { map, switchMap, take } from 'rxjs/operators'; +import { PaginatedList } from '../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { EPersonDataService } from '../../../../core/eperson/eperson-data.service'; import { GroupDataService } from '../../../../core/eperson/group-data.service'; @@ -18,11 +16,11 @@ import { EPerson } from '../../../../core/eperson/models/eperson.model'; import { Group } from '../../../../core/eperson/models/group.model'; import { getFirstCompletedRemoteData, - getAllCompletedRemoteData + getAllCompletedRemoteData, + getRemoteDataPayload } from '../../../../core/shared/operators'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model'; -import { EpersonDtoModel } from '../../../../core/eperson/models/eperson-dto.model'; import { PaginationService } from '../../../../core/pagination/pagination.service'; import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service'; @@ -93,11 +91,11 @@ export class MembersListComponent implements OnInit, OnDestroy { /** * EPeople being displayed in search result, initially all members, after search result of search */ - ePeopleSearchDtos: BehaviorSubject> = new BehaviorSubject>(undefined); + ePeopleSearch: BehaviorSubject> = new BehaviorSubject>(undefined); /** * List of EPeople members of currently active group being edited */ - ePeopleMembersOfGroupDtos: BehaviorSubject> = new BehaviorSubject>(undefined); + ePeopleMembersOfGroup: BehaviorSubject> = new BehaviorSubject>(undefined); /** * Pagination config used to display the list of EPeople that are result of EPeople search @@ -186,18 +184,9 @@ export class MembersListComponent implements OnInit, OnDestroy { return rd; } }), - switchMap((epersonListRD: RemoteData>) => { - const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => { - const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); - epersonDtoModel.eperson = member; - return observableOf(epersonDtoModel); - })]); - return dtos$.pipe(defaultIfEmpty([]), map((dtos: EpersonDtoModel[]) => { - return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); - })); - })) - .subscribe((paginatedListOfDTOs: PaginatedList) => { - this.ePeopleMembersOfGroupDtos.next(paginatedListOfDTOs); + getRemoteDataPayload()) + .subscribe((paginatedListOfEPersons: PaginatedList) => { + this.ePeopleMembersOfGroup.next(paginatedListOfEPersons); })); } @@ -217,13 +206,13 @@ export class MembersListComponent implements OnInit, OnDestroy { /** * Deletes a given EPerson from the members list of the group currently being edited - * @param ePerson EPerson we want to delete as member from group that is currently being edited + * @param eperson EPerson we want to delete as member from group that is currently being edited */ - deleteMemberFromGroup(ePerson: EpersonDtoModel) { + deleteMemberFromGroup(eperson: EPerson) { this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => { if (activeGroup != null) { - const response = this.groupDataService.deleteMemberFromGroup(activeGroup, ePerson.eperson); - this.showNotifications('deleteMember', response, this.dsoNameService.getName(ePerson.eperson), activeGroup); + const response = this.groupDataService.deleteMemberFromGroup(activeGroup, eperson); + this.showNotifications('deleteMember', response, this.dsoNameService.getName(eperson), activeGroup); } else { this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup')); } @@ -232,13 +221,13 @@ export class MembersListComponent implements OnInit, OnDestroy { /** * Adds a given EPerson to the members list of the group currently being edited - * @param ePerson EPerson we want to add as member to group that is currently being edited + * @param eperson EPerson we want to add as member to group that is currently being edited */ - addMemberToGroup(ePerson: EpersonDtoModel) { + addMemberToGroup(eperson: EPerson) { this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => { if (activeGroup != null) { - const response = this.groupDataService.addMemberToGroup(activeGroup, ePerson.eperson); - this.showNotifications('addMember', response, this.dsoNameService.getName(ePerson.eperson), activeGroup); + const response = this.groupDataService.addMemberToGroup(activeGroup, eperson); + this.showNotifications('addMember', response, this.dsoNameService.getName(eperson), activeGroup); } else { this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup')); } @@ -286,18 +275,9 @@ export class MembersListComponent implements OnInit, OnDestroy { return rd; } }), - switchMap((epersonListRD: RemoteData>) => { - const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => { - const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel(); - epersonDtoModel.eperson = member; - return observableOf(epersonDtoModel); - })]); - return dtos$.pipe(defaultIfEmpty([]), map((dtos: EpersonDtoModel[]) => { - return buildPaginatedList(epersonListRD.payload.pageInfo, dtos); - })); - })) - .subscribe((paginatedListOfDTOs: PaginatedList) => { - this.ePeopleSearchDtos.next(paginatedListOfDTOs); + getRemoteDataPayload()) + .subscribe((paginatedListOfEPersons: PaginatedList) => { + this.ePeopleSearch.next(paginatedListOfEPersons); })); } From b598f1b5ca9b54c4b5fe23daa3d7b502ee0dc6b2 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 26 Sep 2023 12:07:30 -0500 Subject: [PATCH 128/196] Also remove unnecessary EpersonDtoModel from extending ReviewersListComponent. Remove "memberOfGroup" from EpersonDtoModel as it is no longer used --- .../members-list/members-list.component.ts | 12 +-- .../core/eperson/models/eperson-dto.model.ts | 5 - .../reviewers-list.component.spec.ts | 95 ++++++++----------- .../reviewers-list.component.ts | 51 ++++------ 4 files changed, 65 insertions(+), 98 deletions(-) diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts index f49690f6746..e828555a80f 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts @@ -29,8 +29,8 @@ import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service'; */ enum SubKey { ActiveGroup, - MembersDTO, - SearchResultsDTO, + Members, + SearchResults, } /** @@ -166,8 +166,8 @@ export class MembersListComponent implements OnInit, OnDestroy { * @private */ retrieveMembers(page: number): void { - this.unsubFrom(SubKey.MembersDTO); - this.subs.set(SubKey.MembersDTO, + this.unsubFrom(SubKey.Members); + this.subs.set(SubKey.Members, this.paginationService.getCurrentPagination(this.config.id, this.config).pipe( switchMap((currentPagination) => { return this.ePersonDataService.findListByHref(this.groupBeingEdited._links.epersons.href, { @@ -239,8 +239,8 @@ export class MembersListComponent implements OnInit, OnDestroy { * @param data Contains scope and query param */ search(data: any) { - this.unsubFrom(SubKey.SearchResultsDTO); - this.subs.set(SubKey.SearchResultsDTO, + this.unsubFrom(SubKey.SearchResults); + this.subs.set(SubKey.SearchResults, this.paginationService.getCurrentPagination(this.configSearch.id, this.configSearch).pipe( switchMap((paginationOptions) => { diff --git a/src/app/core/eperson/models/eperson-dto.model.ts b/src/app/core/eperson/models/eperson-dto.model.ts index 0e79902196b..5fa6c7ed68b 100644 --- a/src/app/core/eperson/models/eperson-dto.model.ts +++ b/src/app/core/eperson/models/eperson-dto.model.ts @@ -13,9 +13,4 @@ export class EpersonDtoModel { * Whether or not the linked EPerson is able to be deleted */ public ableToDelete: boolean; - /** - * Whether or not this EPerson is member of group on page it is being used on - */ - public memberOfGroup: boolean; - } diff --git a/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.spec.ts b/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.spec.ts index 7c8db782ce6..bcbeef56830 100644 --- a/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.spec.ts +++ b/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.spec.ts @@ -17,7 +17,7 @@ import { Group } from '../../../../core/eperson/models/group.model'; import { PageInfo } from '../../../../core/shared/page-info.model'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; -import { GroupMock, GroupMock2 } from '../../../../shared/testing/group-mock'; +import { GroupMock } from '../../../../shared/testing/group-mock'; import { ReviewersListComponent } from './reviewers-list.component'; import { EPersonMock, EPersonMock2 } from '../../../../shared/testing/eperson.mock'; import { @@ -31,8 +31,10 @@ import { NotificationsServiceStub } from '../../../../shared/testing/notificatio import { RouterMock } from '../../../../shared/mocks/router.mock'; import { PaginationService } from '../../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub'; -import { EpersonDtoModel } from '../../../../core/eperson/models/eperson-dto.model'; +// NOTE: Because ReviewersListComponent extends MembersListComponent, the below tests ONLY validate +// features which are *unique* to ReviewersListComponent. All other features are tested in the +// members-list.component.spec.ts file. describe('ReviewersListComponent', () => { let component: ReviewersListComponent; let fixture: ComponentFixture; @@ -40,31 +42,27 @@ describe('ReviewersListComponent', () => { let builderService: FormBuilderService; let ePersonDataServiceStub: any; let groupsDataServiceStub: any; - let activeGroup; - let allEPersons; - let allGroups; - let epersonMembers; - let subgroupMembers; + let activeGroup: Group; + let epersonMembers: EPerson[]; + let epersonNonMembers: EPerson[]; let paginationService; - let ePersonDtoModel1: EpersonDtoModel; - let ePersonDtoModel2: EpersonDtoModel; beforeEach(waitForAsync(() => { activeGroup = GroupMock; epersonMembers = [EPersonMock2]; - subgroupMembers = [GroupMock2]; - allEPersons = [EPersonMock, EPersonMock2]; - allGroups = [GroupMock, GroupMock2]; + epersonNonMembers = [EPersonMock]; ePersonDataServiceStub = { activeGroup: activeGroup, epersonMembers: epersonMembers, - subgroupMembers: subgroupMembers, + epersonNonMembers: epersonNonMembers, + // This method is used to get all the current members findListByHref(_href: string): Observable>> { return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupsDataServiceStub.getEPersonMembers())); }, + // This method is used to search across *non-members* searchByScope(scope: string, query: string): Observable>> { if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), allEPersons)); + return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), epersonNonMembers)); } return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); }, @@ -81,22 +79,22 @@ describe('ReviewersListComponent', () => { groupsDataServiceStub = { activeGroup: activeGroup, epersonMembers: epersonMembers, - subgroupMembers: subgroupMembers, - allGroups: allGroups, + epersonNonMembers: epersonNonMembers, getActiveGroup(): Observable { return observableOf(activeGroup); }, getEPersonMembers() { return this.epersonMembers; }, - searchGroups(query: string): Observable>> { - if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), this.allGroups)); - } - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); - }, - addMemberToGroup(parentGroup, eperson: EPerson): Observable { - this.epersonMembers = [...this.epersonMembers, eperson]; + addMemberToGroup(parentGroup, epersonToAdd: EPerson): Observable { + // Add eperson to list of members + this.epersonMembers = [...this.epersonMembers, epersonToAdd]; + // Remove eperson from list of non-members + this.epersonNonMembers.forEach( (eperson: EPerson, index: number) => { + if (eperson.id === epersonToAdd.id) { + this.epersonNonMembers.splice(index, 1); + } + }); return observableOf(new RestResponse(true, 200, 'Success')); }, clearGroupsRequests() { @@ -109,21 +107,20 @@ describe('ReviewersListComponent', () => { return '/access-control/groups/' + group.id; }, deleteMemberFromGroup(parentGroup, epersonToDelete: EPerson): Observable { - this.epersonMembers = this.epersonMembers.find((eperson: EPerson) => { - if (eperson.id !== epersonToDelete.id) { - return eperson; + // Remove eperson from list of members + this.epersonMembers.forEach( (eperson: EPerson, index: number) => { + if (eperson.id === epersonToDelete.id) { + this.epersonMembers.splice(index, 1); } }); - if (this.epersonMembers === undefined) { - this.epersonMembers = []; - } + // Add eperson to list of non-members + this.epersonNonMembers = [...this.epersonNonMembers, epersonToDelete]; return observableOf(new RestResponse(true, 200, 'Success')); }, + // Used to find the currently active group findById(id: string) { - for (const group of allGroups) { - if (group.id === id) { - return createSuccessfulRemoteDataObject$(group); - } + if (activeGroup.id === id) { + return createSuccessfulRemoteDataObject$(activeGroup); } return createNoContentRemoteDataObject$(); }, @@ -135,7 +132,7 @@ describe('ReviewersListComponent', () => { translateService = getMockTranslateService(); paginationService = new PaginationServiceStub(); - TestBed.configureTestingModule({ + return TestBed.configureTestingModule({ imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule, TranslateModule.forRoot({ loader: { @@ -169,12 +166,6 @@ describe('ReviewersListComponent', () => { fixture.debugElement.nativeElement.remove(); })); - beforeEach(() => { - ePersonDtoModel1 = new EpersonDtoModel(); - ePersonDtoModel1.eperson = EPersonMock; - ePersonDtoModel2 = new EpersonDtoModel(); - ePersonDtoModel2.eperson = EPersonMock2; - }); describe('when no group is selected', () => { beforeEach(() => { @@ -218,34 +209,32 @@ describe('ReviewersListComponent', () => { it('should replace the value when a new member is added when multipleReviewers is false', () => { spyOn(component.selectedReviewersUpdated, 'emit'); component.multipleReviewers = false; - component.selectedReviewers = [ePersonDtoModel1]; + component.selectedReviewers = [EPersonMock]; - component.addMemberToGroup(ePersonDtoModel2); + component.addMemberToGroup(EPersonMock2); - expect(component.selectedReviewers).toEqual([ePersonDtoModel2]); - expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([ePersonDtoModel2.eperson]); + expect(component.selectedReviewers).toEqual([EPersonMock2]); + expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([EPersonMock2]); }); it('should add the value when a new member is added when multipleReviewers is true', () => { spyOn(component.selectedReviewersUpdated, 'emit'); component.multipleReviewers = true; - component.selectedReviewers = [ePersonDtoModel1]; + component.selectedReviewers = [EPersonMock]; - component.addMemberToGroup(ePersonDtoModel2); + component.addMemberToGroup(EPersonMock2); - expect(component.selectedReviewers).toEqual([ePersonDtoModel1, ePersonDtoModel2]); - expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([ePersonDtoModel1.eperson, ePersonDtoModel2.eperson]); + expect(component.selectedReviewers).toEqual([EPersonMock, EPersonMock2]); + expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([EPersonMock, EPersonMock2]); }); it('should delete the member when present', () => { spyOn(component.selectedReviewersUpdated, 'emit'); - ePersonDtoModel1.memberOfGroup = true; - component.selectedReviewers = [ePersonDtoModel1]; + component.selectedReviewers = [EPersonMock]; - component.deleteMemberFromGroup(ePersonDtoModel1); + component.deleteMemberFromGroup(EPersonMock); expect(component.selectedReviewers).toEqual([]); - expect(ePersonDtoModel1.memberOfGroup).toBeFalse(); expect(component.selectedReviewersUpdated.emit).toHaveBeenCalledWith([]); }); diff --git a/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.ts b/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.ts index 6984a1d86dd..65a106e2e84 100644 --- a/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.ts +++ b/src/app/workflowitems-edit-page/advanced-workflow-action/advanced-workflow-action-select-reviewer/reviewers-list/reviewers-list.component.ts @@ -8,10 +8,7 @@ import { NotificationsService } from '../../../../shared/notifications/notificat import { PaginationService } from '../../../../core/pagination/pagination.service'; import { Group } from '../../../../core/eperson/models/group.model'; import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators'; -import { EpersonDtoModel } from '../../../../core/eperson/models/eperson-dto.model'; import { EPerson } from '../../../../core/eperson/models/eperson.model'; -import { Observable, of as observableOf } from 'rxjs'; -import { hasValue } from '../../../../shared/empty.util'; import { PaginatedList } from '../../../../core/data/paginated-list.model'; import { MembersListComponent, @@ -24,8 +21,8 @@ import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service'; */ enum SubKey { ActiveGroup, - MembersDTO, - SearchResultsDTO, + Members, + SearchResults, } /** @@ -50,7 +47,7 @@ export class ReviewersListComponent extends MembersListComponent implements OnIn @Output() selectedReviewersUpdated: EventEmitter = new EventEmitter(); - selectedReviewers: EpersonDtoModel[] = []; + selectedReviewers: EPerson[] = []; constructor( protected groupService: GroupDataService, @@ -100,54 +97,40 @@ export class ReviewersListComponent extends MembersListComponent implements OnIn retrieveMembers(page: number): void { this.config.currentPage = page; if (this.groupId === null) { - this.unsubFrom(SubKey.MembersDTO); - const paginatedListOfDTOs: PaginatedList = new PaginatedList(); - paginatedListOfDTOs.page = this.selectedReviewers; - this.ePeopleMembersOfGroupDtos.next(paginatedListOfDTOs); + this.unsubFrom(SubKey.Members); + const paginatedListOfEPersons: PaginatedList = new PaginatedList(); + paginatedListOfEPersons.page = this.selectedReviewers; + this.ePeopleMembersOfGroup.next(paginatedListOfEPersons); } else { super.retrieveMembers(page); } } /** - * Checks whether the given {@link possibleMember} is part of the {@link selectedReviewers}. + * Removes the {@link eperson} from the {@link selectedReviewers} * - * @param possibleMember The {@link EPerson} that needs to be checked + * @param eperson The {@link EPerson} to remove */ - isMemberOfGroup(possibleMember: EPerson): Observable { - return observableOf(hasValue(this.selectedReviewers.find((reviewer: EpersonDtoModel) => reviewer.eperson.id === possibleMember.id))); - } - - /** - * Removes the {@link ePerson} from the {@link selectedReviewers} - * - * @param ePerson The {@link EpersonDtoModel} containg the {@link EPerson} to remove - */ - deleteMemberFromGroup(ePerson: EpersonDtoModel) { - ePerson.memberOfGroup = false; - const index = this.selectedReviewers.indexOf(ePerson); + deleteMemberFromGroup(eperson: EPerson) { + const index = this.selectedReviewers.indexOf(eperson); if (index !== -1) { this.selectedReviewers.splice(index, 1); } - this.selectedReviewersUpdated.emit(this.selectedReviewers.map((ePersonDtoModel: EpersonDtoModel) => ePersonDtoModel.eperson)); + this.selectedReviewersUpdated.emit(this.selectedReviewers); } /** - * Adds the {@link ePerson} to the {@link selectedReviewers} (or replaces it when {@link multipleReviewers} is + * Adds the {@link eperson} to the {@link selectedReviewers} (or replaces it when {@link multipleReviewers} is * `false`). Afterwards it will emit the list. * - * @param ePerson The {@link EPerson} to add to the list + * @param eperson The {@link EPerson} to add to the list */ - addMemberToGroup(ePerson: EpersonDtoModel) { - ePerson.memberOfGroup = true; + addMemberToGroup(eperson: EPerson) { if (!this.multipleReviewers) { - for (const selectedReviewer of this.selectedReviewers) { - selectedReviewer.memberOfGroup = false; - } this.selectedReviewers = []; } - this.selectedReviewers.push(ePerson); - this.selectedReviewersUpdated.emit(this.selectedReviewers.map((epersonDtoModel: EpersonDtoModel) => epersonDtoModel.eperson)); + this.selectedReviewers.push(eperson); + this.selectedReviewersUpdated.emit(this.selectedReviewers); } } From 64f968b246774140b2e3d4f134be7608ab7a6207 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 2 Oct 2023 16:35:26 -0500 Subject: [PATCH 129/196] Fix subgroups-list specs so they align with new members-list specs --- .../subgroups-list.component.spec.ts | 184 ++++++++++-------- 1 file changed, 102 insertions(+), 82 deletions(-) diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts index ac5750dcaca..7bbbb24f304 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.spec.ts @@ -1,12 +1,12 @@ import { CommonModule } from '@angular/common'; import { NO_ERRORS_SCHEMA, DebugElement } from '@angular/core'; -import { ComponentFixture, fakeAsync, flush, inject, TestBed, tick, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, flush, inject, TestBed, waitForAsync } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserModule, By } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; -import { Observable, of as observableOf, BehaviorSubject } from 'rxjs'; +import { Observable, of as observableOf } from 'rxjs'; import { RestResponse } from '../../../../core/cache/response.models'; import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../core/data/remote-data'; @@ -18,19 +18,18 @@ import { NotificationsService } from '../../../../shared/notifications/notificat import { GroupMock, GroupMock2 } from '../../../../shared/testing/group-mock'; import { SubgroupsListComponent } from './subgroups-list.component'; import { - createSuccessfulRemoteDataObject$, - createSuccessfulRemoteDataObject + createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils'; import { RouterMock } from '../../../../shared/mocks/router.mock'; import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock'; import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock'; import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock'; import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; -import { map } from 'rxjs/operators'; import { PaginationService } from '../../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub'; import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service'; import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock'; +import { EPersonMock2 } from 'src/app/shared/testing/eperson.mock'; describe('SubgroupsListComponent', () => { let component: SubgroupsListComponent; @@ -39,44 +38,70 @@ describe('SubgroupsListComponent', () => { let builderService: FormBuilderService; let ePersonDataServiceStub: any; let groupsDataServiceStub: any; - let activeGroup; + let activeGroup: Group; let subgroups: Group[]; - let allGroups: Group[]; + let groupNonMembers: Group[]; let routerStub; let paginationService; + // Define a new mock activegroup for all tests below + let mockActiveGroup: Group = Object.assign(new Group(), { + handle: null, + subgroups: [GroupMock2], + epersons: [EPersonMock2], + selfRegistered: false, + permanent: false, + _links: { + self: { + href: 'https://rest.api/server/api/eperson/groups/activegroupid', + }, + subgroups: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/subgroups' }, + object: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/object' }, + epersons: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/epersons' } + }, + _name: 'activegroupname', + id: 'activegroupid', + uuid: 'activegroupid', + type: 'group', + }); beforeEach(waitForAsync(() => { - activeGroup = GroupMock; + activeGroup = mockActiveGroup; subgroups = [GroupMock2]; - allGroups = [GroupMock, GroupMock2]; + groupNonMembers = [GroupMock]; ePersonDataServiceStub = {}; groupsDataServiceStub = { activeGroup: activeGroup, - subgroups$: new BehaviorSubject(subgroups), + subgroups: subgroups, + groupNonMembers: groupNonMembers, getActiveGroup(): Observable { return observableOf(this.activeGroup); }, getSubgroups(): Group { - return this.activeGroup; + return this.subgroups; }, + // This method is used to get all the current subgroups findListByHref(_href: string): Observable>> { - return this.subgroups$.pipe( - map((currentGroups: Group[]) => { - return createSuccessfulRemoteDataObject(buildPaginatedList(new PageInfo(), currentGroups)); - }) - ); + return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupsDataServiceStub.getSubgroups())); }, getGroupEditPageRouterLink(group: Group): string { return '/access-control/groups/' + group.id; }, + // This method is used to get all groups which are NOT currently a subgroup member searchGroups(query: string): Observable>> { if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), allGroups)); + return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupNonMembers)); } return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); }, - addSubGroupToGroup(parentGroup, subgroup: Group): Observable { - this.subgroups$.next([...this.subgroups$.getValue(), subgroup]); + addSubGroupToGroup(parentGroup, subgroupToAdd: Group): Observable { + // Add group to list of subgroups + this.subgroups = [...this.subgroups, subgroupToAdd]; + // Remove group from list of non-members + this.groupNonMembers.forEach( (group: Group, index: number) => { + if (group.id === subgroupToAdd.id) { + this.groupNonMembers.splice(index, 1); + } + }); return observableOf(new RestResponse(true, 200, 'Success')); }, clearGroupsRequests() { @@ -85,12 +110,15 @@ describe('SubgroupsListComponent', () => { clearGroupLinkRequests() { // empty }, - deleteSubGroupFromGroup(parentGroup, subgroup: Group): Observable { - this.subgroups$.next(this.subgroups$.getValue().filter((group: Group) => { - if (group.id !== subgroup.id) { - return group; + deleteSubGroupFromGroup(parentGroup, subgroupToDelete: Group): Observable { + // Remove group from list of subgroups + this.subgroups.forEach( (group: Group, index: number) => { + if (group.id === subgroupToDelete.id) { + this.subgroups.splice(index, 1); } - })); + }); + // Add group to list of non-members + this.groupNonMembers = [...this.groupNonMembers, subgroupToDelete]; return observableOf(new RestResponse(true, 200, 'Success')); } }; @@ -99,7 +127,7 @@ describe('SubgroupsListComponent', () => { translateService = getMockTranslateService(); paginationService = new PaginationServiceStub(); - TestBed.configureTestingModule({ + return TestBed.configureTestingModule({ imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule, TranslateModule.forRoot({ loader: { @@ -137,30 +165,38 @@ describe('SubgroupsListComponent', () => { expect(comp).toBeDefined(); })); - it('should show list of subgroups of current active group', () => { - const groupIdsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tr td:first-child')); - expect(groupIdsFound.length).toEqual(1); - activeGroup.subgroups.map((group: Group) => { - expect(groupIdsFound.find((foundEl) => { - return (foundEl.nativeElement.textContent.trim() === group.uuid); - })).toBeTruthy(); + describe('current subgroup list', () => { + it('should show list of subgroups of current active group', () => { + const groupIdsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tr td:first-child')); + expect(groupIdsFound.length).toEqual(1); + subgroups.map((group: Group) => { + expect(groupIdsFound.find((foundEl) => { + return (foundEl.nativeElement.textContent.trim() === group.uuid); + })).toBeTruthy(); + }); }); - }); - describe('if first group delete button is pressed', () => { - let groupsFound: DebugElement[]; - beforeEach(fakeAsync(() => { - const addButton = fixture.debugElement.query(By.css('#subgroupsOfGroup tbody .deleteButton')); - addButton.triggerEventHandler('click', { - preventDefault: () => {/**/ - } + it('should show a delete button next to each subgroup', () => { + const subgroupsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tbody tr')); + subgroupsFound.map((foundGroupRowElement: DebugElement) => { + const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus')); + const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt')); + expect(addButton).toBeNull(); + expect(deleteButton).not.toBeNull(); + }); + }); + + describe('if first group delete button is pressed', () => { + let groupsFound: DebugElement[]; + beforeEach(() => { + const deleteButton = fixture.debugElement.query(By.css('#subgroupsOfGroup tbody .deleteButton')); + deleteButton.nativeElement.click(); + fixture.detectChanges(); + }); + it('then no subgroup remains as a member of the active group', () => { + groupsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tbody tr')); + expect(groupsFound.length).toEqual(0); }); - tick(); - fixture.detectChanges(); - })); - it('one less subgroup in list from 1 to 0 (of 2 total groups)', () => { - groupsFound = fixture.debugElement.queryAll(By.css('#subgroupsOfGroup tbody tr')); - expect(groupsFound.length).toEqual(0); }); }); @@ -169,54 +205,38 @@ describe('SubgroupsListComponent', () => { let groupsFound: DebugElement[]; beforeEach(fakeAsync(() => { component.search({ query: '' }); + fixture.detectChanges(); groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr')); })); - it('should display all groups', () => { - fixture.detectChanges(); - groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr')); - expect(groupsFound.length).toEqual(2); - groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr')); + it('should display only non-member groups (i.e. groups that are not a subgroup)', () => { const groupIdsFound: DebugElement[] = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr td:first-child')); - allGroups.map((group: Group) => { + expect(groupIdsFound.length).toEqual(1); + groupNonMembers.map((group: Group) => { expect(groupIdsFound.find((foundEl: DebugElement) => { return (foundEl.nativeElement.textContent.trim() === group.uuid); })).toBeTruthy(); }); }); - describe('if group is already a subgroup', () => { - it('should have delete button, else it should have add button', () => { + it('should display an add button next to non-member groups, not a delete button', () => { + groupsFound.map((foundGroupRowElement: DebugElement) => { + const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus')); + const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt')); + expect(addButton).not.toBeNull(); + expect(deleteButton).toBeNull(); + }); + }); + + describe('if first add button is pressed', () => { + beforeEach(() => { + const addButton: DebugElement = fixture.debugElement.query(By.css('#groupsSearch tbody .fa-plus')); + addButton.nativeElement.click(); fixture.detectChanges(); + }); + it('then all (two) Groups are subgroups of the active group. No non-members left', () => { groupsFound = fixture.debugElement.queryAll(By.css('#groupsSearch tbody tr')); - const getSubgroups = groupsDataServiceStub.getSubgroups().subgroups; - if (getSubgroups !== undefined && getSubgroups.length > 0) { - groupsFound.map((foundGroupRowElement: DebugElement) => { - const groupId: DebugElement = foundGroupRowElement.query(By.css('td:first-child')); - const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus')); - const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt')); - expect(addButton).toBeNull(); - if (activeGroup.id === groupId.nativeElement.textContent) { - expect(deleteButton).toBeNull(); - } else { - expect(deleteButton).not.toBeNull(); - } - }); - } else { - const subgroupIds: string[] = activeGroup.subgroups.map((group: Group) => group.id); - groupsFound.map((foundGroupRowElement: DebugElement) => { - const groupId: DebugElement = foundGroupRowElement.query(By.css('td:first-child')); - const addButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-plus')); - const deleteButton: DebugElement = foundGroupRowElement.query(By.css('td:last-child .fa-trash-alt')); - if (subgroupIds.includes(groupId.nativeElement.textContent)) { - expect(addButton).toBeNull(); - expect(deleteButton).not.toBeNull(); - } else { - expect(deleteButton).toBeNull(); - expect(addButton).not.toBeNull(); - } - }); - } + expect(groupsFound.length).toEqual(0); }); }); }); From 8a10888d2ad7916570472173070370da61320a72 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 13 Oct 2023 14:43:28 -0500 Subject: [PATCH 130/196] Refactor members-list and subgroups-list components to use new isNotMemberOf endpoints (via services) --- .../members-list/members-list.component.html | 10 +---- .../members-list.component.spec.ts | 2 +- .../members-list/members-list.component.ts | 30 +++++++------ .../subgroups-list.component.html | 5 +-- .../subgroups-list.component.spec.ts | 2 +- .../subgroup-list/subgroups-list.component.ts | 35 +++++++--------- .../core/eperson/eperson-data.service.spec.ts | 25 +++++++++++ src/app/core/eperson/eperson-data.service.ts | 28 +++++++++++++ .../core/eperson/group-data.service.spec.ts | 28 ++++++++++++- src/app/core/eperson/group-data.service.ts | 42 +++++++++++-------- src/assets/i18n/en.json5 | 10 ----- 11 files changed, 139 insertions(+), 78 deletions(-) diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html index 0f5010e08eb..e185d37e286 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.html +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.html @@ -15,14 +15,8 @@
    -
    - -
    -
    -
    +
    +
    diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts index 76e38067bc8..5d97dcade8d 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.spec.ts @@ -56,7 +56,7 @@ describe('MembersListComponent', () => { return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupsDataServiceStub.getEPersonMembers())); }, // This method is used to search across *non-members* - searchByScope(scope: string, query: string): Observable>> { + searchNonMembers(query: string, group: string): Observable>> { if (query === '') { return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), epersonNonMembers)); } diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts index e828555a80f..4924f3168b5 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts @@ -124,7 +124,6 @@ export class MembersListComponent implements OnInit, OnDestroy { // Current search in edit group - epeople search form currentSearchQuery: string; - currentSearchScope: string; // Whether or not user has done a EPeople search yet searchDone: boolean; @@ -143,12 +142,10 @@ export class MembersListComponent implements OnInit, OnDestroy { public dsoNameService: DSONameService, ) { this.currentSearchQuery = ''; - this.currentSearchScope = 'metadata'; } ngOnInit(): void { this.searchForm = this.formBuilder.group(({ - scope: 'metadata', query: '', })); this.subs.set(SubKey.ActiveGroup, this.groupDataService.getActiveGroup().subscribe((activeGroup: Group) => { @@ -213,6 +210,11 @@ export class MembersListComponent implements OnInit, OnDestroy { if (activeGroup != null) { const response = this.groupDataService.deleteMemberFromGroup(activeGroup, eperson); this.showNotifications('deleteMember', response, this.dsoNameService.getName(eperson), activeGroup); + // Reload search results (if there is an active query). + // This will potentially add this deleted subgroup into the list of search results. + if (this.currentSearchQuery != null) { + this.search({query: this.currentSearchQuery}); + } } else { this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup')); } @@ -228,6 +230,11 @@ export class MembersListComponent implements OnInit, OnDestroy { if (activeGroup != null) { const response = this.groupDataService.addMemberToGroup(activeGroup, eperson); this.showNotifications('addMember', response, this.dsoNameService.getName(eperson), activeGroup); + // Reload search results (if there is an active query). + // This will potentially add this deleted subgroup into the list of search results. + if (this.currentSearchQuery != null) { + this.search({query: this.currentSearchQuery}); + } } else { this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup')); } @@ -235,17 +242,15 @@ export class MembersListComponent implements OnInit, OnDestroy { } /** - * Search in the EPeople by name, email or metadata - * @param data Contains scope and query param + * Search all EPeople who are NOT a member of the current group by name, email or metadata + * @param data Contains query param */ search(data: any) { this.unsubFrom(SubKey.SearchResults); this.subs.set(SubKey.SearchResults, this.paginationService.getCurrentPagination(this.configSearch.id, this.configSearch).pipe( switchMap((paginationOptions) => { - const query: string = data.query; - const scope: string = data.scope; if (query != null && this.currentSearchQuery !== query && this.groupBeingEdited) { this.router.navigate([], { queryParamsHandling: 'merge' @@ -253,19 +258,12 @@ export class MembersListComponent implements OnInit, OnDestroy { this.currentSearchQuery = query; this.paginationService.resetPage(this.configSearch.id); } - if (scope != null && this.currentSearchScope !== scope && this.groupBeingEdited) { - this.router.navigate([], { - queryParamsHandling: 'merge' - }); - this.currentSearchScope = scope; - this.paginationService.resetPage(this.configSearch.id); - } this.searchDone = true; - return this.ePersonDataService.searchByScope(this.currentSearchScope, this.currentSearchQuery, { + return this.ePersonDataService.searchNonMembers(this.currentSearchQuery, this.groupBeingEdited.id, { currentPage: paginationOptions.currentPage, elementsPerPage: paginationOptions.pageSize - }); + }, false, true); }), getAllCompletedRemoteData(), map((rd: RemoteData) => { diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html index 8268eb5eb45..d97272ec6fe 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html @@ -62,10 +62,7 @@
    {{ dsoNameService.getName((group.object | async)?.payload) }}
    - {{ messagePrefix + '.table.edit.currentGroup' | translate }} - -
    -

    {{messagePrefix + '.headMembers' | translate}}

    - - - -
    - - - - - - - - - - - - - - - - - -
    {{messagePrefix + '.table.id' | translate}}{{messagePrefix + '.table.name' | translate}}{{messagePrefix + '.table.identity' | translate}}{{messagePrefix + '.table.edit' | translate}}
    {{eperson.id}} - - {{ dsoNameService.getName(eperson) }} - - - {{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}
    - {{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }} -
    -
    - -
    -
    -
    - -
    - - - diff --git a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts index d2ddd700a9b..feb90b52b37 100644 --- a/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts +++ b/src/app/access-control/group-registry/group-form/members-list/members-list.component.ts @@ -152,6 +152,7 @@ export class MembersListComponent implements OnInit, OnDestroy { if (activeGroup != null) { this.groupBeingEdited = activeGroup; this.retrieveMembers(this.config.currentPage); + this.search({query: ''}); } })); } diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html index d97272ec6fe..85fe8974edd 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.html @@ -1,6 +1,55 @@

    {{messagePrefix + '.head' | translate}}

    +

    {{messagePrefix + '.headSubgroups' | translate}}

    + + + +
    + + + + + + + + + + + + + + + + + +
    {{messagePrefix + '.table.id' | translate}}{{messagePrefix + '.table.name' | translate}}{{messagePrefix + '.table.collectionOrCommunity' | translate}}{{messagePrefix + '.table.edit' | translate}}
    {{group.id}} + + {{ dsoNameService.getName(group) }} + + {{ dsoNameService.getName((group.object | async)?.payload)}} +
    + +
    +
    +
    +
    + + +
    {{process.endTime | date:dateFormat:'UTC'}} {{process.processStatus}} - +
    - + @@ -31,6 +31,7 @@ diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index dbf32bb7074..1522723bdd3 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3610,6 +3610,14 @@ "resource-policies.table.headers.group": "Group", + "resource-policies.table.headers.select-all": "Select all", + + "resource-policies.table.headers.deselect-all": "Deselect all", + + "resource-policies.table.headers.select": "Select", + + "resource-policies.table.headers.deselect": "Deselect", + "resource-policies.table.headers.id": "ID", "resource-policies.table.headers.name": "Name", From 5b21d14583f8b1ca22f889ee4c24fc7e54579fa7 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Sun, 3 Dec 2023 15:15:52 +0100 Subject: [PATCH 173/196] Fix item mapper accessibility issues - Added missing aria-labels to input checkboxes - Fixed role="tablist" not having direct role="tab" by adding role="presentation" on the li elements --- .../collection-item-mapper.component.html | 4 ++-- .../object-select/item-select/item-select.component.html | 4 ++-- src/assets/i18n/en.json5 | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html index a48c4d15bfd..649aa9b43db 100644 --- a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html +++ b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html @@ -6,7 +6,7 @@

    {{'collection.edit.item-mapper.head' | translate}}

    {{'collection.edit.item-mapper.description' | translate}}

    {{'admin.registries.bitstream-formats.table.id' | translate}} {{'admin.registries.bitstream-formats.table.name' | translate}} {{'admin.registries.bitstream-formats.table.mimetype' | translate}} diff --git a/src/app/shared/resource-policies/resource-policies.component.html b/src/app/shared/resource-policies/resource-policies.component.html index 277f6e49988..b3dda9091d9 100644 --- a/src/app/shared/resource-policies/resource-policies.component.html +++ b/src/app/shared/resource-policies/resource-policies.component.html @@ -38,11 +38,13 @@
    - - +
    {{'resource-policies.table.headers.id' | translate}}
    - + @@ -19,7 +19,7 @@ - +
    {{'item.select.table.collection' | translate}} {{'item.select.table.author' | translate}} {{'item.select.table.title' | translate}}
    diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 1522723bdd3..3fa71678b86 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2508,6 +2508,10 @@ "item.select.empty": "No items to show", + "item.select.table.select": "Select item", + + "item.select.table.deselect": "Deselect item", + "item.select.table.author": "Author", "item.select.table.collection": "Collection", From 1db83ba3c5529fdf8dadddf8431b2dac029cfa0e Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Sun, 3 Dec 2023 15:42:13 +0100 Subject: [PATCH 174/196] Fix collection mapper accessibility issues - Added missing aria-labels to input checkboxes - Fixed multiple tab related accessibility issues --- .../item-page/edit-item-page/edit-item-page.component.html | 6 ++++-- .../item-collection-mapper.component.html | 4 ++-- .../collection-select/collection-select.component.html | 4 ++-- src/assets/i18n/en.json5 | 4 ++++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/app/item-page/edit-item-page/edit-item-page.component.html b/src/app/item-page/edit-item-page/edit-item-page.component.html index c370fe4f20d..4aa4c9af161 100644 --- a/src/app/item-page/edit-item-page/edit-item-page.component.html +++ b/src/app/item-page/edit-item-page/edit-item-page.component.html @@ -4,11 +4,13 @@

    {{'item.edit.head' | translate}}